xref: /qemu/tcg/tcg.c (revision becc452a367aa681ca0c1fcb688ae0f16b32b11f)
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"
371de7afc9SPaolo Bonzini #include "qemu/timer.h"
38084cfca1SRichard Henderson #include "qemu/cacheflush.h"
39ad768e6fSPeter Maydell #include "qemu/cacheinfo.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"
635ff7258cSRichard Henderson #include "tcg-internal.h"
645584e2dbSIlya Leoshkevich #include "accel/tcg/perf.h"
65c896fe29Sbellard 
66139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and
67ce151109SPeter Maydell    used here. */
68e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s);
69e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
706ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
712ba7fae2SRichard Henderson                         intptr_t value, intptr_t addend);
72c896fe29Sbellard 
73497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts.  */
74497a22ebSRichard Henderson typedef struct {
75497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
76497a22ebSRichard Henderson     uint32_t id;
77497a22ebSRichard Henderson     uint8_t version;
78497a22ebSRichard Henderson     char augmentation[1];
79497a22ebSRichard Henderson     uint8_t code_align;
80497a22ebSRichard Henderson     uint8_t data_align;
81497a22ebSRichard Henderson     uint8_t return_column;
82497a22ebSRichard Henderson } DebugFrameCIE;
83497a22ebSRichard Henderson 
84497a22ebSRichard Henderson typedef struct QEMU_PACKED {
85497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
86497a22ebSRichard Henderson     uint32_t cie_offset;
87edee2579SRichard Henderson     uintptr_t func_start;
88edee2579SRichard Henderson     uintptr_t func_len;
89497a22ebSRichard Henderson } DebugFrameFDEHeader;
90497a22ebSRichard Henderson 
912c90784aSRichard Henderson typedef struct QEMU_PACKED {
922c90784aSRichard Henderson     DebugFrameCIE cie;
932c90784aSRichard Henderson     DebugFrameFDEHeader fde;
942c90784aSRichard Henderson } DebugFrameHeader;
952c90784aSRichard Henderson 
96755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
972c90784aSRichard Henderson                                  const void *debug_frame,
982c90784aSRichard Henderson                                  size_t debug_frame_size)
99813da627SRichard Henderson     __attribute__((unused));
100813da627SRichard Henderson 
101139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */
1022a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
103a05b5b9bSRichard Henderson                        intptr_t arg2);
10478113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
105c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1062a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
107b55a8d9dSRichard Henderson static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg);
1085e8892dbSMiroslav Rezanina static void tcg_out_op(TCGContext *s, TCGOpcode opc,
1095e8892dbSMiroslav Rezanina                        const TCGArg args[TCG_MAX_OP_ARGS],
1105e8892dbSMiroslav Rezanina                        const int const_args[TCG_MAX_OP_ARGS]);
111d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec
112e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
113e7632cfaSRichard Henderson                             TCGReg dst, TCGReg src);
114d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
115d6ecb4a9SRichard Henderson                              TCGReg dst, TCGReg base, intptr_t offset);
1164e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1174e186175SRichard Henderson                              TCGReg dst, int64_t arg);
1185e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1195e8892dbSMiroslav Rezanina                            unsigned vecl, unsigned vece,
1205e8892dbSMiroslav Rezanina                            const TCGArg args[TCG_MAX_OP_ARGS],
1215e8892dbSMiroslav Rezanina                            const int const_args[TCG_MAX_OP_ARGS]);
122d2fd745fSRichard Henderson #else
123e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
124e7632cfaSRichard Henderson                                    TCGReg dst, TCGReg src)
125e7632cfaSRichard Henderson {
126e7632cfaSRichard Henderson     g_assert_not_reached();
127e7632cfaSRichard Henderson }
128d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
129d6ecb4a9SRichard Henderson                                     TCGReg dst, TCGReg base, intptr_t offset)
130d6ecb4a9SRichard Henderson {
131d6ecb4a9SRichard Henderson     g_assert_not_reached();
132d6ecb4a9SRichard Henderson }
1334e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1344e186175SRichard Henderson                                     TCGReg dst, int64_t arg)
135e7632cfaSRichard Henderson {
136e7632cfaSRichard Henderson     g_assert_not_reached();
137e7632cfaSRichard Henderson }
1385e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1395e8892dbSMiroslav Rezanina                                   unsigned vecl, unsigned vece,
1405e8892dbSMiroslav Rezanina                                   const TCGArg args[TCG_MAX_OP_ARGS],
1415e8892dbSMiroslav Rezanina                                   const int const_args[TCG_MAX_OP_ARGS])
142d2fd745fSRichard Henderson {
143d2fd745fSRichard Henderson     g_assert_not_reached();
144d2fd745fSRichard Henderson }
145d2fd745fSRichard Henderson #endif
1462a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
147a05b5b9bSRichard Henderson                        intptr_t arg2);
14859d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
14959d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
1507b7d8b2dSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target,
151cee44b03SRichard Henderson                          const TCGHelperInfo *info);
152a4fbbd77SRichard Henderson static bool tcg_target_const_match(int64_t val, TCGType type, int ct);
153659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
154aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s);
155659ef5cbSRichard Henderson #endif
156c896fe29Sbellard 
15742eb6dfcSRichard Henderson TCGContext tcg_init_ctx;
15842eb6dfcSRichard Henderson __thread TCGContext *tcg_ctx;
15942eb6dfcSRichard Henderson 
1605ff7258cSRichard Henderson TCGContext **tcg_ctxs;
1610e2d61cfSRichard Henderson unsigned int tcg_cur_ctxs;
1620e2d61cfSRichard Henderson unsigned int tcg_max_ctxs;
1631c2adb95SRichard Henderson TCGv_env cpu_env = 0;
164c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue;
165db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff;
166df2cce29SEmilio G. Cota 
167b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
168b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec;
169b91ccb31SRichard Henderson #endif
170b91ccb31SRichard Henderson 
171d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
172b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
173c896fe29Sbellard 
1741813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
1754196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
176c896fe29Sbellard {
177c896fe29Sbellard     *s->code_ptr++ = v;
178c896fe29Sbellard }
179c896fe29Sbellard 
1804196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
1814196dca6SPeter Maydell                                                       uint8_t v)
1825c53bb81SPeter Maydell {
1831813e175SRichard Henderson     *p = v;
1845c53bb81SPeter Maydell }
1851813e175SRichard Henderson #endif
1865c53bb81SPeter Maydell 
1871813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
1884196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
189c896fe29Sbellard {
1901813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
1911813e175SRichard Henderson         *s->code_ptr++ = v;
1921813e175SRichard Henderson     } else {
1931813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
1944387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
1951813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
1961813e175SRichard Henderson     }
197c896fe29Sbellard }
198c896fe29Sbellard 
1994196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2004196dca6SPeter Maydell                                                        uint16_t v)
2015c53bb81SPeter Maydell {
2021813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2031813e175SRichard Henderson         *p = v;
2041813e175SRichard Henderson     } else {
2055c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2065c53bb81SPeter Maydell     }
2071813e175SRichard Henderson }
2081813e175SRichard Henderson #endif
2095c53bb81SPeter Maydell 
2101813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
2114196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
212c896fe29Sbellard {
2131813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2141813e175SRichard Henderson         *s->code_ptr++ = v;
2151813e175SRichard Henderson     } else {
2161813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2174387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2181813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
2191813e175SRichard Henderson     }
220c896fe29Sbellard }
221c896fe29Sbellard 
2224196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
2234196dca6SPeter Maydell                                                        uint32_t v)
2245c53bb81SPeter Maydell {
2251813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2261813e175SRichard Henderson         *p = v;
2271813e175SRichard Henderson     } else {
2285c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2295c53bb81SPeter Maydell     }
2301813e175SRichard Henderson }
2311813e175SRichard Henderson #endif
2325c53bb81SPeter Maydell 
2331813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
2344196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
235ac26eb69SRichard Henderson {
2361813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2371813e175SRichard Henderson         *s->code_ptr++ = v;
2381813e175SRichard Henderson     } else {
2391813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2404387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2411813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
2421813e175SRichard Henderson     }
243ac26eb69SRichard Henderson }
244ac26eb69SRichard Henderson 
2454196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
2464196dca6SPeter Maydell                                                        uint64_t v)
2475c53bb81SPeter Maydell {
2481813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2491813e175SRichard Henderson         *p = v;
2501813e175SRichard Henderson     } else {
2515c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2525c53bb81SPeter Maydell     }
2531813e175SRichard Henderson }
2541813e175SRichard Henderson #endif
2555c53bb81SPeter Maydell 
256c896fe29Sbellard /* label relocation processing */
257c896fe29Sbellard 
2581813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
259bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
260c896fe29Sbellard {
2617ecd02a0SRichard Henderson     TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation));
262c896fe29Sbellard 
263c896fe29Sbellard     r->type = type;
264c896fe29Sbellard     r->ptr = code_ptr;
265c896fe29Sbellard     r->addend = addend;
2667ecd02a0SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
267c896fe29Sbellard }
268c896fe29Sbellard 
26992ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l)
270c896fe29Sbellard {
271eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
272c896fe29Sbellard     l->has_value = 1;
27392ab8e7dSRichard Henderson     l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr);
274c896fe29Sbellard }
275c896fe29Sbellard 
27642a268c2SRichard Henderson TCGLabel *gen_new_label(void)
277c896fe29Sbellard {
278b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
27951e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
280c896fe29Sbellard 
2817ecd02a0SRichard Henderson     memset(l, 0, sizeof(TCGLabel));
2827ecd02a0SRichard Henderson     l->id = s->nb_labels++;
2837ecd02a0SRichard Henderson     QSIMPLEQ_INIT(&l->relocs);
2847ecd02a0SRichard Henderson 
285bef16ab4SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
28642a268c2SRichard Henderson 
28742a268c2SRichard Henderson     return l;
288c896fe29Sbellard }
289c896fe29Sbellard 
2907ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s)
2917ecd02a0SRichard Henderson {
2927ecd02a0SRichard Henderson     TCGLabel *l;
2937ecd02a0SRichard Henderson 
2947ecd02a0SRichard Henderson     QSIMPLEQ_FOREACH(l, &s->labels, next) {
2957ecd02a0SRichard Henderson         TCGRelocation *r;
2967ecd02a0SRichard Henderson         uintptr_t value = l->u.value;
2977ecd02a0SRichard Henderson 
2987ecd02a0SRichard Henderson         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
2997ecd02a0SRichard Henderson             if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
3007ecd02a0SRichard Henderson                 return false;
3017ecd02a0SRichard Henderson             }
3027ecd02a0SRichard Henderson         }
3037ecd02a0SRichard Henderson     }
3047ecd02a0SRichard Henderson     return true;
3057ecd02a0SRichard Henderson }
3067ecd02a0SRichard Henderson 
3079f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3089f754620SRichard Henderson {
309f14bed3fSRichard Henderson     /*
310f14bed3fSRichard Henderson      * We will check for overflow at the end of the opcode loop in
311f14bed3fSRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
312f14bed3fSRichard Henderson      */
313f14bed3fSRichard Henderson     s->tb_jmp_reset_offset[which] = tcg_current_code_size(s);
3149f754620SRichard Henderson }
3159f754620SRichard Henderson 
316b52a2c03SRichard Henderson static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which)
317b52a2c03SRichard Henderson {
318b52a2c03SRichard Henderson     /*
319b52a2c03SRichard Henderson      * We will check for overflow at the end of the opcode loop in
320b52a2c03SRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
321b52a2c03SRichard Henderson      */
322b52a2c03SRichard Henderson     tcg_debug_assert(TCG_TARGET_HAS_direct_jump);
323b52a2c03SRichard Henderson     s->tb_jmp_insn_offset[which] = tcg_current_code_size(s);
324b52a2c03SRichard Henderson }
325b52a2c03SRichard Henderson 
326*becc452aSRichard Henderson static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which)
327*becc452aSRichard Henderson {
328*becc452aSRichard Henderson     /*
329*becc452aSRichard Henderson      * Return the read-execute version of the pointer, for the benefit
330*becc452aSRichard Henderson      * of any pc-relative addressing mode.
331*becc452aSRichard Henderson      */
332*becc452aSRichard Henderson     return (uintptr_t)tcg_splitwx_to_rx(&s->tb_jmp_target_addr[which]);
333*becc452aSRichard Henderson }
334*becc452aSRichard Henderson 
335db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */
3368905770bSMarc-André Lureau static G_NORETURN
3378905770bSMarc-André Lureau void tcg_raise_tb_overflow(TCGContext *s)
338db6b7d0cSRichard Henderson {
339db6b7d0cSRichard Henderson     siglongjmp(s->jmp_trans, -2);
340db6b7d0cSRichard Henderson }
341db6b7d0cSRichard Henderson 
3424c22e840SRichard Henderson #define C_PFX1(P, A)                    P##A
3434c22e840SRichard Henderson #define C_PFX2(P, A, B)                 P##A##_##B
3444c22e840SRichard Henderson #define C_PFX3(P, A, B, C)              P##A##_##B##_##C
3454c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D)           P##A##_##B##_##C##_##D
3464c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E)        P##A##_##B##_##C##_##D##_##E
3474c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F)     P##A##_##B##_##C##_##D##_##E##_##F
3484c22e840SRichard Henderson 
3494c22e840SRichard Henderson /* Define an enumeration for the various combinations. */
3504c22e840SRichard Henderson 
3514c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1),
3524c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2),
3534c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3),
3544c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4),
3554c22e840SRichard Henderson 
3564c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1),
3574c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2),
3584c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3),
3594c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4),
3604c22e840SRichard Henderson 
3614c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2),
3624c22e840SRichard Henderson 
3634c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1),
3644c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2),
3654c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3),
3664c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4),
3674c22e840SRichard Henderson 
3684c22e840SRichard Henderson typedef enum {
3694c22e840SRichard Henderson #include "tcg-target-con-set.h"
3704c22e840SRichard Henderson } TCGConstraintSetIndex;
3714c22e840SRichard Henderson 
3724c22e840SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode);
3734c22e840SRichard Henderson 
3744c22e840SRichard Henderson #undef C_O0_I1
3754c22e840SRichard Henderson #undef C_O0_I2
3764c22e840SRichard Henderson #undef C_O0_I3
3774c22e840SRichard Henderson #undef C_O0_I4
3784c22e840SRichard Henderson #undef C_O1_I1
3794c22e840SRichard Henderson #undef C_O1_I2
3804c22e840SRichard Henderson #undef C_O1_I3
3814c22e840SRichard Henderson #undef C_O1_I4
3824c22e840SRichard Henderson #undef C_N1_I2
3834c22e840SRichard Henderson #undef C_O2_I1
3844c22e840SRichard Henderson #undef C_O2_I2
3854c22e840SRichard Henderson #undef C_O2_I3
3864c22e840SRichard Henderson #undef C_O2_I4
3874c22e840SRichard Henderson 
3884c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */
3894c22e840SRichard Henderson 
3904c22e840SRichard Henderson #define C_O0_I1(I1)                     { .args_ct_str = { #I1 } },
3914c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 { .args_ct_str = { #I1, #I2 } },
3924c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             { .args_ct_str = { #I1, #I2, #I3 } },
3934c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         { .args_ct_str = { #I1, #I2, #I3, #I4 } },
3944c22e840SRichard Henderson 
3954c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 { .args_ct_str = { #O1, #I1 } },
3964c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             { .args_ct_str = { #O1, #I1, #I2 } },
3974c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         { .args_ct_str = { #O1, #I1, #I2, #I3 } },
3984c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } },
3994c22e840SRichard Henderson 
4004c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             { .args_ct_str = { "&" #O1, #I1, #I2 } },
4014c22e840SRichard Henderson 
4024c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             { .args_ct_str = { #O1, #O2, #I1 } },
4034c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         { .args_ct_str = { #O1, #O2, #I1, #I2 } },
4044c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } },
4054c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } },
4064c22e840SRichard Henderson 
4074c22e840SRichard Henderson static const TCGTargetOpDef constraint_sets[] = {
4084c22e840SRichard Henderson #include "tcg-target-con-set.h"
4094c22e840SRichard Henderson };
4104c22e840SRichard Henderson 
4114c22e840SRichard Henderson 
4124c22e840SRichard Henderson #undef C_O0_I1
4134c22e840SRichard Henderson #undef C_O0_I2
4144c22e840SRichard Henderson #undef C_O0_I3
4154c22e840SRichard Henderson #undef C_O0_I4
4164c22e840SRichard Henderson #undef C_O1_I1
4174c22e840SRichard Henderson #undef C_O1_I2
4184c22e840SRichard Henderson #undef C_O1_I3
4194c22e840SRichard Henderson #undef C_O1_I4
4204c22e840SRichard Henderson #undef C_N1_I2
4214c22e840SRichard Henderson #undef C_O2_I1
4224c22e840SRichard Henderson #undef C_O2_I2
4234c22e840SRichard Henderson #undef C_O2_I3
4244c22e840SRichard Henderson #undef C_O2_I4
4254c22e840SRichard Henderson 
4264c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */
4274c22e840SRichard Henderson 
4284c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1)
4294c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2)
4304c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3)
4314c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4)
4324c22e840SRichard Henderson 
4334c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1)
4344c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2)
4354c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3)
4364c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4)
4374c22e840SRichard Henderson 
4384c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2)
4394c22e840SRichard Henderson 
4404c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1)
4414c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2)
4424c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3)
4434c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4)
4444c22e840SRichard Henderson 
445139c1837SPaolo Bonzini #include "tcg-target.c.inc"
446c896fe29Sbellard 
44738b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s)
44838b47b19SEmilio G. Cota {
44938b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
45038b47b19SEmilio G. Cota     s->plugin_tb = g_new0(struct qemu_plugin_tb, 1);
45138b47b19SEmilio G. Cota     s->plugin_tb->insns =
45238b47b19SEmilio G. Cota         g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn);
45338b47b19SEmilio G. Cota #endif
45438b47b19SEmilio G. Cota }
45538b47b19SEmilio G. Cota 
456e8feb96fSEmilio G. Cota /*
4573468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
4583468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
4593468b59eSEmilio G. Cota  * before initiating translation.
4603468b59eSEmilio G. Cota  *
4613468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
4623468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
4633468b59eSEmilio G. Cota  *
4643468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
4653468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
4663468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
4673468b59eSEmilio G. Cota  *
4683468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
4693468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
4703468b59eSEmilio G. Cota  */
4713468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
4723468b59eSEmilio G. Cota void tcg_register_thread(void)
4733468b59eSEmilio G. Cota {
4743468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
4753468b59eSEmilio G. Cota }
4763468b59eSEmilio G. Cota #else
4773468b59eSEmilio G. Cota void tcg_register_thread(void)
4783468b59eSEmilio G. Cota {
4793468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
4803468b59eSEmilio G. Cota     unsigned int i, n;
4813468b59eSEmilio G. Cota 
4823468b59eSEmilio G. Cota     *s = tcg_init_ctx;
4833468b59eSEmilio G. Cota 
4843468b59eSEmilio G. Cota     /* Relink mem_base.  */
4853468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
4863468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
4873468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
4883468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
4893468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
4903468b59eSEmilio G. Cota         }
4913468b59eSEmilio G. Cota     }
4923468b59eSEmilio G. Cota 
4933468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
4940e2d61cfSRichard Henderson     n = qatomic_fetch_inc(&tcg_cur_ctxs);
4950e2d61cfSRichard Henderson     g_assert(n < tcg_max_ctxs);
496d73415a3SStefan Hajnoczi     qatomic_set(&tcg_ctxs[n], s);
4973468b59eSEmilio G. Cota 
49838b47b19SEmilio G. Cota     if (n > 0) {
49938b47b19SEmilio G. Cota         alloc_tcg_plugin_context(s);
500bf042e8eSRichard Henderson         tcg_region_initial_alloc(s);
50138b47b19SEmilio G. Cota     }
50238b47b19SEmilio G. Cota 
5033468b59eSEmilio G. Cota     tcg_ctx = s;
5043468b59eSEmilio G. Cota }
5053468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
5063468b59eSEmilio G. Cota 
507c896fe29Sbellard /* pool based memory allocation */
508c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
509c896fe29Sbellard {
510c896fe29Sbellard     TCGPool *p;
511c896fe29Sbellard     int pool_size;
512c896fe29Sbellard 
513c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
514c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
5157267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
516c896fe29Sbellard         p->size = size;
5174055299eSKirill Batuzov         p->next = s->pool_first_large;
5184055299eSKirill Batuzov         s->pool_first_large = p;
5194055299eSKirill Batuzov         return p->data;
520c896fe29Sbellard     } else {
521c896fe29Sbellard         p = s->pool_current;
522c896fe29Sbellard         if (!p) {
523c896fe29Sbellard             p = s->pool_first;
524c896fe29Sbellard             if (!p)
525c896fe29Sbellard                 goto new_pool;
526c896fe29Sbellard         } else {
527c896fe29Sbellard             if (!p->next) {
528c896fe29Sbellard             new_pool:
529c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
5307267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
531c896fe29Sbellard                 p->size = pool_size;
532c896fe29Sbellard                 p->next = NULL;
533a813e36fSRichard Henderson                 if (s->pool_current) {
534c896fe29Sbellard                     s->pool_current->next = p;
535a813e36fSRichard Henderson                 } else {
536c896fe29Sbellard                     s->pool_first = p;
537a813e36fSRichard Henderson                 }
538c896fe29Sbellard             } else {
539c896fe29Sbellard                 p = p->next;
540c896fe29Sbellard             }
541c896fe29Sbellard         }
542c896fe29Sbellard     }
543c896fe29Sbellard     s->pool_current = p;
544c896fe29Sbellard     s->pool_cur = p->data + size;
545c896fe29Sbellard     s->pool_end = p->data + p->size;
546c896fe29Sbellard     return p->data;
547c896fe29Sbellard }
548c896fe29Sbellard 
549c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
550c896fe29Sbellard {
5514055299eSKirill Batuzov     TCGPool *p, *t;
5524055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
5534055299eSKirill Batuzov         t = p->next;
5544055299eSKirill Batuzov         g_free(p);
5554055299eSKirill Batuzov     }
5564055299eSKirill Batuzov     s->pool_first_large = NULL;
557c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
558c896fe29Sbellard     s->pool_current = NULL;
559c896fe29Sbellard }
560c896fe29Sbellard 
5612ef6175aSRichard Henderson #include "exec/helper-proto.h"
5622ef6175aSRichard Henderson 
56339004a71SRichard Henderson static TCGHelperInfo all_helpers[] = {
5642ef6175aSRichard Henderson #include "exec/helper-tcg.h"
565100b5e01SRichard Henderson };
566619205fdSEmilio G. Cota static GHashTable *helper_table;
567100b5e01SRichard Henderson 
56822f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
569c6ef8c7bSPhilippe Mathieu-Daudé static ffi_type *typecode_to_ffi(int argmask)
570c6ef8c7bSPhilippe Mathieu-Daudé {
571c6ef8c7bSPhilippe Mathieu-Daudé     switch (argmask) {
572c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_void:
573c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_void;
574c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_i32:
575c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_uint32;
576c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_s32:
577c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_sint32;
578c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_i64:
579c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_uint64;
580c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_s64:
581c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_sint64;
582c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_ptr:
583c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_pointer;
584c6ef8c7bSPhilippe Mathieu-Daudé     }
585c6ef8c7bSPhilippe Mathieu-Daudé     g_assert_not_reached();
586c6ef8c7bSPhilippe Mathieu-Daudé }
5870c22e176SPhilippe Mathieu-Daudé 
5880c22e176SPhilippe Mathieu-Daudé static void init_ffi_layouts(void)
5890c22e176SPhilippe Mathieu-Daudé {
5900c22e176SPhilippe Mathieu-Daudé     /* g_direct_hash/equal for direct comparisons on uint32_t.  */
591f9c4bb80SRichard Henderson     GHashTable *ffi_table = g_hash_table_new(NULL, NULL);
592f9c4bb80SRichard Henderson 
5930c22e176SPhilippe Mathieu-Daudé     for (int i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
594f9c4bb80SRichard Henderson         TCGHelperInfo *info = &all_helpers[i];
595f9c4bb80SRichard Henderson         unsigned typemask = info->typemask;
5960c22e176SPhilippe Mathieu-Daudé         gpointer hash = (gpointer)(uintptr_t)typemask;
5970c22e176SPhilippe Mathieu-Daudé         struct {
5980c22e176SPhilippe Mathieu-Daudé             ffi_cif cif;
5990c22e176SPhilippe Mathieu-Daudé             ffi_type *args[];
6000c22e176SPhilippe Mathieu-Daudé         } *ca;
6010c22e176SPhilippe Mathieu-Daudé         ffi_status status;
6020c22e176SPhilippe Mathieu-Daudé         int nargs;
603f9c4bb80SRichard Henderson         ffi_cif *cif;
6040c22e176SPhilippe Mathieu-Daudé 
605f9c4bb80SRichard Henderson         cif = g_hash_table_lookup(ffi_table, hash);
606f9c4bb80SRichard Henderson         if (cif) {
607f9c4bb80SRichard Henderson             info->cif = cif;
6080c22e176SPhilippe Mathieu-Daudé             continue;
6090c22e176SPhilippe Mathieu-Daudé         }
6100c22e176SPhilippe Mathieu-Daudé 
6110c22e176SPhilippe Mathieu-Daudé         /* Ignoring the return type, find the last non-zero field. */
6120c22e176SPhilippe Mathieu-Daudé         nargs = 32 - clz32(typemask >> 3);
6130c22e176SPhilippe Mathieu-Daudé         nargs = DIV_ROUND_UP(nargs, 3);
6140c22e176SPhilippe Mathieu-Daudé 
6150c22e176SPhilippe Mathieu-Daudé         ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *));
6160c22e176SPhilippe Mathieu-Daudé         ca->cif.rtype = typecode_to_ffi(typemask & 7);
6170c22e176SPhilippe Mathieu-Daudé         ca->cif.nargs = nargs;
6180c22e176SPhilippe Mathieu-Daudé 
6190c22e176SPhilippe Mathieu-Daudé         if (nargs != 0) {
6200c22e176SPhilippe Mathieu-Daudé             ca->cif.arg_types = ca->args;
6210c22e176SPhilippe Mathieu-Daudé             for (int j = 0; j < nargs; ++j) {
6220c22e176SPhilippe Mathieu-Daudé                 int typecode = extract32(typemask, (j + 1) * 3, 3);
6230c22e176SPhilippe Mathieu-Daudé                 ca->args[j] = typecode_to_ffi(typecode);
6240c22e176SPhilippe Mathieu-Daudé             }
6250c22e176SPhilippe Mathieu-Daudé         }
6260c22e176SPhilippe Mathieu-Daudé 
6270c22e176SPhilippe Mathieu-Daudé         status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs,
6280c22e176SPhilippe Mathieu-Daudé                               ca->cif.rtype, ca->cif.arg_types);
6290c22e176SPhilippe Mathieu-Daudé         assert(status == FFI_OK);
6300c22e176SPhilippe Mathieu-Daudé 
631f9c4bb80SRichard Henderson         cif = &ca->cif;
632f9c4bb80SRichard Henderson         info->cif = cif;
633f9c4bb80SRichard Henderson         g_hash_table_insert(ffi_table, hash, (gpointer)cif);
6340c22e176SPhilippe Mathieu-Daudé     }
635f9c4bb80SRichard Henderson 
636f9c4bb80SRichard Henderson     g_hash_table_destroy(ffi_table);
6370c22e176SPhilippe Mathieu-Daudé }
6380c22e176SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG_INTERPRETER */
63922f15579SRichard Henderson 
64039004a71SRichard Henderson typedef struct TCGCumulativeArgs {
64139004a71SRichard Henderson     int arg_idx;                /* tcg_gen_callN args[] */
64239004a71SRichard Henderson     int info_in_idx;            /* TCGHelperInfo in[] */
64339004a71SRichard Henderson     int arg_slot;               /* regs+stack slot */
64439004a71SRichard Henderson     int ref_slot;               /* stack slots for references */
64539004a71SRichard Henderson } TCGCumulativeArgs;
64639004a71SRichard Henderson 
64739004a71SRichard Henderson static void layout_arg_even(TCGCumulativeArgs *cum)
64839004a71SRichard Henderson {
64939004a71SRichard Henderson     cum->arg_slot += cum->arg_slot & 1;
65039004a71SRichard Henderson }
65139004a71SRichard Henderson 
65239004a71SRichard Henderson static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info,
65339004a71SRichard Henderson                          TCGCallArgumentKind kind)
65439004a71SRichard Henderson {
65539004a71SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
65639004a71SRichard Henderson 
65739004a71SRichard Henderson     *loc = (TCGCallArgumentLoc){
65839004a71SRichard Henderson         .kind = kind,
65939004a71SRichard Henderson         .arg_idx = cum->arg_idx,
66039004a71SRichard Henderson         .arg_slot = cum->arg_slot,
66139004a71SRichard Henderson     };
66239004a71SRichard Henderson     cum->info_in_idx++;
66339004a71SRichard Henderson     cum->arg_slot++;
66439004a71SRichard Henderson }
66539004a71SRichard Henderson 
66639004a71SRichard Henderson static void layout_arg_normal_n(TCGCumulativeArgs *cum,
66739004a71SRichard Henderson                                 TCGHelperInfo *info, int n)
66839004a71SRichard Henderson {
66939004a71SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
67039004a71SRichard Henderson 
67139004a71SRichard Henderson     for (int i = 0; i < n; ++i) {
67239004a71SRichard Henderson         /* Layout all using the same arg_idx, adjusting the subindex. */
67339004a71SRichard Henderson         loc[i] = (TCGCallArgumentLoc){
67439004a71SRichard Henderson             .kind = TCG_CALL_ARG_NORMAL,
67539004a71SRichard Henderson             .arg_idx = cum->arg_idx,
67639004a71SRichard Henderson             .tmp_subindex = i,
67739004a71SRichard Henderson             .arg_slot = cum->arg_slot + i,
67839004a71SRichard Henderson         };
67939004a71SRichard Henderson     }
68039004a71SRichard Henderson     cum->info_in_idx += n;
68139004a71SRichard Henderson     cum->arg_slot += n;
68239004a71SRichard Henderson }
68339004a71SRichard Henderson 
68439004a71SRichard Henderson static void init_call_layout(TCGHelperInfo *info)
68539004a71SRichard Henderson {
68639004a71SRichard Henderson     int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs);
68739004a71SRichard Henderson     int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long);
68839004a71SRichard Henderson     unsigned typemask = info->typemask;
68939004a71SRichard Henderson     unsigned typecode;
69039004a71SRichard Henderson     TCGCumulativeArgs cum = { };
69139004a71SRichard Henderson 
69239004a71SRichard Henderson     /*
69339004a71SRichard Henderson      * Parse and place any function return value.
69439004a71SRichard Henderson      */
69539004a71SRichard Henderson     typecode = typemask & 7;
69639004a71SRichard Henderson     switch (typecode) {
69739004a71SRichard Henderson     case dh_typecode_void:
69839004a71SRichard Henderson         info->nr_out = 0;
69939004a71SRichard Henderson         break;
70039004a71SRichard Henderson     case dh_typecode_i32:
70139004a71SRichard Henderson     case dh_typecode_s32:
70239004a71SRichard Henderson     case dh_typecode_ptr:
70339004a71SRichard Henderson         info->nr_out = 1;
70439004a71SRichard Henderson         info->out_kind = TCG_CALL_RET_NORMAL;
70539004a71SRichard Henderson         break;
70639004a71SRichard Henderson     case dh_typecode_i64:
70739004a71SRichard Henderson     case dh_typecode_s64:
70839004a71SRichard Henderson         info->nr_out = 64 / TCG_TARGET_REG_BITS;
70939004a71SRichard Henderson         info->out_kind = TCG_CALL_RET_NORMAL;
71039004a71SRichard Henderson         break;
71139004a71SRichard Henderson     default:
71239004a71SRichard Henderson         g_assert_not_reached();
71339004a71SRichard Henderson     }
71439004a71SRichard Henderson     assert(info->nr_out <= ARRAY_SIZE(tcg_target_call_oarg_regs));
71539004a71SRichard Henderson 
71639004a71SRichard Henderson     /*
71739004a71SRichard Henderson      * Parse and place function arguments.
71839004a71SRichard Henderson      */
71939004a71SRichard Henderson     for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) {
72039004a71SRichard Henderson         TCGCallArgumentKind kind;
72139004a71SRichard Henderson         TCGType type;
72239004a71SRichard Henderson 
72339004a71SRichard Henderson         typecode = typemask & 7;
72439004a71SRichard Henderson         switch (typecode) {
72539004a71SRichard Henderson         case dh_typecode_i32:
72639004a71SRichard Henderson         case dh_typecode_s32:
72739004a71SRichard Henderson             type = TCG_TYPE_I32;
72839004a71SRichard Henderson             break;
72939004a71SRichard Henderson         case dh_typecode_i64:
73039004a71SRichard Henderson         case dh_typecode_s64:
73139004a71SRichard Henderson             type = TCG_TYPE_I64;
73239004a71SRichard Henderson             break;
73339004a71SRichard Henderson         case dh_typecode_ptr:
73439004a71SRichard Henderson             type = TCG_TYPE_PTR;
73539004a71SRichard Henderson             break;
73639004a71SRichard Henderson         default:
73739004a71SRichard Henderson             g_assert_not_reached();
73839004a71SRichard Henderson         }
73939004a71SRichard Henderson 
74039004a71SRichard Henderson         switch (type) {
74139004a71SRichard Henderson         case TCG_TYPE_I32:
74239004a71SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I32) {
74339004a71SRichard Henderson             case TCG_CALL_ARG_EVEN:
74439004a71SRichard Henderson                 layout_arg_even(&cum);
74539004a71SRichard Henderson                 /* fall through */
74639004a71SRichard Henderson             case TCG_CALL_ARG_NORMAL:
74739004a71SRichard Henderson                 layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
74839004a71SRichard Henderson                 break;
74939004a71SRichard Henderson             case TCG_CALL_ARG_EXTEND:
75039004a71SRichard Henderson                 kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1);
75139004a71SRichard Henderson                 layout_arg_1(&cum, info, kind);
75239004a71SRichard Henderson                 break;
75339004a71SRichard Henderson             default:
75439004a71SRichard Henderson                 qemu_build_not_reached();
75539004a71SRichard Henderson             }
75639004a71SRichard Henderson             break;
75739004a71SRichard Henderson 
75839004a71SRichard Henderson         case TCG_TYPE_I64:
75939004a71SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I64) {
76039004a71SRichard Henderson             case TCG_CALL_ARG_EVEN:
76139004a71SRichard Henderson                 layout_arg_even(&cum);
76239004a71SRichard Henderson                 /* fall through */
76339004a71SRichard Henderson             case TCG_CALL_ARG_NORMAL:
76439004a71SRichard Henderson                 if (TCG_TARGET_REG_BITS == 32) {
76539004a71SRichard Henderson                     layout_arg_normal_n(&cum, info, 2);
76639004a71SRichard Henderson                 } else {
76739004a71SRichard Henderson                     layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
76839004a71SRichard Henderson                 }
76939004a71SRichard Henderson                 break;
77039004a71SRichard Henderson             default:
77139004a71SRichard Henderson                 qemu_build_not_reached();
77239004a71SRichard Henderson             }
77339004a71SRichard Henderson             break;
77439004a71SRichard Henderson 
77539004a71SRichard Henderson         default:
77639004a71SRichard Henderson             g_assert_not_reached();
77739004a71SRichard Henderson         }
77839004a71SRichard Henderson     }
77939004a71SRichard Henderson     info->nr_in = cum.info_in_idx;
78039004a71SRichard Henderson 
78139004a71SRichard Henderson     /* Validate that we didn't overrun the input array. */
78239004a71SRichard Henderson     assert(cum.info_in_idx <= ARRAY_SIZE(info->in));
78339004a71SRichard Henderson     /* Validate the backend has enough argument space. */
78439004a71SRichard Henderson     assert(cum.arg_slot <= max_reg_slots + max_stk_slots);
78539004a71SRichard Henderson     assert(cum.ref_slot <= max_stk_slots);
78639004a71SRichard Henderson }
78739004a71SRichard Henderson 
78891478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
789f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
7901c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
7911c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
79291478cefSRichard Henderson 
79343b972b7SRichard Henderson static void tcg_context_init(unsigned max_cpus)
794c896fe29Sbellard {
795a76aabd3SRichard Henderson     TCGContext *s = &tcg_init_ctx;
796100b5e01SRichard Henderson     int op, total_args, n, i;
797c896fe29Sbellard     TCGOpDef *def;
798c896fe29Sbellard     TCGArgConstraint *args_ct;
7991c2adb95SRichard Henderson     TCGTemp *ts;
800c896fe29Sbellard 
801c896fe29Sbellard     memset(s, 0, sizeof(*s));
802c896fe29Sbellard     s->nb_globals = 0;
803c896fe29Sbellard 
804c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
805c896fe29Sbellard        space */
806c896fe29Sbellard     total_args = 0;
807c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
808c896fe29Sbellard         def = &tcg_op_defs[op];
809c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
810c896fe29Sbellard         total_args += n;
811c896fe29Sbellard     }
812c896fe29Sbellard 
813bc2b17e6SRichard Henderson     args_ct = g_new0(TCGArgConstraint, total_args);
814c896fe29Sbellard 
815c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
816c896fe29Sbellard         def = &tcg_op_defs[op];
817c896fe29Sbellard         def->args_ct = args_ct;
818c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
819c896fe29Sbellard         args_ct += n;
820c896fe29Sbellard     }
821c896fe29Sbellard 
8225cd8f621SRichard Henderson     /* Register helpers.  */
82384fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
824619205fdSEmilio G. Cota     helper_table = g_hash_table_new(NULL, NULL);
82584fd9dd3SRichard Henderson 
826100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
82739004a71SRichard Henderson         init_call_layout(&all_helpers[i]);
82884fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
82972866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
830100b5e01SRichard Henderson     }
8315cd8f621SRichard Henderson 
83222f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
8330c22e176SPhilippe Mathieu-Daudé     init_ffi_layouts();
83422f15579SRichard Henderson #endif
83522f15579SRichard Henderson 
836c896fe29Sbellard     tcg_target_init(s);
837f69d277eSRichard Henderson     process_op_defs(s);
83891478cefSRichard Henderson 
83991478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
84091478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
84191478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
84291478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
84391478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
84491478cefSRichard Henderson             break;
84591478cefSRichard Henderson         }
84691478cefSRichard Henderson     }
84791478cefSRichard Henderson     for (i = 0; i < n; ++i) {
84891478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
84991478cefSRichard Henderson     }
85091478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
85191478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
85291478cefSRichard Henderson     }
853b1311c4aSEmilio G. Cota 
85438b47b19SEmilio G. Cota     alloc_tcg_plugin_context(s);
85538b47b19SEmilio G. Cota 
856b1311c4aSEmilio G. Cota     tcg_ctx = s;
8573468b59eSEmilio G. Cota     /*
8583468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
8593468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
8603468b59eSEmilio G. Cota      * reasoning behind this.
8613468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
8623468b59eSEmilio G. Cota      */
8633468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
864df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
8650e2d61cfSRichard Henderson     tcg_cur_ctxs = 1;
8660e2d61cfSRichard Henderson     tcg_max_ctxs = 1;
8673468b59eSEmilio G. Cota #else
8680e2d61cfSRichard Henderson     tcg_max_ctxs = max_cpus;
8690e2d61cfSRichard Henderson     tcg_ctxs = g_new0(TCGContext *, max_cpus);
8703468b59eSEmilio G. Cota #endif
8711c2adb95SRichard Henderson 
8721c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
8731c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
8741c2adb95SRichard Henderson     cpu_env = temp_tcgv_ptr(ts);
8759002ec79SRichard Henderson }
876b03cce8eSbellard 
87743b972b7SRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus)
878a76aabd3SRichard Henderson {
87943b972b7SRichard Henderson     tcg_context_init(max_cpus);
88043b972b7SRichard Henderson     tcg_region_init(tb_size, splitwx, max_cpus);
881a76aabd3SRichard Henderson }
882a76aabd3SRichard Henderson 
8836e3b2bfdSEmilio G. Cota /*
8846e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
8856e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
8866e3b2bfdSEmilio G. Cota  */
8876e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
8886e3b2bfdSEmilio G. Cota {
8896e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
8906e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
8916e3b2bfdSEmilio G. Cota     void *next;
8926e3b2bfdSEmilio G. Cota 
893e8feb96fSEmilio G. Cota  retry:
8946e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
8956e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
8966e3b2bfdSEmilio G. Cota 
8976e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
898e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
8996e3b2bfdSEmilio G. Cota             return NULL;
9006e3b2bfdSEmilio G. Cota         }
901e8feb96fSEmilio G. Cota         goto retry;
902e8feb96fSEmilio G. Cota     }
903d73415a3SStefan Hajnoczi     qatomic_set(&s->code_gen_ptr, next);
90457a26946SRichard Henderson     s->data_gen_ptr = NULL;
9056e3b2bfdSEmilio G. Cota     return tb;
9066e3b2bfdSEmilio G. Cota }
9076e3b2bfdSEmilio G. Cota 
9089002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
9099002ec79SRichard Henderson {
910b0a0794aSRichard Henderson     size_t prologue_size;
9118163b749SRichard Henderson 
912b0a0794aSRichard Henderson     s->code_ptr = s->code_gen_ptr;
913b0a0794aSRichard Henderson     s->code_buf = s->code_gen_ptr;
9145b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
915b91ccb31SRichard Henderson 
916b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
917b0a0794aSRichard Henderson     tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr);
918b91ccb31SRichard Henderson #endif
9198163b749SRichard Henderson 
9205b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
9215b38ee31SRichard Henderson     s->pool_labels = NULL;
9225b38ee31SRichard Henderson #endif
9235b38ee31SRichard Henderson 
924653b87ebSRoman Bolshakov     qemu_thread_jit_write();
9258163b749SRichard Henderson     /* Generate the prologue.  */
926b03cce8eSbellard     tcg_target_qemu_prologue(s);
9275b38ee31SRichard Henderson 
9285b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
9295b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
9305b38ee31SRichard Henderson     {
9311768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
9321768987bSRichard Henderson         tcg_debug_assert(result == 0);
9335b38ee31SRichard Henderson     }
9345b38ee31SRichard Henderson #endif
9355b38ee31SRichard Henderson 
936b0a0794aSRichard Henderson     prologue_size = tcg_current_code_size(s);
9375584e2dbSIlya Leoshkevich     perf_report_prologue(s->code_gen_ptr, prologue_size);
938b0a0794aSRichard Henderson 
939df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
940b0a0794aSRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
941b0a0794aSRichard Henderson                         (uintptr_t)s->code_buf, prologue_size);
942df5d2b16SRichard Henderson #endif
9438163b749SRichard Henderson 
944d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
945d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
946c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
94778b54858SRichard Henderson         if (logfile) {
94878b54858SRichard Henderson             fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size);
9495b38ee31SRichard Henderson             if (s->data_gen_ptr) {
950b0a0794aSRichard Henderson                 size_t code_size = s->data_gen_ptr - s->code_gen_ptr;
9515b38ee31SRichard Henderson                 size_t data_size = prologue_size - code_size;
9525b38ee31SRichard Henderson                 size_t i;
9535b38ee31SRichard Henderson 
95478b54858SRichard Henderson                 disas(logfile, s->code_gen_ptr, code_size);
9555b38ee31SRichard Henderson 
9565b38ee31SRichard Henderson                 for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
9575b38ee31SRichard Henderson                     if (sizeof(tcg_target_ulong) == 8) {
95878b54858SRichard Henderson                         fprintf(logfile,
95978b54858SRichard Henderson                                 "0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
9605b38ee31SRichard Henderson                                 (uintptr_t)s->data_gen_ptr + i,
9615b38ee31SRichard Henderson                                 *(uint64_t *)(s->data_gen_ptr + i));
9625b38ee31SRichard Henderson                     } else {
96378b54858SRichard Henderson                         fprintf(logfile,
96478b54858SRichard Henderson                                 "0x%08" PRIxPTR ":  .long  0x%08x\n",
9655b38ee31SRichard Henderson                                 (uintptr_t)s->data_gen_ptr + i,
9665b38ee31SRichard Henderson                                 *(uint32_t *)(s->data_gen_ptr + i));
9675b38ee31SRichard Henderson                     }
9685b38ee31SRichard Henderson                 }
9695b38ee31SRichard Henderson             } else {
97078b54858SRichard Henderson                 disas(logfile, s->code_gen_ptr, prologue_size);
9715b38ee31SRichard Henderson             }
97278b54858SRichard Henderson             fprintf(logfile, "\n");
973fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
974d6b64b2bSRichard Henderson         }
97578b54858SRichard Henderson     }
976d6b64b2bSRichard Henderson #endif
977cedbcb01SEmilio G. Cota 
9786eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
9796eea0434SRichard Henderson     /*
9806eea0434SRichard Henderson      * Assert that goto_ptr is implemented completely, setting an epilogue.
9816eea0434SRichard Henderson      * For tci, we use NULL as the signal to return from the interpreter,
9826eea0434SRichard Henderson      * so skip this check.
9836eea0434SRichard Henderson      */
9848b5c2b62SRichard Henderson     tcg_debug_assert(tcg_code_gen_epilogue != NULL);
9856eea0434SRichard Henderson #endif
986d1c74ab3SRichard Henderson 
987d1c74ab3SRichard Henderson     tcg_region_prologue_set(s);
988c896fe29Sbellard }
989c896fe29Sbellard 
990c896fe29Sbellard void tcg_func_start(TCGContext *s)
991c896fe29Sbellard {
992c896fe29Sbellard     tcg_pool_reset(s);
993c896fe29Sbellard     s->nb_temps = s->nb_globals;
9940ec9eabcSRichard Henderson 
9950ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
9960ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
9970ec9eabcSRichard Henderson 
998c0522136SRichard Henderson     /* No constant temps have been previously allocated. */
999c0522136SRichard Henderson     for (int i = 0; i < TCG_TYPE_COUNT; ++i) {
1000c0522136SRichard Henderson         if (s->const_table[i]) {
1001c0522136SRichard Henderson             g_hash_table_remove_all(s->const_table[i]);
1002c0522136SRichard Henderson         }
1003c0522136SRichard Henderson     }
1004c0522136SRichard Henderson 
1005abebf925SRichard Henderson     s->nb_ops = 0;
1006c896fe29Sbellard     s->nb_labels = 0;
1007c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1008c896fe29Sbellard 
10090a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
10100a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
10110a209d4bSRichard Henderson #endif
10120a209d4bSRichard Henderson 
101315fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
101415fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
1015bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
1016c896fe29Sbellard }
1017c896fe29Sbellard 
1018ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s)
10197ca4b752SRichard Henderson {
10207ca4b752SRichard Henderson     int n = s->nb_temps++;
1021ae30e866SRichard Henderson 
1022ae30e866SRichard Henderson     if (n >= TCG_MAX_TEMPS) {
1023db6b7d0cSRichard Henderson         tcg_raise_tb_overflow(s);
1024ae30e866SRichard Henderson     }
10257ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
10267ca4b752SRichard Henderson }
10277ca4b752SRichard Henderson 
1028ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s)
10297ca4b752SRichard Henderson {
1030fa477d25SRichard Henderson     TCGTemp *ts;
1031fa477d25SRichard Henderson 
10327ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
1033ae30e866SRichard Henderson     tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS);
10347ca4b752SRichard Henderson     s->nb_globals++;
1035fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1036ee17db83SRichard Henderson     ts->kind = TEMP_GLOBAL;
1037fa477d25SRichard Henderson 
1038fa477d25SRichard Henderson     return ts;
1039c896fe29Sbellard }
1040c896fe29Sbellard 
1041085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1042b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1043c896fe29Sbellard {
1044c896fe29Sbellard     TCGTemp *ts;
1045c896fe29Sbellard 
1046b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
1047c896fe29Sbellard         tcg_abort();
1048b3a62939SRichard Henderson     }
10497ca4b752SRichard Henderson 
10507ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1051c896fe29Sbellard     ts->base_type = type;
1052c896fe29Sbellard     ts->type = type;
1053ee17db83SRichard Henderson     ts->kind = TEMP_FIXED;
1054c896fe29Sbellard     ts->reg = reg;
1055c896fe29Sbellard     ts->name = name;
1056c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
10577ca4b752SRichard Henderson 
1058085272b3SRichard Henderson     return ts;
1059a7812ae4Spbrook }
1060a7812ae4Spbrook 
1061b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1062a7812ae4Spbrook {
1063b3a62939SRichard Henderson     s->frame_start = start;
1064b3a62939SRichard Henderson     s->frame_end = start + size;
1065085272b3SRichard Henderson     s->frame_temp
1066085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1067b3a62939SRichard Henderson }
1068a7812ae4Spbrook 
1069085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
1070e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
1071c896fe29Sbellard {
1072b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1073dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
10747ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1075aef85402SRichard Henderson     int indirect_reg = 0;
1076c896fe29Sbellard 
1077c0522136SRichard Henderson     switch (base_ts->kind) {
1078c0522136SRichard Henderson     case TEMP_FIXED:
1079c0522136SRichard Henderson         break;
1080c0522136SRichard Henderson     case TEMP_GLOBAL:
10815a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
10825a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1083b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
10845a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
10855a18407fSRichard Henderson                             ? 2 : 1);
10865a18407fSRichard Henderson         indirect_reg = 1;
1087c0522136SRichard Henderson         break;
1088c0522136SRichard Henderson     default:
1089c0522136SRichard Henderson         g_assert_not_reached();
1090b3915dbbSRichard Henderson     }
1091b3915dbbSRichard Henderson 
10927ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
10937ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1094c896fe29Sbellard         char buf[64];
10957ca4b752SRichard Henderson 
10967ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1097c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1098b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1099c896fe29Sbellard         ts->mem_allocated = 1;
1100b3a62939SRichard Henderson         ts->mem_base = base_ts;
1101aef85402SRichard Henderson         ts->mem_offset = offset;
1102c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1103c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1104c896fe29Sbellard         ts->name = strdup(buf);
1105c896fe29Sbellard 
11067ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
11077ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
11087ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1109b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
11107ca4b752SRichard Henderson         ts2->mem_allocated = 1;
11117ca4b752SRichard Henderson         ts2->mem_base = base_ts;
1112aef85402SRichard Henderson         ts2->mem_offset = offset + 4;
1113fac87bd2SRichard Henderson         ts2->temp_subindex = 1;
1114c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1115c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1116120c1084SRichard Henderson         ts2->name = strdup(buf);
11177ca4b752SRichard Henderson     } else {
1118c896fe29Sbellard         ts->base_type = type;
1119c896fe29Sbellard         ts->type = type;
1120b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1121c896fe29Sbellard         ts->mem_allocated = 1;
1122b3a62939SRichard Henderson         ts->mem_base = base_ts;
1123c896fe29Sbellard         ts->mem_offset = offset;
1124c896fe29Sbellard         ts->name = name;
1125c896fe29Sbellard     }
1126085272b3SRichard Henderson     return ts;
1127c896fe29Sbellard }
1128c896fe29Sbellard 
11295bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local)
1130c896fe29Sbellard {
1131b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1132ee17db83SRichard Henderson     TCGTempKind kind = temp_local ? TEMP_LOCAL : TEMP_NORMAL;
1133c896fe29Sbellard     TCGTemp *ts;
1134641d5fbeSbellard     int idx, k;
1135c896fe29Sbellard 
11360ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
11370ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
11380ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
11390ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
11400ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
11410ec9eabcSRichard Henderson 
1142e8996ee0Sbellard         ts = &s->temps[idx];
1143e8996ee0Sbellard         ts->temp_allocated = 1;
11447ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
1145ee17db83SRichard Henderson         tcg_debug_assert(ts->kind == kind);
1146e8996ee0Sbellard     } else {
11477ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
11487ca4b752SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
11497ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
11507ca4b752SRichard Henderson 
1151c896fe29Sbellard             ts->base_type = type;
1152c896fe29Sbellard             ts->type = TCG_TYPE_I32;
1153e8996ee0Sbellard             ts->temp_allocated = 1;
1154ee17db83SRichard Henderson             ts->kind = kind;
11557ca4b752SRichard Henderson 
11567ca4b752SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
11577ca4b752SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
11587ca4b752SRichard Henderson             ts2->type = TCG_TYPE_I32;
11597ca4b752SRichard Henderson             ts2->temp_allocated = 1;
1160fac87bd2SRichard Henderson             ts2->temp_subindex = 1;
1161ee17db83SRichard Henderson             ts2->kind = kind;
11627ca4b752SRichard Henderson         } else {
1163c896fe29Sbellard             ts->base_type = type;
1164c896fe29Sbellard             ts->type = type;
1165e8996ee0Sbellard             ts->temp_allocated = 1;
1166ee17db83SRichard Henderson             ts->kind = kind;
1167c896fe29Sbellard         }
1168e8996ee0Sbellard     }
116927bfd83cSPeter Maydell 
117027bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
117127bfd83cSPeter Maydell     s->temps_in_use++;
117227bfd83cSPeter Maydell #endif
1173085272b3SRichard Henderson     return ts;
1174c896fe29Sbellard }
1175c896fe29Sbellard 
1176d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1177d2fd745fSRichard Henderson {
1178d2fd745fSRichard Henderson     TCGTemp *t;
1179d2fd745fSRichard Henderson 
1180d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1181d2fd745fSRichard Henderson     switch (type) {
1182d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1183d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1184d2fd745fSRichard Henderson         break;
1185d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1186d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1187d2fd745fSRichard Henderson         break;
1188d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1189d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1190d2fd745fSRichard Henderson         break;
1191d2fd745fSRichard Henderson     default:
1192d2fd745fSRichard Henderson         g_assert_not_reached();
1193d2fd745fSRichard Henderson     }
1194d2fd745fSRichard Henderson #endif
1195d2fd745fSRichard Henderson 
1196d2fd745fSRichard Henderson     t = tcg_temp_new_internal(type, 0);
1197d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1198d2fd745fSRichard Henderson }
1199d2fd745fSRichard Henderson 
1200d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1201d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1202d2fd745fSRichard Henderson {
1203d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1204d2fd745fSRichard Henderson 
1205d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1206d2fd745fSRichard Henderson 
1207d2fd745fSRichard Henderson     t = tcg_temp_new_internal(t->base_type, 0);
1208d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1209d2fd745fSRichard Henderson }
1210d2fd745fSRichard Henderson 
12115bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1212c896fe29Sbellard {
1213b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1214085272b3SRichard Henderson     int k, idx;
1215c896fe29Sbellard 
1216c7482438SRichard Henderson     switch (ts->kind) {
1217c7482438SRichard Henderson     case TEMP_CONST:
1218c7482438SRichard Henderson         /*
1219c7482438SRichard Henderson          * In order to simplify users of tcg_constant_*,
1220c7482438SRichard Henderson          * silently ignore free.
1221c7482438SRichard Henderson          */
1222c0522136SRichard Henderson         return;
1223c7482438SRichard Henderson     case TEMP_NORMAL:
1224c7482438SRichard Henderson     case TEMP_LOCAL:
1225c7482438SRichard Henderson         break;
1226c7482438SRichard Henderson     default:
1227c7482438SRichard Henderson         g_assert_not_reached();
1228c0522136SRichard Henderson     }
1229c0522136SRichard Henderson 
123027bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
123127bfd83cSPeter Maydell     s->temps_in_use--;
123227bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
123327bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
123427bfd83cSPeter Maydell     }
123527bfd83cSPeter Maydell #endif
123627bfd83cSPeter Maydell 
1237eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
1238e8996ee0Sbellard     ts->temp_allocated = 0;
12390ec9eabcSRichard Henderson 
1240085272b3SRichard Henderson     idx = temp_idx(ts);
1241ee17db83SRichard Henderson     k = ts->base_type + (ts->kind == TEMP_NORMAL ? 0 : TCG_TYPE_COUNT);
12420ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
1243e8996ee0Sbellard }
1244e8996ee0Sbellard 
1245c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val)
1246c0522136SRichard Henderson {
1247c0522136SRichard Henderson     TCGContext *s = tcg_ctx;
1248c0522136SRichard Henderson     GHashTable *h = s->const_table[type];
1249c0522136SRichard Henderson     TCGTemp *ts;
1250c0522136SRichard Henderson 
1251c0522136SRichard Henderson     if (h == NULL) {
1252c0522136SRichard Henderson         h = g_hash_table_new(g_int64_hash, g_int64_equal);
1253c0522136SRichard Henderson         s->const_table[type] = h;
1254c0522136SRichard Henderson     }
1255c0522136SRichard Henderson 
1256c0522136SRichard Henderson     ts = g_hash_table_lookup(h, &val);
1257c0522136SRichard Henderson     if (ts == NULL) {
1258aef85402SRichard Henderson         int64_t *val_ptr;
1259aef85402SRichard Henderson 
1260c0522136SRichard Henderson         ts = tcg_temp_alloc(s);
1261c0522136SRichard Henderson 
1262c0522136SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
1263c0522136SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
1264c0522136SRichard Henderson 
1265aef85402SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
1266aef85402SRichard Henderson 
1267c0522136SRichard Henderson             ts->base_type = TCG_TYPE_I64;
1268c0522136SRichard Henderson             ts->type = TCG_TYPE_I32;
1269c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1270c0522136SRichard Henderson             ts->temp_allocated = 1;
1271c0522136SRichard Henderson 
1272c0522136SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
1273c0522136SRichard Henderson             ts2->type = TCG_TYPE_I32;
1274c0522136SRichard Henderson             ts2->kind = TEMP_CONST;
1275c0522136SRichard Henderson             ts2->temp_allocated = 1;
1276fac87bd2SRichard Henderson             ts2->temp_subindex = 1;
1277aef85402SRichard Henderson 
1278aef85402SRichard Henderson             /*
1279aef85402SRichard Henderson              * Retain the full value of the 64-bit constant in the low
1280aef85402SRichard Henderson              * part, so that the hash table works.  Actual uses will
1281aef85402SRichard Henderson              * truncate the value to the low part.
1282aef85402SRichard Henderson              */
1283aef85402SRichard Henderson             ts[HOST_BIG_ENDIAN].val = val;
1284aef85402SRichard Henderson             ts[!HOST_BIG_ENDIAN].val = val >> 32;
1285aef85402SRichard Henderson             val_ptr = &ts[HOST_BIG_ENDIAN].val;
1286c0522136SRichard Henderson         } else {
1287c0522136SRichard Henderson             ts->base_type = type;
1288c0522136SRichard Henderson             ts->type = type;
1289c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1290c0522136SRichard Henderson             ts->temp_allocated = 1;
1291c0522136SRichard Henderson             ts->val = val;
1292aef85402SRichard Henderson             val_ptr = &ts->val;
1293c0522136SRichard Henderson         }
1294aef85402SRichard Henderson         g_hash_table_insert(h, val_ptr, ts);
1295c0522136SRichard Henderson     }
1296c0522136SRichard Henderson 
1297c0522136SRichard Henderson     return ts;
1298c0522136SRichard Henderson }
1299c0522136SRichard Henderson 
1300c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val)
1301c0522136SRichard Henderson {
1302c0522136SRichard Henderson     val = dup_const(vece, val);
1303c0522136SRichard Henderson     return temp_tcgv_vec(tcg_constant_internal(type, val));
1304c0522136SRichard Henderson }
1305c0522136SRichard Henderson 
130688d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val)
130788d4005bSRichard Henderson {
130888d4005bSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
130988d4005bSRichard Henderson 
131088d4005bSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
131188d4005bSRichard Henderson     return tcg_constant_vec(t->base_type, vece, val);
131288d4005bSRichard Henderson }
131388d4005bSRichard Henderson 
1314a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
1315a7812ae4Spbrook {
1316a7812ae4Spbrook     TCGv_i32 t0;
1317a7812ae4Spbrook     t0 = tcg_temp_new_i32();
1318e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
1319e8996ee0Sbellard     return t0;
1320c896fe29Sbellard }
1321c896fe29Sbellard 
1322a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
1323c896fe29Sbellard {
1324a7812ae4Spbrook     TCGv_i64 t0;
1325a7812ae4Spbrook     t0 = tcg_temp_new_i64();
1326e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
1327e8996ee0Sbellard     return t0;
1328c896fe29Sbellard }
1329c896fe29Sbellard 
1330a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
1331bdffd4a9Saurel32 {
1332a7812ae4Spbrook     TCGv_i32 t0;
1333a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
1334bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
1335bdffd4a9Saurel32     return t0;
1336bdffd4a9Saurel32 }
1337bdffd4a9Saurel32 
1338a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
1339bdffd4a9Saurel32 {
1340a7812ae4Spbrook     TCGv_i64 t0;
1341a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
1342bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
1343bdffd4a9Saurel32     return t0;
1344bdffd4a9Saurel32 }
1345bdffd4a9Saurel32 
134627bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
134727bfd83cSPeter Maydell void tcg_clear_temp_count(void)
134827bfd83cSPeter Maydell {
1349b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
135027bfd83cSPeter Maydell     s->temps_in_use = 0;
135127bfd83cSPeter Maydell }
135227bfd83cSPeter Maydell 
135327bfd83cSPeter Maydell int tcg_check_temp_count(void)
135427bfd83cSPeter Maydell {
1355b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
135627bfd83cSPeter Maydell     if (s->temps_in_use) {
135727bfd83cSPeter Maydell         /* Clear the count so that we don't give another
135827bfd83cSPeter Maydell          * warning immediately next time around.
135927bfd83cSPeter Maydell          */
136027bfd83cSPeter Maydell         s->temps_in_use = 0;
136127bfd83cSPeter Maydell         return 1;
136227bfd83cSPeter Maydell     }
136327bfd83cSPeter Maydell     return 0;
136427bfd83cSPeter Maydell }
136527bfd83cSPeter Maydell #endif
136627bfd83cSPeter Maydell 
1367be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1368be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1369be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1370be0f34b5SRichard Henderson {
1371d2fd745fSRichard Henderson     const bool have_vec
1372d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1373d2fd745fSRichard Henderson 
1374be0f34b5SRichard Henderson     switch (op) {
1375be0f34b5SRichard Henderson     case INDEX_op_discard:
1376be0f34b5SRichard Henderson     case INDEX_op_set_label:
1377be0f34b5SRichard Henderson     case INDEX_op_call:
1378be0f34b5SRichard Henderson     case INDEX_op_br:
1379be0f34b5SRichard Henderson     case INDEX_op_mb:
1380be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1381be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1382be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1383f4e01e30SRichard Henderson     case INDEX_op_goto_ptr:
1384be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i32:
1385be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i32:
1386be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i64:
1387be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i64:
1388be0f34b5SRichard Henderson         return true;
1389be0f34b5SRichard Henderson 
139007ce0b05SRichard Henderson     case INDEX_op_qemu_st8_i32:
139107ce0b05SRichard Henderson         return TCG_TARGET_HAS_qemu_st8_i32;
139207ce0b05SRichard Henderson 
1393be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1394be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1395be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1396be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1397be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1398be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1399be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1400be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1401be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1402be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1403be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1404be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1405be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1406be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1407be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1408be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1409be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1410be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1411be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1412be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1413be0f34b5SRichard Henderson         return true;
1414be0f34b5SRichard Henderson 
1415be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1416be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1417be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1418be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1419be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1420be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1421be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1422be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1423be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1424be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1425be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1426be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1427be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1428be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1429be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1430be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1431be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1432be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1433be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1434be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1435fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
1436fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
1437be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1438be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1439be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1440be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1441be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1442be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1443be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1444be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1445be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1446be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1447be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1448be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1449be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1450be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1451be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1452be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1453be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1454be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1455be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1456be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1457be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1458be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1459be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1460be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1461be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1462be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1463be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1464be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1465be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1466be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1467be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1468be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1469be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1470be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1471be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1472be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1473be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1474be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1475be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1476be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1477be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1478be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1479be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1480be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1481be0f34b5SRichard Henderson 
1482be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1483be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1484be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1485be0f34b5SRichard Henderson 
1486be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1487be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1488be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1489be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1490be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1491be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1492be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1493be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1494be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1495be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1496be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1497be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1498be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1499be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1500be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1501be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1502be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1503be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1504be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1505be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1506be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1507be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1508be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1509be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1510be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1511be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1512be0f34b5SRichard Henderson 
1513be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1514be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1515be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1516be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1517be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1518be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1519be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1520be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1521be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1522be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
1523be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
1524be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
1525be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
1526be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
1527be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
1528be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
1529be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
1530be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
1531be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
1532be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
1533fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
1534fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
1535be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
1536be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrl_i64_i32;
1537be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
1538be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrh_i64_i32;
1539be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
1540be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
1541be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
1542be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
1543be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
1544be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
1545be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
1546be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
1547be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
1548be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
1549be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
1550be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
1551be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
1552be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
1553be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
1554be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
1555be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
1556be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
1557be0f34b5SRichard Henderson     case INDEX_op_not_i64:
1558be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
1559be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
1560be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
1561be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
1562be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
1563be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
1564be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
1565be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
1566be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
1567be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
1568be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
1569be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
1570be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
1571be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
1572be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
1573be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
1574be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
1575be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
1576be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
1577be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
1578be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
1579be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
1580be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
1581be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
1582be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
1583be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
1584be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
1585be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
1586be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
1587be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
1588be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
1589be0f34b5SRichard Henderson 
1590d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
1591d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
159237ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
1593d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
1594d2fd745fSRichard Henderson     case INDEX_op_st_vec:
1595d2fd745fSRichard Henderson     case INDEX_op_add_vec:
1596d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
1597d2fd745fSRichard Henderson     case INDEX_op_and_vec:
1598d2fd745fSRichard Henderson     case INDEX_op_or_vec:
1599d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
1600212be173SRichard Henderson     case INDEX_op_cmp_vec:
1601d2fd745fSRichard Henderson         return have_vec;
1602d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
1603d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
1604d2fd745fSRichard Henderson     case INDEX_op_not_vec:
1605d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
1606d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
1607d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
1608bcefc902SRichard Henderson     case INDEX_op_abs_vec:
1609bcefc902SRichard Henderson         return have_vec && TCG_TARGET_HAS_abs_vec;
1610d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
1611d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
1612d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
1613d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
1614ed523473SRichard Henderson     case INDEX_op_nand_vec:
1615ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_nand_vec;
1616ed523473SRichard Henderson     case INDEX_op_nor_vec:
1617ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_nor_vec;
1618ed523473SRichard Henderson     case INDEX_op_eqv_vec:
1619ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_eqv_vec;
16203774030aSRichard Henderson     case INDEX_op_mul_vec:
16213774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
1622d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
1623d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
1624d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
1625d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
1626d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
1627d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
1628d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
1629d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
1630d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
1631d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
1632d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
1633d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
1634b0f7e744SRichard Henderson     case INDEX_op_rotli_vec:
1635b0f7e744SRichard Henderson         return have_vec && TCG_TARGET_HAS_roti_vec;
163623850a74SRichard Henderson     case INDEX_op_rotls_vec:
163723850a74SRichard Henderson         return have_vec && TCG_TARGET_HAS_rots_vec;
16385d0ceda9SRichard Henderson     case INDEX_op_rotlv_vec:
16395d0ceda9SRichard Henderson     case INDEX_op_rotrv_vec:
16405d0ceda9SRichard Henderson         return have_vec && TCG_TARGET_HAS_rotv_vec;
16418afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
16428afaf050SRichard Henderson     case INDEX_op_usadd_vec:
16438afaf050SRichard Henderson     case INDEX_op_sssub_vec:
16448afaf050SRichard Henderson     case INDEX_op_ussub_vec:
16458afaf050SRichard Henderson         return have_vec && TCG_TARGET_HAS_sat_vec;
1646dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
1647dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
1648dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
1649dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
1650dd0a0fcdSRichard Henderson         return have_vec && TCG_TARGET_HAS_minmax_vec;
165138dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
165238dc1294SRichard Henderson         return have_vec && TCG_TARGET_HAS_bitsel_vec;
1653f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
1654f75da298SRichard Henderson         return have_vec && TCG_TARGET_HAS_cmpsel_vec;
1655d2fd745fSRichard Henderson 
1656db432672SRichard Henderson     default:
1657db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
1658db432672SRichard Henderson         return true;
1659be0f34b5SRichard Henderson     }
1660be0f34b5SRichard Henderson }
1661be0f34b5SRichard Henderson 
166239004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs);
166339004a71SRichard Henderson 
1664ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
1665c896fe29Sbellard {
16663e92aa34SRichard Henderson     const TCGHelperInfo *info;
166739004a71SRichard Henderson     TCGv_i64 extend_free[MAX_CALL_IARGS];
166839004a71SRichard Henderson     int n_extend = 0;
166975e8b9b7SRichard Henderson     TCGOp *op;
167039004a71SRichard Henderson     int i, n, pi = 0, total_args;
1671afb49896SRichard Henderson 
1672619205fdSEmilio G. Cota     info = g_hash_table_lookup(helper_table, (gpointer)func);
167339004a71SRichard Henderson     total_args = info->nr_out + info->nr_in + 2;
167439004a71SRichard Henderson     op = tcg_op_alloc(INDEX_op_call, total_args);
16752bece2c8SRichard Henderson 
167638b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
167738b47b19SEmilio G. Cota     /* detect non-plugin helpers */
167838b47b19SEmilio G. Cota     if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) {
167938b47b19SEmilio G. Cota         tcg_ctx->plugin_insn->calls_helpers = true;
168038b47b19SEmilio G. Cota     }
168138b47b19SEmilio G. Cota #endif
168238b47b19SEmilio G. Cota 
168339004a71SRichard Henderson     TCGOP_CALLO(op) = n = info->nr_out;
168439004a71SRichard Henderson     switch (n) {
168539004a71SRichard Henderson     case 0:
168639004a71SRichard Henderson         tcg_debug_assert(ret == NULL);
168739004a71SRichard Henderson         break;
168839004a71SRichard Henderson     case 1:
168939004a71SRichard Henderson         tcg_debug_assert(ret != NULL);
169039004a71SRichard Henderson         op->args[pi++] = temp_arg(ret);
169139004a71SRichard Henderson         break;
169239004a71SRichard Henderson     case 2:
169339004a71SRichard Henderson         tcg_debug_assert(ret != NULL);
169439004a71SRichard Henderson         tcg_debug_assert(ret->base_type == ret->type + 1);
169539004a71SRichard Henderson         tcg_debug_assert(ret->temp_subindex == 0);
169639004a71SRichard Henderson         op->args[pi++] = temp_arg(ret);
169739004a71SRichard Henderson         op->args[pi++] = temp_arg(ret + 1);
169839004a71SRichard Henderson         break;
169939004a71SRichard Henderson     default:
170039004a71SRichard Henderson         g_assert_not_reached();
170139004a71SRichard Henderson     }
17027319d83aSRichard Henderson 
170339004a71SRichard Henderson     TCGOP_CALLI(op) = n = info->nr_in;
170439004a71SRichard Henderson     for (i = 0; i < n; i++) {
170539004a71SRichard Henderson         const TCGCallArgumentLoc *loc = &info->in[i];
170639004a71SRichard Henderson         TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex;
170739004a71SRichard Henderson 
170839004a71SRichard Henderson         switch (loc->kind) {
170939004a71SRichard Henderson         case TCG_CALL_ARG_NORMAL:
171039004a71SRichard Henderson             op->args[pi++] = temp_arg(ts);
171139004a71SRichard Henderson             break;
171239004a71SRichard Henderson 
171339004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
171439004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
171539004a71SRichard Henderson             {
17162bece2c8SRichard Henderson                 TCGv_i64 temp = tcg_temp_new_i64();
171739004a71SRichard Henderson                 TCGv_i32 orig = temp_tcgv_i32(ts);
171839004a71SRichard Henderson 
171939004a71SRichard Henderson                 if (loc->kind == TCG_CALL_ARG_EXTEND_S) {
172018cf3d07SRichard Henderson                     tcg_gen_ext_i32_i64(temp, orig);
17212bece2c8SRichard Henderson                 } else {
172218cf3d07SRichard Henderson                     tcg_gen_extu_i32_i64(temp, orig);
17232bece2c8SRichard Henderson                 }
172439004a71SRichard Henderson                 op->args[pi++] = tcgv_i64_arg(temp);
172539004a71SRichard Henderson                 extend_free[n_extend++] = temp;
17262bece2c8SRichard Henderson             }
172739004a71SRichard Henderson             break;
17282bece2c8SRichard Henderson 
1729e2a9dd6bSRichard Henderson         default:
1730e2a9dd6bSRichard Henderson             g_assert_not_reached();
1731e2a9dd6bSRichard Henderson         }
1732c896fe29Sbellard     }
173375e8b9b7SRichard Henderson     op->args[pi++] = (uintptr_t)func;
17343e92aa34SRichard Henderson     op->args[pi++] = (uintptr_t)info;
173539004a71SRichard Henderson     tcg_debug_assert(pi == total_args);
1736a7812ae4Spbrook 
173739004a71SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
17382bece2c8SRichard Henderson 
173939004a71SRichard Henderson     tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free));
174039004a71SRichard Henderson     for (i = 0; i < n_extend; ++i) {
174139004a71SRichard Henderson         tcg_temp_free_i64(extend_free[i]);
1742eb8b0224SRichard Henderson     }
1743a7812ae4Spbrook }
1744c896fe29Sbellard 
17458fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
1746c896fe29Sbellard {
1747ac3b8891SRichard Henderson     int i, n;
1748ac3b8891SRichard Henderson 
1749ee17db83SRichard Henderson     for (i = 0, n = s->nb_temps; i < n; i++) {
1750ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
1751ee17db83SRichard Henderson         TCGTempVal val = TEMP_VAL_MEM;
1752ee17db83SRichard Henderson 
1753ee17db83SRichard Henderson         switch (ts->kind) {
1754c0522136SRichard Henderson         case TEMP_CONST:
1755c0522136SRichard Henderson             val = TEMP_VAL_CONST;
1756c0522136SRichard Henderson             break;
1757ee17db83SRichard Henderson         case TEMP_FIXED:
1758ee17db83SRichard Henderson             val = TEMP_VAL_REG;
1759ee17db83SRichard Henderson             break;
1760ee17db83SRichard Henderson         case TEMP_GLOBAL:
1761ee17db83SRichard Henderson             break;
1762ee17db83SRichard Henderson         case TEMP_NORMAL:
1763c7482438SRichard Henderson         case TEMP_EBB:
1764ee17db83SRichard Henderson             val = TEMP_VAL_DEAD;
1765ee17db83SRichard Henderson             /* fall through */
1766ee17db83SRichard Henderson         case TEMP_LOCAL:
1767e8996ee0Sbellard             ts->mem_allocated = 0;
1768ee17db83SRichard Henderson             break;
1769ee17db83SRichard Henderson         default:
1770ee17db83SRichard Henderson             g_assert_not_reached();
1771ee17db83SRichard Henderson         }
1772ee17db83SRichard Henderson         ts->val_type = val;
1773e8996ee0Sbellard     }
1774f8b2f202SRichard Henderson 
1775f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
1776c896fe29Sbellard }
1777c896fe29Sbellard 
1778f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
1779f8b2f202SRichard Henderson                                  TCGTemp *ts)
1780c896fe29Sbellard {
17811807f4c4SRichard Henderson     int idx = temp_idx(ts);
1782ac56dd48Spbrook 
1783ee17db83SRichard Henderson     switch (ts->kind) {
1784ee17db83SRichard Henderson     case TEMP_FIXED:
1785ee17db83SRichard Henderson     case TEMP_GLOBAL:
1786ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
1787ee17db83SRichard Henderson         break;
1788ee17db83SRichard Henderson     case TEMP_LOCAL:
1789641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
1790ee17db83SRichard Henderson         break;
1791c7482438SRichard Henderson     case TEMP_EBB:
1792c7482438SRichard Henderson         snprintf(buf, buf_size, "ebb%d", idx - s->nb_globals);
1793c7482438SRichard Henderson         break;
1794ee17db83SRichard Henderson     case TEMP_NORMAL:
1795ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
1796ee17db83SRichard Henderson         break;
1797c0522136SRichard Henderson     case TEMP_CONST:
1798c0522136SRichard Henderson         switch (ts->type) {
1799c0522136SRichard Henderson         case TCG_TYPE_I32:
1800c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val);
1801c0522136SRichard Henderson             break;
1802c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32
1803c0522136SRichard Henderson         case TCG_TYPE_I64:
1804c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%" PRIx64, ts->val);
1805c0522136SRichard Henderson             break;
1806c0522136SRichard Henderson #endif
1807c0522136SRichard Henderson         case TCG_TYPE_V64:
1808c0522136SRichard Henderson         case TCG_TYPE_V128:
1809c0522136SRichard Henderson         case TCG_TYPE_V256:
1810c0522136SRichard Henderson             snprintf(buf, buf_size, "v%d$0x%" PRIx64,
1811c0522136SRichard Henderson                      64 << (ts->type - TCG_TYPE_V64), ts->val);
1812c0522136SRichard Henderson             break;
1813c0522136SRichard Henderson         default:
1814c0522136SRichard Henderson             g_assert_not_reached();
1815c0522136SRichard Henderson         }
1816c0522136SRichard Henderson         break;
1817c896fe29Sbellard     }
1818c896fe29Sbellard     return buf;
1819c896fe29Sbellard }
1820c896fe29Sbellard 
182143439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
182243439139SRichard Henderson                              int buf_size, TCGArg arg)
1823f8b2f202SRichard Henderson {
182443439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
1825f8b2f202SRichard Henderson }
1826f8b2f202SRichard Henderson 
1827f48f3edeSblueswir1 static const char * const cond_name[] =
1828f48f3edeSblueswir1 {
18290aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
18300aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
1831f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
1832f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
1833f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
1834f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
1835f48f3edeSblueswir1     [TCG_COND_LE] = "le",
1836f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
1837f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
1838f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
1839f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
1840f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
1841f48f3edeSblueswir1 };
1842f48f3edeSblueswir1 
1843f713d6adSRichard Henderson static const char * const ldst_name[] =
1844f713d6adSRichard Henderson {
1845f713d6adSRichard Henderson     [MO_UB]   = "ub",
1846f713d6adSRichard Henderson     [MO_SB]   = "sb",
1847f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
1848f713d6adSRichard Henderson     [MO_LESW] = "lesw",
1849f713d6adSRichard Henderson     [MO_LEUL] = "leul",
1850f713d6adSRichard Henderson     [MO_LESL] = "lesl",
1851fc313c64SFrédéric Pétrot     [MO_LEUQ] = "leq",
1852f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
1853f713d6adSRichard Henderson     [MO_BESW] = "besw",
1854f713d6adSRichard Henderson     [MO_BEUL] = "beul",
1855f713d6adSRichard Henderson     [MO_BESL] = "besl",
1856fc313c64SFrédéric Pétrot     [MO_BEUQ] = "beq",
1857f713d6adSRichard Henderson };
1858f713d6adSRichard Henderson 
18591f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
186052bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY
18611f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
18621f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
18631f00b27fSSergey Sorokin #else
18641f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
18651f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
18661f00b27fSSergey Sorokin #endif
18671f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
18681f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
18691f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
18701f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
18711f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
18721f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
18731f00b27fSSergey Sorokin };
18741f00b27fSSergey Sorokin 
1875587195bdSRichard Henderson static const char bswap_flag_name[][6] = {
1876587195bdSRichard Henderson     [TCG_BSWAP_IZ] = "iz",
1877587195bdSRichard Henderson     [TCG_BSWAP_OZ] = "oz",
1878587195bdSRichard Henderson     [TCG_BSWAP_OS] = "os",
1879587195bdSRichard Henderson     [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz",
1880587195bdSRichard Henderson     [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os",
1881587195bdSRichard Henderson };
1882587195bdSRichard Henderson 
1883b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
1884b016486eSRichard Henderson {
1885b016486eSRichard Henderson     return (d & (d - 1)) == 0;
1886b016486eSRichard Henderson }
1887b016486eSRichard Henderson 
1888b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
1889b016486eSRichard Henderson {
1890b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
1891b016486eSRichard Henderson         return ctz32(d);
1892b016486eSRichard Henderson     } else {
1893b016486eSRichard Henderson         return ctz64(d);
1894b016486eSRichard Henderson     }
1895b016486eSRichard Henderson }
1896b016486eSRichard Henderson 
1897b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */
1898b7a83ff8SRichard Henderson #define ne_fprintf(...) \
1899b7a83ff8SRichard Henderson     ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; })
1900b7a83ff8SRichard Henderson 
1901b7a83ff8SRichard Henderson static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
1902c896fe29Sbellard {
1903c896fe29Sbellard     char buf[128];
1904c45cb8bbSRichard Henderson     TCGOp *op;
1905c896fe29Sbellard 
190615fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
1907c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
1908c45cb8bbSRichard Henderson         const TCGOpDef *def;
1909c45cb8bbSRichard Henderson         TCGOpcode c;
1910bdfb460eSRichard Henderson         int col = 0;
1911c45cb8bbSRichard Henderson 
1912c45cb8bbSRichard Henderson         c = op->opc;
1913c896fe29Sbellard         def = &tcg_op_defs[c];
1914c45cb8bbSRichard Henderson 
1915765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
1916b016486eSRichard Henderson             nb_oargs = 0;
1917b7a83ff8SRichard Henderson             col += ne_fprintf(f, "\n ----");
19189aef40edSRichard Henderson 
19199aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
19209aef40edSRichard Henderson                 target_ulong a;
19217e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
1922efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
19237e4597d7Sbellard #else
1924efee3746SRichard Henderson                 a = op->args[i];
19257e4597d7Sbellard #endif
1926b7a83ff8SRichard Henderson                 col += ne_fprintf(f, " " TARGET_FMT_lx, a);
1927eeacee4dSBlue Swirl             }
19287e4597d7Sbellard         } else if (c == INDEX_op_call) {
19293e92aa34SRichard Henderson             const TCGHelperInfo *info = tcg_call_info(op);
1930fa52e660SRichard Henderson             void *func = tcg_call_func(op);
19313e92aa34SRichard Henderson 
1932c896fe29Sbellard             /* variable number of arguments */
1933cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
1934cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
1935c896fe29Sbellard             nb_cargs = def->nb_cargs;
1936b03cce8eSbellard 
1937b7a83ff8SRichard Henderson             col += ne_fprintf(f, " %s ", def->name);
19383e92aa34SRichard Henderson 
19393e92aa34SRichard Henderson             /*
19403e92aa34SRichard Henderson              * Print the function name from TCGHelperInfo, if available.
19413e92aa34SRichard Henderson              * Note that plugins have a template function for the info,
19423e92aa34SRichard Henderson              * but the actual function pointer comes from the plugin.
19433e92aa34SRichard Henderson              */
19443e92aa34SRichard Henderson             if (func == info->func) {
1945b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s", info->name);
19463e92aa34SRichard Henderson             } else {
1947b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "plugin(%p)", func);
19483e92aa34SRichard Henderson             }
19493e92aa34SRichard Henderson 
1950b7a83ff8SRichard Henderson             col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs);
1951b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
1952b7a83ff8SRichard Henderson                 col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf),
1953efee3746SRichard Henderson                                                             op->args[i]));
1954b03cce8eSbellard             }
1955cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
1956efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
195739004a71SRichard Henderson                 const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
1958b7a83ff8SRichard Henderson                 col += ne_fprintf(f, ",%s", t);
1959e8996ee0Sbellard             }
1960b03cce8eSbellard         } else {
1961b7a83ff8SRichard Henderson             col += ne_fprintf(f, " %s ", def->name);
1962c45cb8bbSRichard Henderson 
1963c896fe29Sbellard             nb_oargs = def->nb_oargs;
1964c896fe29Sbellard             nb_iargs = def->nb_iargs;
1965c896fe29Sbellard             nb_cargs = def->nb_cargs;
1966c896fe29Sbellard 
1967d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
1968b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "v%d,e%d,", 64 << TCGOP_VECL(op),
1969d2fd745fSRichard Henderson                                   8 << TCGOP_VECE(op));
1970d2fd745fSRichard Henderson             }
1971d2fd745fSRichard Henderson 
1972c896fe29Sbellard             k = 0;
1973c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
1974b7a83ff8SRichard Henderson                 const char *sep =  k ? "," : "";
1975b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s%s", sep,
1976b7a83ff8SRichard Henderson                                   tcg_get_arg_str(s, buf, sizeof(buf),
1977efee3746SRichard Henderson                                                   op->args[k++]));
1978c896fe29Sbellard             }
1979c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
1980b7a83ff8SRichard Henderson                 const char *sep =  k ? "," : "";
1981b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s%s", sep,
1982b7a83ff8SRichard Henderson                                   tcg_get_arg_str(s, buf, sizeof(buf),
1983efee3746SRichard Henderson                                                   op->args[k++]));
1984c896fe29Sbellard             }
1985be210acbSRichard Henderson             switch (c) {
1986be210acbSRichard Henderson             case INDEX_op_brcond_i32:
1987ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
1988ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
1989be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
1990be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
1991ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
1992be210acbSRichard Henderson             case INDEX_op_setcond_i64:
1993ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
1994212be173SRichard Henderson             case INDEX_op_cmp_vec:
1995f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
1996efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
1997efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
1998b7a83ff8SRichard Henderson                     col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]);
1999eeacee4dSBlue Swirl                 } else {
2000b7a83ff8SRichard Henderson                     col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]);
2001eeacee4dSBlue Swirl                 }
2002f48f3edeSblueswir1                 i = 1;
2003be210acbSRichard Henderson                 break;
2004f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
2005f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
200607ce0b05SRichard Henderson             case INDEX_op_qemu_st8_i32:
2007f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
2008f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
200959227d5dSRichard Henderson                 {
20109002ffcbSRichard Henderson                     MemOpIdx oi = op->args[k++];
201114776ab5STony Nguyen                     MemOp op = get_memop(oi);
201259227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
201359227d5dSRichard Henderson 
201459c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
2015b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",$0x%x,%u", op, ix);
201659c4b7e8SRichard Henderson                     } else {
20171f00b27fSSergey Sorokin                         const char *s_al, *s_op;
20181f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
201959c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
2020b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",%s%s,%u", s_al, s_op, ix);
2021f713d6adSRichard Henderson                     }
2022f713d6adSRichard Henderson                     i = 1;
202359227d5dSRichard Henderson                 }
2024f713d6adSRichard Henderson                 break;
2025587195bdSRichard Henderson             case INDEX_op_bswap16_i32:
2026587195bdSRichard Henderson             case INDEX_op_bswap16_i64:
2027587195bdSRichard Henderson             case INDEX_op_bswap32_i32:
2028587195bdSRichard Henderson             case INDEX_op_bswap32_i64:
2029587195bdSRichard Henderson             case INDEX_op_bswap64_i64:
2030587195bdSRichard Henderson                 {
2031587195bdSRichard Henderson                     TCGArg flags = op->args[k];
2032587195bdSRichard Henderson                     const char *name = NULL;
2033587195bdSRichard Henderson 
2034587195bdSRichard Henderson                     if (flags < ARRAY_SIZE(bswap_flag_name)) {
2035587195bdSRichard Henderson                         name = bswap_flag_name[flags];
2036587195bdSRichard Henderson                     }
2037587195bdSRichard Henderson                     if (name) {
2038b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",%s", name);
2039587195bdSRichard Henderson                     } else {
2040b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags);
2041587195bdSRichard Henderson                     }
2042587195bdSRichard Henderson                     i = k = 1;
2043587195bdSRichard Henderson                 }
2044587195bdSRichard Henderson                 break;
2045be210acbSRichard Henderson             default:
2046f48f3edeSblueswir1                 i = 0;
2047be210acbSRichard Henderson                 break;
2048be210acbSRichard Henderson             }
204951e3972cSRichard Henderson             switch (c) {
205051e3972cSRichard Henderson             case INDEX_op_set_label:
205151e3972cSRichard Henderson             case INDEX_op_br:
205251e3972cSRichard Henderson             case INDEX_op_brcond_i32:
205351e3972cSRichard Henderson             case INDEX_op_brcond_i64:
205451e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2055b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s$L%d", k ? "," : "",
2056efee3746SRichard Henderson                                   arg_label(op->args[k])->id);
205751e3972cSRichard Henderson                 i++, k++;
205851e3972cSRichard Henderson                 break;
205951e3972cSRichard Henderson             default:
206051e3972cSRichard Henderson                 break;
2061eeacee4dSBlue Swirl             }
206251e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
2063b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "",
2064b7a83ff8SRichard Henderson                                   op->args[k]);
2065bdfb460eSRichard Henderson             }
2066bdfb460eSRichard Henderson         }
2067bdfb460eSRichard Henderson 
20681894f69aSRichard Henderson         if (have_prefs || op->life) {
20691894f69aSRichard Henderson             for (; col < 40; ++col) {
2070b7a83ff8SRichard Henderson                 putc(' ', f);
2071bdfb460eSRichard Henderson             }
20721894f69aSRichard Henderson         }
20731894f69aSRichard Henderson 
20741894f69aSRichard Henderson         if (op->life) {
20751894f69aSRichard Henderson             unsigned life = op->life;
2076bdfb460eSRichard Henderson 
2077bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
2078b7a83ff8SRichard Henderson                 ne_fprintf(f, "  sync:");
2079bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
2080bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
2081b7a83ff8SRichard Henderson                         ne_fprintf(f, " %d", i);
2082bdfb460eSRichard Henderson                     }
2083bdfb460eSRichard Henderson                 }
2084bdfb460eSRichard Henderson             }
2085bdfb460eSRichard Henderson             life /= DEAD_ARG;
2086bdfb460eSRichard Henderson             if (life) {
2087b7a83ff8SRichard Henderson                 ne_fprintf(f, "  dead:");
2088bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
2089bdfb460eSRichard Henderson                     if (life & 1) {
2090b7a83ff8SRichard Henderson                         ne_fprintf(f, " %d", i);
2091bdfb460eSRichard Henderson                     }
2092bdfb460eSRichard Henderson                 }
2093c896fe29Sbellard             }
2094b03cce8eSbellard         }
20951894f69aSRichard Henderson 
20961894f69aSRichard Henderson         if (have_prefs) {
20971894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
209831fd884bSRichard Henderson                 TCGRegSet set = output_pref(op, i);
20991894f69aSRichard Henderson 
21001894f69aSRichard Henderson                 if (i == 0) {
2101b7a83ff8SRichard Henderson                     ne_fprintf(f, "  pref=");
21021894f69aSRichard Henderson                 } else {
2103b7a83ff8SRichard Henderson                     ne_fprintf(f, ",");
21041894f69aSRichard Henderson                 }
21051894f69aSRichard Henderson                 if (set == 0) {
2106b7a83ff8SRichard Henderson                     ne_fprintf(f, "none");
21071894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
2108b7a83ff8SRichard Henderson                     ne_fprintf(f, "all");
21091894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
21101894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
21111894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
2112b7a83ff8SRichard Henderson                     ne_fprintf(f, "%s", tcg_target_reg_names[reg]);
21131894f69aSRichard Henderson #endif
21141894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
2115b7a83ff8SRichard Henderson                     ne_fprintf(f, "0x%x", (uint32_t)set);
21161894f69aSRichard Henderson                 } else {
2117b7a83ff8SRichard Henderson                     ne_fprintf(f, "0x%" PRIx64, (uint64_t)set);
21181894f69aSRichard Henderson                 }
21191894f69aSRichard Henderson             }
21201894f69aSRichard Henderson         }
21211894f69aSRichard Henderson 
2122b7a83ff8SRichard Henderson         putc('\n', f);
2123c896fe29Sbellard     }
2124c896fe29Sbellard }
2125c896fe29Sbellard 
2126c896fe29Sbellard /* we give more priority to constraints with less registers */
2127c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2128c896fe29Sbellard {
212974a11790SRichard Henderson     const TCGArgConstraint *arg_ct = &def->args_ct[k];
213029f5e925SRichard Henderson     int n = ctpop64(arg_ct->regs);
2131c896fe29Sbellard 
213229f5e925SRichard Henderson     /*
213329f5e925SRichard Henderson      * Sort constraints of a single register first, which includes output
213429f5e925SRichard Henderson      * aliases (which must exactly match the input already allocated).
213529f5e925SRichard Henderson      */
213629f5e925SRichard Henderson     if (n == 1 || arg_ct->oalias) {
213729f5e925SRichard Henderson         return INT_MAX;
2138c896fe29Sbellard     }
213929f5e925SRichard Henderson 
214029f5e925SRichard Henderson     /*
214129f5e925SRichard Henderson      * Sort register pairs next, first then second immediately after.
214229f5e925SRichard Henderson      * Arbitrarily sort multiple pairs by the index of the first reg;
214329f5e925SRichard Henderson      * there shouldn't be many pairs.
214429f5e925SRichard Henderson      */
214529f5e925SRichard Henderson     switch (arg_ct->pair) {
214629f5e925SRichard Henderson     case 1:
214729f5e925SRichard Henderson     case 3:
214829f5e925SRichard Henderson         return (k + 1) * 2;
214929f5e925SRichard Henderson     case 2:
215029f5e925SRichard Henderson         return (arg_ct->pair_index + 1) * 2 - 1;
215129f5e925SRichard Henderson     }
215229f5e925SRichard Henderson 
215329f5e925SRichard Henderson     /* Finally, sort by decreasing register count. */
215429f5e925SRichard Henderson     assert(n > 1);
215529f5e925SRichard Henderson     return -n;
2156c896fe29Sbellard }
2157c896fe29Sbellard 
2158c896fe29Sbellard /* sort from highest priority to lowest */
2159c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2160c896fe29Sbellard {
216166792f90SRichard Henderson     int i, j;
216266792f90SRichard Henderson     TCGArgConstraint *a = def->args_ct;
2163c896fe29Sbellard 
216466792f90SRichard Henderson     for (i = 0; i < n; i++) {
216566792f90SRichard Henderson         a[start + i].sort_index = start + i;
216666792f90SRichard Henderson     }
216766792f90SRichard Henderson     if (n <= 1) {
2168c896fe29Sbellard         return;
216966792f90SRichard Henderson     }
2170c896fe29Sbellard     for (i = 0; i < n - 1; i++) {
2171c896fe29Sbellard         for (j = i + 1; j < n; j++) {
217266792f90SRichard Henderson             int p1 = get_constraint_priority(def, a[start + i].sort_index);
217366792f90SRichard Henderson             int p2 = get_constraint_priority(def, a[start + j].sort_index);
2174c896fe29Sbellard             if (p1 < p2) {
217566792f90SRichard Henderson                 int tmp = a[start + i].sort_index;
217666792f90SRichard Henderson                 a[start + i].sort_index = a[start + j].sort_index;
217766792f90SRichard Henderson                 a[start + j].sort_index = tmp;
2178c896fe29Sbellard             }
2179c896fe29Sbellard         }
2180c896fe29Sbellard     }
2181c896fe29Sbellard }
2182c896fe29Sbellard 
2183f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2184c896fe29Sbellard {
2185a9751609SRichard Henderson     TCGOpcode op;
2186c896fe29Sbellard 
2187f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
2188f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
2189f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
219029f5e925SRichard Henderson         bool saw_alias_pair = false;
219129f5e925SRichard Henderson         int i, o, i2, o2, nb_args;
2192f69d277eSRichard Henderson 
2193f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
2194f69d277eSRichard Henderson             continue;
2195f69d277eSRichard Henderson         }
2196f69d277eSRichard Henderson 
2197c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
2198f69d277eSRichard Henderson         if (nb_args == 0) {
2199f69d277eSRichard Henderson             continue;
2200f69d277eSRichard Henderson         }
2201f69d277eSRichard Henderson 
22024c22e840SRichard Henderson         /*
22034c22e840SRichard Henderson          * Macro magic should make it impossible, but double-check that
22044c22e840SRichard Henderson          * the array index is in range.  Since the signness of an enum
22054c22e840SRichard Henderson          * is implementation defined, force the result to unsigned.
22064c22e840SRichard Henderson          */
22074c22e840SRichard Henderson         unsigned con_set = tcg_target_op_def(op);
22084c22e840SRichard Henderson         tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets));
22094c22e840SRichard Henderson         tdefs = &constraint_sets[con_set];
2210f69d277eSRichard Henderson 
2211c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2212f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
22138940ea0dSPhilippe Mathieu-Daudé             bool input_p = i >= def->nb_oargs;
22148940ea0dSPhilippe Mathieu-Daudé 
2215f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2216eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2217f69d277eSRichard Henderson 
221817280ff4SRichard Henderson             switch (*ct_str) {
221917280ff4SRichard Henderson             case '0' ... '9':
22208940ea0dSPhilippe Mathieu-Daudé                 o = *ct_str - '0';
22218940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(input_p);
22228940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(o < def->nb_oargs);
22238940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(def->args_ct[o].regs != 0);
22248940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(!def->args_ct[o].oalias);
22258940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i] = def->args_ct[o];
2226bc2b17e6SRichard Henderson                 /* The output sets oalias.  */
22278940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[o].oalias = 1;
22288940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[o].alias_index = i;
2229bc2b17e6SRichard Henderson                 /* The input sets ialias. */
22308940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i].ialias = 1;
22318940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i].alias_index = o;
223229f5e925SRichard Henderson                 if (def->args_ct[i].pair) {
223329f5e925SRichard Henderson                     saw_alias_pair = true;
223429f5e925SRichard Henderson                 }
22358940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(ct_str[1] == '\0');
22368940ea0dSPhilippe Mathieu-Daudé                 continue;
22378940ea0dSPhilippe Mathieu-Daudé 
223882790a87SRichard Henderson             case '&':
22398940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(!input_p);
2240bc2b17e6SRichard Henderson                 def->args_ct[i].newreg = true;
224182790a87SRichard Henderson                 ct_str++;
224282790a87SRichard Henderson                 break;
224329f5e925SRichard Henderson 
224429f5e925SRichard Henderson             case 'p': /* plus */
224529f5e925SRichard Henderson                 /* Allocate to the register after the previous. */
224629f5e925SRichard Henderson                 tcg_debug_assert(i > (input_p ? def->nb_oargs : 0));
224729f5e925SRichard Henderson                 o = i - 1;
224829f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].pair);
224929f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].ct);
225029f5e925SRichard Henderson                 def->args_ct[i] = (TCGArgConstraint){
225129f5e925SRichard Henderson                     .pair = 2,
225229f5e925SRichard Henderson                     .pair_index = o,
225329f5e925SRichard Henderson                     .regs = def->args_ct[o].regs << 1,
225429f5e925SRichard Henderson                 };
225529f5e925SRichard Henderson                 def->args_ct[o].pair = 1;
225629f5e925SRichard Henderson                 def->args_ct[o].pair_index = i;
225729f5e925SRichard Henderson                 tcg_debug_assert(ct_str[1] == '\0');
225829f5e925SRichard Henderson                 continue;
225929f5e925SRichard Henderson 
226029f5e925SRichard Henderson             case 'm': /* minus */
226129f5e925SRichard Henderson                 /* Allocate to the register before the previous. */
226229f5e925SRichard Henderson                 tcg_debug_assert(i > (input_p ? def->nb_oargs : 0));
226329f5e925SRichard Henderson                 o = i - 1;
226429f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].pair);
226529f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].ct);
226629f5e925SRichard Henderson                 def->args_ct[i] = (TCGArgConstraint){
226729f5e925SRichard Henderson                     .pair = 1,
226829f5e925SRichard Henderson                     .pair_index = o,
226929f5e925SRichard Henderson                     .regs = def->args_ct[o].regs >> 1,
227029f5e925SRichard Henderson                 };
227129f5e925SRichard Henderson                 def->args_ct[o].pair = 2;
227229f5e925SRichard Henderson                 def->args_ct[o].pair_index = i;
227329f5e925SRichard Henderson                 tcg_debug_assert(ct_str[1] == '\0');
227429f5e925SRichard Henderson                 continue;
22758940ea0dSPhilippe Mathieu-Daudé             }
22768940ea0dSPhilippe Mathieu-Daudé 
22778940ea0dSPhilippe Mathieu-Daudé             do {
22788940ea0dSPhilippe Mathieu-Daudé                 switch (*ct_str) {
2279c896fe29Sbellard                 case 'i':
2280c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2281c896fe29Sbellard                     break;
2282358b4923SRichard Henderson 
2283358b4923SRichard Henderson                 /* Include all of the target-specific constraints. */
2284358b4923SRichard Henderson 
2285358b4923SRichard Henderson #undef CONST
2286358b4923SRichard Henderson #define CONST(CASE, MASK) \
22878940ea0dSPhilippe Mathieu-Daudé     case CASE: def->args_ct[i].ct |= MASK; break;
2288358b4923SRichard Henderson #define REGS(CASE, MASK) \
22898940ea0dSPhilippe Mathieu-Daudé     case CASE: def->args_ct[i].regs |= MASK; break;
2290358b4923SRichard Henderson 
2291358b4923SRichard Henderson #include "tcg-target-con-str.h"
2292358b4923SRichard Henderson 
2293358b4923SRichard Henderson #undef REGS
2294358b4923SRichard Henderson #undef CONST
2295c896fe29Sbellard                 default:
22968940ea0dSPhilippe Mathieu-Daudé                 case '0' ... '9':
22978940ea0dSPhilippe Mathieu-Daudé                 case '&':
229829f5e925SRichard Henderson                 case 'p':
229929f5e925SRichard Henderson                 case 'm':
2300358b4923SRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2301358b4923SRichard Henderson                     g_assert_not_reached();
2302358b4923SRichard Henderson                 }
23038940ea0dSPhilippe Mathieu-Daudé             } while (*++ct_str != '\0');
2304c896fe29Sbellard         }
2305c896fe29Sbellard 
2306c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2307eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2308c68aaa18SStefan Weil 
230929f5e925SRichard Henderson         /*
231029f5e925SRichard Henderson          * Fix up output pairs that are aliased with inputs.
231129f5e925SRichard Henderson          * When we created the alias, we copied pair from the output.
231229f5e925SRichard Henderson          * There are three cases:
231329f5e925SRichard Henderson          *    (1a) Pairs of inputs alias pairs of outputs.
231429f5e925SRichard Henderson          *    (1b) One input aliases the first of a pair of outputs.
231529f5e925SRichard Henderson          *    (2)  One input aliases the second of a pair of outputs.
231629f5e925SRichard Henderson          *
231729f5e925SRichard Henderson          * Case 1a is handled by making sure that the pair_index'es are
231829f5e925SRichard Henderson          * properly updated so that they appear the same as a pair of inputs.
231929f5e925SRichard Henderson          *
232029f5e925SRichard Henderson          * Case 1b is handled by setting the pair_index of the input to
232129f5e925SRichard Henderson          * itself, simply so it doesn't point to an unrelated argument.
232229f5e925SRichard Henderson          * Since we don't encounter the "second" during the input allocation
232329f5e925SRichard Henderson          * phase, nothing happens with the second half of the input pair.
232429f5e925SRichard Henderson          *
232529f5e925SRichard Henderson          * Case 2 is handled by setting the second input to pair=3, the
232629f5e925SRichard Henderson          * first output to pair=3, and the pair_index'es to match.
232729f5e925SRichard Henderson          */
232829f5e925SRichard Henderson         if (saw_alias_pair) {
232929f5e925SRichard Henderson             for (i = def->nb_oargs; i < nb_args; i++) {
233029f5e925SRichard Henderson                 /*
233129f5e925SRichard Henderson                  * Since [0-9pm] must be alone in the constraint string,
233229f5e925SRichard Henderson                  * the only way they can both be set is if the pair comes
233329f5e925SRichard Henderson                  * from the output alias.
233429f5e925SRichard Henderson                  */
233529f5e925SRichard Henderson                 if (!def->args_ct[i].ialias) {
233629f5e925SRichard Henderson                     continue;
233729f5e925SRichard Henderson                 }
233829f5e925SRichard Henderson                 switch (def->args_ct[i].pair) {
233929f5e925SRichard Henderson                 case 0:
234029f5e925SRichard Henderson                     break;
234129f5e925SRichard Henderson                 case 1:
234229f5e925SRichard Henderson                     o = def->args_ct[i].alias_index;
234329f5e925SRichard Henderson                     o2 = def->args_ct[o].pair_index;
234429f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o].pair == 1);
234529f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o2].pair == 2);
234629f5e925SRichard Henderson                     if (def->args_ct[o2].oalias) {
234729f5e925SRichard Henderson                         /* Case 1a */
234829f5e925SRichard Henderson                         i2 = def->args_ct[o2].alias_index;
234929f5e925SRichard Henderson                         tcg_debug_assert(def->args_ct[i2].pair == 2);
235029f5e925SRichard Henderson                         def->args_ct[i2].pair_index = i;
235129f5e925SRichard Henderson                         def->args_ct[i].pair_index = i2;
235229f5e925SRichard Henderson                     } else {
235329f5e925SRichard Henderson                         /* Case 1b */
235429f5e925SRichard Henderson                         def->args_ct[i].pair_index = i;
235529f5e925SRichard Henderson                     }
235629f5e925SRichard Henderson                     break;
235729f5e925SRichard Henderson                 case 2:
235829f5e925SRichard Henderson                     o = def->args_ct[i].alias_index;
235929f5e925SRichard Henderson                     o2 = def->args_ct[o].pair_index;
236029f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o].pair == 2);
236129f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o2].pair == 1);
236229f5e925SRichard Henderson                     if (def->args_ct[o2].oalias) {
236329f5e925SRichard Henderson                         /* Case 1a */
236429f5e925SRichard Henderson                         i2 = def->args_ct[o2].alias_index;
236529f5e925SRichard Henderson                         tcg_debug_assert(def->args_ct[i2].pair == 1);
236629f5e925SRichard Henderson                         def->args_ct[i2].pair_index = i;
236729f5e925SRichard Henderson                         def->args_ct[i].pair_index = i2;
236829f5e925SRichard Henderson                     } else {
236929f5e925SRichard Henderson                         /* Case 2 */
237029f5e925SRichard Henderson                         def->args_ct[i].pair = 3;
237129f5e925SRichard Henderson                         def->args_ct[o2].pair = 3;
237229f5e925SRichard Henderson                         def->args_ct[i].pair_index = o2;
237329f5e925SRichard Henderson                         def->args_ct[o2].pair_index = i;
237429f5e925SRichard Henderson                     }
237529f5e925SRichard Henderson                     break;
237629f5e925SRichard Henderson                 default:
237729f5e925SRichard Henderson                     g_assert_not_reached();
237829f5e925SRichard Henderson                 }
237929f5e925SRichard Henderson             }
238029f5e925SRichard Henderson         }
238129f5e925SRichard Henderson 
2382c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
2383c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
2384c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
2385c896fe29Sbellard     }
2386c896fe29Sbellard }
2387c896fe29Sbellard 
23880c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
23890c627cdcSRichard Henderson {
2390d88a117eSRichard Henderson     TCGLabel *label;
2391d88a117eSRichard Henderson 
2392d88a117eSRichard Henderson     switch (op->opc) {
2393d88a117eSRichard Henderson     case INDEX_op_br:
2394d88a117eSRichard Henderson         label = arg_label(op->args[0]);
2395d88a117eSRichard Henderson         label->refs--;
2396d88a117eSRichard Henderson         break;
2397d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
2398d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
2399d88a117eSRichard Henderson         label = arg_label(op->args[3]);
2400d88a117eSRichard Henderson         label->refs--;
2401d88a117eSRichard Henderson         break;
2402d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
2403d88a117eSRichard Henderson         label = arg_label(op->args[5]);
2404d88a117eSRichard Henderson         label->refs--;
2405d88a117eSRichard Henderson         break;
2406d88a117eSRichard Henderson     default:
2407d88a117eSRichard Henderson         break;
2408d88a117eSRichard Henderson     }
2409d88a117eSRichard Henderson 
241015fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
241115fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
2412abebf925SRichard Henderson     s->nb_ops--;
24130c627cdcSRichard Henderson 
24140c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
2415d73415a3SStefan Hajnoczi     qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
24160c627cdcSRichard Henderson #endif
24170c627cdcSRichard Henderson }
24180c627cdcSRichard Henderson 
2419a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op)
2420a80cdd31SRichard Henderson {
2421a80cdd31SRichard Henderson     TCGContext *s = tcg_ctx;
2422a80cdd31SRichard Henderson 
2423a80cdd31SRichard Henderson     while (true) {
2424a80cdd31SRichard Henderson         TCGOp *last = tcg_last_op();
2425a80cdd31SRichard Henderson         if (last == op) {
2426a80cdd31SRichard Henderson             return;
2427a80cdd31SRichard Henderson         }
2428a80cdd31SRichard Henderson         tcg_op_remove(s, last);
2429a80cdd31SRichard Henderson     }
2430a80cdd31SRichard Henderson }
2431a80cdd31SRichard Henderson 
2432d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs)
243315fa08f8SRichard Henderson {
243415fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
2435cb10bc63SRichard Henderson     TCGOp *op = NULL;
243615fa08f8SRichard Henderson 
2437cb10bc63SRichard Henderson     if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) {
2438cb10bc63SRichard Henderson         QTAILQ_FOREACH(op, &s->free_ops, link) {
2439cb10bc63SRichard Henderson             if (nargs <= op->nargs) {
244015fa08f8SRichard Henderson                 QTAILQ_REMOVE(&s->free_ops, op, link);
2441cb10bc63SRichard Henderson                 nargs = op->nargs;
2442cb10bc63SRichard Henderson                 goto found;
244315fa08f8SRichard Henderson             }
2444cb10bc63SRichard Henderson         }
2445cb10bc63SRichard Henderson     }
2446cb10bc63SRichard Henderson 
2447cb10bc63SRichard Henderson     /* Most opcodes have 3 or 4 operands: reduce fragmentation. */
2448cb10bc63SRichard Henderson     nargs = MAX(4, nargs);
2449cb10bc63SRichard Henderson     op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs);
2450cb10bc63SRichard Henderson 
2451cb10bc63SRichard Henderson  found:
245215fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
245315fa08f8SRichard Henderson     op->opc = opc;
2454cb10bc63SRichard Henderson     op->nargs = nargs;
245515fa08f8SRichard Henderson 
2456cb10bc63SRichard Henderson     /* Check for bitfield overflow. */
2457cb10bc63SRichard Henderson     tcg_debug_assert(op->nargs == nargs);
2458cb10bc63SRichard Henderson 
2459cb10bc63SRichard Henderson     s->nb_ops++;
246015fa08f8SRichard Henderson     return op;
246115fa08f8SRichard Henderson }
246215fa08f8SRichard Henderson 
2463d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs)
246415fa08f8SRichard Henderson {
2465d4478943SPhilippe Mathieu-Daudé     TCGOp *op = tcg_op_alloc(opc, nargs);
246615fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
246715fa08f8SRichard Henderson     return op;
246815fa08f8SRichard Henderson }
246915fa08f8SRichard Henderson 
2470d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op,
2471d4478943SPhilippe Mathieu-Daudé                             TCGOpcode opc, unsigned nargs)
24725a18407fSRichard Henderson {
2473d4478943SPhilippe Mathieu-Daudé     TCGOp *new_op = tcg_op_alloc(opc, nargs);
247415fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
24755a18407fSRichard Henderson     return new_op;
24765a18407fSRichard Henderson }
24775a18407fSRichard Henderson 
2478d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op,
2479d4478943SPhilippe Mathieu-Daudé                            TCGOpcode opc, unsigned nargs)
24805a18407fSRichard Henderson {
2481d4478943SPhilippe Mathieu-Daudé     TCGOp *new_op = tcg_op_alloc(opc, nargs);
248215fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
24835a18407fSRichard Henderson     return new_op;
24845a18407fSRichard Henderson }
24855a18407fSRichard Henderson 
2486b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
2487b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s)
2488b4fc67c7SRichard Henderson {
2489b4fc67c7SRichard Henderson     TCGOp *op, *op_next;
2490b4fc67c7SRichard Henderson     bool dead = false;
2491b4fc67c7SRichard Henderson 
2492b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
2493b4fc67c7SRichard Henderson         bool remove = dead;
2494b4fc67c7SRichard Henderson         TCGLabel *label;
2495b4fc67c7SRichard Henderson 
2496b4fc67c7SRichard Henderson         switch (op->opc) {
2497b4fc67c7SRichard Henderson         case INDEX_op_set_label:
2498b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
2499b4fc67c7SRichard Henderson             if (label->refs == 0) {
2500b4fc67c7SRichard Henderson                 /*
2501b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
2502b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
2503b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
2504b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
2505b4fc67c7SRichard Henderson                  * little to be gained by iterating.
2506b4fc67c7SRichard Henderson                  */
2507b4fc67c7SRichard Henderson                 remove = true;
2508b4fc67c7SRichard Henderson             } else {
2509b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
2510b4fc67c7SRichard Henderson                 dead = false;
2511b4fc67c7SRichard Henderson                 remove = false;
2512b4fc67c7SRichard Henderson 
2513b4fc67c7SRichard Henderson                 /*
2514b4fc67c7SRichard Henderson                  * Optimization can fold conditional branches to unconditional.
2515b4fc67c7SRichard Henderson                  * If we find a label with one reference which is preceded by
2516b4fc67c7SRichard Henderson                  * an unconditional branch to it, remove both.  This needed to
2517b4fc67c7SRichard Henderson                  * wait until the dead code in between them was removed.
2518b4fc67c7SRichard Henderson                  */
2519b4fc67c7SRichard Henderson                 if (label->refs == 1) {
2520eae3eb3eSPaolo Bonzini                     TCGOp *op_prev = QTAILQ_PREV(op, link);
2521b4fc67c7SRichard Henderson                     if (op_prev->opc == INDEX_op_br &&
2522b4fc67c7SRichard Henderson                         label == arg_label(op_prev->args[0])) {
2523b4fc67c7SRichard Henderson                         tcg_op_remove(s, op_prev);
2524b4fc67c7SRichard Henderson                         remove = true;
2525b4fc67c7SRichard Henderson                     }
2526b4fc67c7SRichard Henderson                 }
2527b4fc67c7SRichard Henderson             }
2528b4fc67c7SRichard Henderson             break;
2529b4fc67c7SRichard Henderson 
2530b4fc67c7SRichard Henderson         case INDEX_op_br:
2531b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
2532b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
2533b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
2534b4fc67c7SRichard Henderson             dead = true;
2535b4fc67c7SRichard Henderson             break;
2536b4fc67c7SRichard Henderson 
2537b4fc67c7SRichard Henderson         case INDEX_op_call:
2538b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
253990163900SRichard Henderson             if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) {
2540b4fc67c7SRichard Henderson                 dead = true;
2541b4fc67c7SRichard Henderson             }
2542b4fc67c7SRichard Henderson             break;
2543b4fc67c7SRichard Henderson 
2544b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
2545b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
2546b4fc67c7SRichard Henderson             remove = false;
2547b4fc67c7SRichard Henderson             break;
2548b4fc67c7SRichard Henderson 
2549b4fc67c7SRichard Henderson         default:
2550b4fc67c7SRichard Henderson             break;
2551b4fc67c7SRichard Henderson         }
2552b4fc67c7SRichard Henderson 
2553b4fc67c7SRichard Henderson         if (remove) {
2554b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
2555b4fc67c7SRichard Henderson         }
2556b4fc67c7SRichard Henderson     }
2557b4fc67c7SRichard Henderson }
2558b4fc67c7SRichard Henderson 
2559c70fbf0aSRichard Henderson #define TS_DEAD  1
2560c70fbf0aSRichard Henderson #define TS_MEM   2
2561c70fbf0aSRichard Henderson 
25625a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
25635a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
25645a18407fSRichard Henderson 
256525f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
256625f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
256725f49c5fSRichard Henderson {
256825f49c5fSRichard Henderson     return ts->state_ptr;
256925f49c5fSRichard Henderson }
257025f49c5fSRichard Henderson 
257125f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
257225f49c5fSRichard Henderson  * maximal regset for its type.
257325f49c5fSRichard Henderson  */
257425f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
257525f49c5fSRichard Henderson {
257625f49c5fSRichard Henderson     *la_temp_pref(ts)
257725f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
257825f49c5fSRichard Henderson }
257925f49c5fSRichard Henderson 
25809c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
25819c43b68dSAurelien Jarno    should be in memory. */
25822616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
2583c896fe29Sbellard {
2584b83eabeaSRichard Henderson     int i;
2585b83eabeaSRichard Henderson 
2586b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2587b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
258825f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2589b83eabeaSRichard Henderson     }
2590b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2591b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
259225f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2593b83eabeaSRichard Henderson     }
2594c896fe29Sbellard }
2595c896fe29Sbellard 
25969c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
25979c43b68dSAurelien Jarno    and local temps should be in memory. */
25982616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
2599641d5fbeSbellard {
2600b83eabeaSRichard Henderson     int i;
2601641d5fbeSbellard 
2602ee17db83SRichard Henderson     for (i = 0; i < nt; ++i) {
2603ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2604ee17db83SRichard Henderson         int state;
2605ee17db83SRichard Henderson 
2606ee17db83SRichard Henderson         switch (ts->kind) {
2607ee17db83SRichard Henderson         case TEMP_FIXED:
2608ee17db83SRichard Henderson         case TEMP_GLOBAL:
2609ee17db83SRichard Henderson         case TEMP_LOCAL:
2610ee17db83SRichard Henderson             state = TS_DEAD | TS_MEM;
2611ee17db83SRichard Henderson             break;
2612ee17db83SRichard Henderson         case TEMP_NORMAL:
2613c7482438SRichard Henderson         case TEMP_EBB:
2614c0522136SRichard Henderson         case TEMP_CONST:
2615ee17db83SRichard Henderson             state = TS_DEAD;
2616ee17db83SRichard Henderson             break;
2617ee17db83SRichard Henderson         default:
2618ee17db83SRichard Henderson             g_assert_not_reached();
2619c70fbf0aSRichard Henderson         }
2620ee17db83SRichard Henderson         ts->state = state;
2621ee17db83SRichard Henderson         la_reset_pref(ts);
2622641d5fbeSbellard     }
2623641d5fbeSbellard }
2624641d5fbeSbellard 
2625f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
2626f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
2627f65a061cSRichard Henderson {
2628f65a061cSRichard Henderson     int i;
2629f65a061cSRichard Henderson 
2630f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
263125f49c5fSRichard Henderson         int state = s->temps[i].state;
263225f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
263325f49c5fSRichard Henderson         if (state == TS_DEAD) {
263425f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
263525f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
263625f49c5fSRichard Henderson         }
2637f65a061cSRichard Henderson     }
2638f65a061cSRichard Henderson }
2639f65a061cSRichard Henderson 
2640b4cb76e6SRichard Henderson /*
2641c7482438SRichard Henderson  * liveness analysis: conditional branch: all temps are dead unless
2642c7482438SRichard Henderson  * explicitly live-across-conditional-branch, globals and local temps
2643c7482438SRichard Henderson  * should be synced.
2644b4cb76e6SRichard Henderson  */
2645b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
2646b4cb76e6SRichard Henderson {
2647b4cb76e6SRichard Henderson     la_global_sync(s, ng);
2648b4cb76e6SRichard Henderson 
2649b4cb76e6SRichard Henderson     for (int i = ng; i < nt; ++i) {
2650c0522136SRichard Henderson         TCGTemp *ts = &s->temps[i];
2651c0522136SRichard Henderson         int state;
2652c0522136SRichard Henderson 
2653c0522136SRichard Henderson         switch (ts->kind) {
2654c0522136SRichard Henderson         case TEMP_LOCAL:
2655c0522136SRichard Henderson             state = ts->state;
2656c0522136SRichard Henderson             ts->state = state | TS_MEM;
2657b4cb76e6SRichard Henderson             if (state != TS_DEAD) {
2658b4cb76e6SRichard Henderson                 continue;
2659b4cb76e6SRichard Henderson             }
2660c0522136SRichard Henderson             break;
2661c0522136SRichard Henderson         case TEMP_NORMAL:
2662b4cb76e6SRichard Henderson             s->temps[i].state = TS_DEAD;
2663c0522136SRichard Henderson             break;
2664c7482438SRichard Henderson         case TEMP_EBB:
2665c0522136SRichard Henderson         case TEMP_CONST:
2666c0522136SRichard Henderson             continue;
2667c0522136SRichard Henderson         default:
2668c0522136SRichard Henderson             g_assert_not_reached();
2669b4cb76e6SRichard Henderson         }
2670b4cb76e6SRichard Henderson         la_reset_pref(&s->temps[i]);
2671b4cb76e6SRichard Henderson     }
2672b4cb76e6SRichard Henderson }
2673b4cb76e6SRichard Henderson 
2674f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
2675f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
2676f65a061cSRichard Henderson {
2677f65a061cSRichard Henderson     int i;
2678f65a061cSRichard Henderson 
2679f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
2680f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
268125f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
268225f49c5fSRichard Henderson     }
268325f49c5fSRichard Henderson }
268425f49c5fSRichard Henderson 
268525f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
268625f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
268725f49c5fSRichard Henderson {
268825f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
268925f49c5fSRichard Henderson     int i;
269025f49c5fSRichard Henderson 
269125f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
269225f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
269325f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
269425f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
269525f49c5fSRichard Henderson             TCGRegSet set = *pset;
269625f49c5fSRichard Henderson 
269725f49c5fSRichard Henderson             set &= mask;
269825f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
269925f49c5fSRichard Henderson             if (set == 0) {
270025f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
270125f49c5fSRichard Henderson             }
270225f49c5fSRichard Henderson             *pset = set;
270325f49c5fSRichard Henderson         }
2704f65a061cSRichard Henderson     }
2705f65a061cSRichard Henderson }
2706f65a061cSRichard Henderson 
2707a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
2708c896fe29Sbellard    given input arguments is dead. Instructions updating dead
2709c896fe29Sbellard    temporaries are removed. */
2710b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s)
2711c896fe29Sbellard {
2712c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
27132616c808SRichard Henderson     int nb_temps = s->nb_temps;
271415fa08f8SRichard Henderson     TCGOp *op, *op_prev;
271525f49c5fSRichard Henderson     TCGRegSet *prefs;
271625f49c5fSRichard Henderson     int i;
271725f49c5fSRichard Henderson 
271825f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
271925f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
272025f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
272125f49c5fSRichard Henderson     }
2722c896fe29Sbellard 
2723ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
27242616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
2725c896fe29Sbellard 
2726eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
272725f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
2728c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
2729c45cb8bbSRichard Henderson         bool have_opc_new2;
2730a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
273125f49c5fSRichard Henderson         TCGTemp *ts;
2732c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2733c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2734c45cb8bbSRichard Henderson 
2735c45cb8bbSRichard Henderson         switch (opc) {
2736c896fe29Sbellard         case INDEX_op_call:
2737c6e113f5Sbellard             {
273839004a71SRichard Henderson                 const TCGHelperInfo *info = tcg_call_info(op);
273939004a71SRichard Henderson                 int call_flags = tcg_call_flags(op);
2740c6e113f5Sbellard 
2741cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
2742cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
2743c6e113f5Sbellard 
2744c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
274578505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
2746c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
274725f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
274825f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
2749c6e113f5Sbellard                             goto do_not_remove_call;
2750c6e113f5Sbellard                         }
27519c43b68dSAurelien Jarno                     }
2752c45cb8bbSRichard Henderson                     goto do_remove;
2753152c35aaSRichard Henderson                 }
2754c6e113f5Sbellard             do_not_remove_call:
2755c896fe29Sbellard 
275625f49c5fSRichard Henderson                 /* Output args are dead.  */
2757c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
275825f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
275925f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
2760a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
27616b64b624SAurelien Jarno                     }
276225f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
2763a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
27649c43b68dSAurelien Jarno                     }
276525f49c5fSRichard Henderson                     ts->state = TS_DEAD;
276625f49c5fSRichard Henderson                     la_reset_pref(ts);
2767c896fe29Sbellard                 }
2768c896fe29Sbellard 
276931fd884bSRichard Henderson                 /* Not used -- it will be tcg_target_call_oarg_reg().  */
277031fd884bSRichard Henderson                 memset(op->output_pref, 0, sizeof(op->output_pref));
277131fd884bSRichard Henderson 
277278505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
277378505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
2774f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
2775c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
2776f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
2777b9c18f56Saurel32                 }
2778c896fe29Sbellard 
277925f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
2780866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
278125f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
278239004a71SRichard Henderson                     if (ts->state & TS_DEAD) {
2783a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
2784c896fe29Sbellard                     }
2785c896fe29Sbellard                 }
278625f49c5fSRichard Henderson 
278725f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
278825f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
278925f49c5fSRichard Henderson 
279039004a71SRichard Henderson                 /*
279139004a71SRichard Henderson                  * Input arguments are live for preceding opcodes.
279239004a71SRichard Henderson                  *
279339004a71SRichard Henderson                  * For those arguments that die, and will be allocated in
279439004a71SRichard Henderson                  * registers, clear the register set for that arg, to be
279539004a71SRichard Henderson                  * filled in below.  For args that will be on the stack,
279639004a71SRichard Henderson                  * reset to any available reg.  Process arguments in reverse
279739004a71SRichard Henderson                  * order so that if a temp is used more than once, the stack
279839004a71SRichard Henderson                  * reset to max happens before the register reset to 0.
279925f49c5fSRichard Henderson                  */
280039004a71SRichard Henderson                 for (i = nb_iargs - 1; i >= 0; i--) {
280139004a71SRichard Henderson                     const TCGCallArgumentLoc *loc = &info->in[i];
280239004a71SRichard Henderson                     ts = arg_temp(op->args[nb_oargs + i]);
280339004a71SRichard Henderson 
280439004a71SRichard Henderson                     if (ts->state & TS_DEAD) {
280539004a71SRichard Henderson                         switch (loc->kind) {
280639004a71SRichard Henderson                         case TCG_CALL_ARG_NORMAL:
280739004a71SRichard Henderson                         case TCG_CALL_ARG_EXTEND_U:
280839004a71SRichard Henderson                         case TCG_CALL_ARG_EXTEND_S:
280939004a71SRichard Henderson                             if (REG_P(loc)) {
281039004a71SRichard Henderson                                 *la_temp_pref(ts) = 0;
281139004a71SRichard Henderson                                 break;
281239004a71SRichard Henderson                             }
281339004a71SRichard Henderson                             /* fall through */
281439004a71SRichard Henderson                         default:
281539004a71SRichard Henderson                             *la_temp_pref(ts) =
281639004a71SRichard Henderson                                 tcg_target_available_regs[ts->type];
281739004a71SRichard Henderson                             break;
281839004a71SRichard Henderson                         }
281925f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
282025f49c5fSRichard Henderson                     }
282125f49c5fSRichard Henderson                 }
282225f49c5fSRichard Henderson 
282339004a71SRichard Henderson                 /*
282439004a71SRichard Henderson                  * For each input argument, add its input register to prefs.
282539004a71SRichard Henderson                  * If a temp is used once, this produces a single set bit;
282639004a71SRichard Henderson                  * if a temp is used multiple times, this produces a set.
282739004a71SRichard Henderson                  */
282839004a71SRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
282939004a71SRichard Henderson                     const TCGCallArgumentLoc *loc = &info->in[i];
283039004a71SRichard Henderson                     ts = arg_temp(op->args[nb_oargs + i]);
283139004a71SRichard Henderson 
283239004a71SRichard Henderson                     switch (loc->kind) {
283339004a71SRichard Henderson                     case TCG_CALL_ARG_NORMAL:
283439004a71SRichard Henderson                     case TCG_CALL_ARG_EXTEND_U:
283539004a71SRichard Henderson                     case TCG_CALL_ARG_EXTEND_S:
283639004a71SRichard Henderson                         if (REG_P(loc)) {
283725f49c5fSRichard Henderson                             tcg_regset_set_reg(*la_temp_pref(ts),
283839004a71SRichard Henderson                                 tcg_target_call_iarg_regs[loc->arg_slot]);
283939004a71SRichard Henderson                         }
284039004a71SRichard Henderson                         break;
284139004a71SRichard Henderson                     default:
284239004a71SRichard Henderson                         break;
2843c70fbf0aSRichard Henderson                     }
2844c19f47bfSAurelien Jarno                 }
2845c6e113f5Sbellard             }
2846c896fe29Sbellard             break;
2847765b842aSRichard Henderson         case INDEX_op_insn_start:
2848c896fe29Sbellard             break;
28495ff9d6a4Sbellard         case INDEX_op_discard:
28505ff9d6a4Sbellard             /* mark the temporary as dead */
285125f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
285225f49c5fSRichard Henderson             ts->state = TS_DEAD;
285325f49c5fSRichard Henderson             la_reset_pref(ts);
28545ff9d6a4Sbellard             break;
28551305c451SRichard Henderson 
28561305c451SRichard Henderson         case INDEX_op_add2_i32:
2857c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
2858f1fae40cSRichard Henderson             goto do_addsub2;
28591305c451SRichard Henderson         case INDEX_op_sub2_i32:
2860c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
2861f1fae40cSRichard Henderson             goto do_addsub2;
2862f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
2863c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
2864f1fae40cSRichard Henderson             goto do_addsub2;
2865f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
2866c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
2867f1fae40cSRichard Henderson         do_addsub2:
28681305c451SRichard Henderson             nb_iargs = 4;
28691305c451SRichard Henderson             nb_oargs = 2;
28701305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
28711305c451SRichard Henderson                the low part.  The result can be optimized to a simple
28721305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
28731305c451SRichard Henderson                cpu mode is set to 32 bit.  */
2874b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2875b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
28761305c451SRichard Henderson                     goto do_remove;
28771305c451SRichard Henderson                 }
2878c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
2879c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
2880c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2881efee3746SRichard Henderson                 op->args[1] = op->args[2];
2882efee3746SRichard Henderson                 op->args[2] = op->args[4];
28831305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
28841305c451SRichard Henderson                 nb_iargs = 2;
28851305c451SRichard Henderson                 nb_oargs = 1;
28861305c451SRichard Henderson             }
28871305c451SRichard Henderson             goto do_not_remove;
28881305c451SRichard Henderson 
28891414968aSRichard Henderson         case INDEX_op_mulu2_i32:
2890c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2891c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
2892c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
289303271524SRichard Henderson             goto do_mul2;
2894f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
2895c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2896c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
2897c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
2898f1fae40cSRichard Henderson             goto do_mul2;
2899f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
2900c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2901c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
2902c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
290303271524SRichard Henderson             goto do_mul2;
2904f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
2905c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2906c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
2907c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
290803271524SRichard Henderson             goto do_mul2;
2909f1fae40cSRichard Henderson         do_mul2:
29101414968aSRichard Henderson             nb_iargs = 2;
29111414968aSRichard Henderson             nb_oargs = 2;
2912b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2913b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
291403271524SRichard Henderson                     /* Both parts of the operation are dead.  */
29151414968aSRichard Henderson                     goto do_remove;
29161414968aSRichard Henderson                 }
291703271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
2918c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2919efee3746SRichard Henderson                 op->args[1] = op->args[2];
2920efee3746SRichard Henderson                 op->args[2] = op->args[3];
2921b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
292203271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
2923c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
2924efee3746SRichard Henderson                 op->args[0] = op->args[1];
2925efee3746SRichard Henderson                 op->args[1] = op->args[2];
2926efee3746SRichard Henderson                 op->args[2] = op->args[3];
292703271524SRichard Henderson             } else {
292803271524SRichard Henderson                 goto do_not_remove;
292903271524SRichard Henderson             }
293003271524SRichard Henderson             /* Mark the single-word operation live.  */
29311414968aSRichard Henderson             nb_oargs = 1;
29321414968aSRichard Henderson             goto do_not_remove;
29331414968aSRichard Henderson 
2934c896fe29Sbellard         default:
29351305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
2936c896fe29Sbellard             nb_iargs = def->nb_iargs;
2937c896fe29Sbellard             nb_oargs = def->nb_oargs;
2938c896fe29Sbellard 
2939c896fe29Sbellard             /* Test if the operation can be removed because all
29405ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
29415ff9d6a4Sbellard                implies side effects */
29425ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
2943c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
2944b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
2945c896fe29Sbellard                         goto do_not_remove;
2946c896fe29Sbellard                     }
29479c43b68dSAurelien Jarno                 }
2948152c35aaSRichard Henderson                 goto do_remove;
2949152c35aaSRichard Henderson             }
2950152c35aaSRichard Henderson             goto do_not_remove;
2951152c35aaSRichard Henderson 
29521305c451SRichard Henderson         do_remove:
29530c627cdcSRichard Henderson             tcg_op_remove(s, op);
2954152c35aaSRichard Henderson             break;
2955152c35aaSRichard Henderson 
2956c896fe29Sbellard         do_not_remove:
2957c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
295825f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
295925f49c5fSRichard Henderson 
296025f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
296131fd884bSRichard Henderson                 if (i < ARRAY_SIZE(op->output_pref)) {
296225f49c5fSRichard Henderson                     op->output_pref[i] = *la_temp_pref(ts);
296331fd884bSRichard Henderson                 }
296425f49c5fSRichard Henderson 
296525f49c5fSRichard Henderson                 /* Output args are dead.  */
296625f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2967a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
29686b64b624SAurelien Jarno                 }
296925f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
2970a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
29719c43b68dSAurelien Jarno                 }
297225f49c5fSRichard Henderson                 ts->state = TS_DEAD;
297325f49c5fSRichard Henderson                 la_reset_pref(ts);
2974c896fe29Sbellard             }
2975c896fe29Sbellard 
297625f49c5fSRichard Henderson             /* If end of basic block, update.  */
2977ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
2978ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
2979b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_COND_BRANCH) {
2980b4cb76e6SRichard Henderson                 la_bb_sync(s, nb_globals, nb_temps);
2981ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
29822616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
29833d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
2984f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
298525f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
298625f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
298725f49c5fSRichard Henderson                 }
2988c896fe29Sbellard             }
2989c896fe29Sbellard 
299025f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
2991866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
299225f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
299325f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2994a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
2995c896fe29Sbellard                 }
2996c19f47bfSAurelien Jarno             }
299725f49c5fSRichard Henderson 
299825f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
2999c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
300025f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
300125f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
300225f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
300325f49c5fSRichard Henderson                        all regs for the type.  */
300425f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
300525f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
300625f49c5fSRichard Henderson                 }
300725f49c5fSRichard Henderson             }
300825f49c5fSRichard Henderson 
300925f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
301025f49c5fSRichard Henderson             switch (opc) {
301125f49c5fSRichard Henderson             case INDEX_op_mov_i32:
301225f49c5fSRichard Henderson             case INDEX_op_mov_i64:
301325f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
301425f49c5fSRichard Henderson                    have proper constraints.  That said, special case
301525f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
301625f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
301725f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
301825f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
301925f49c5fSRichard Henderson                 }
302025f49c5fSRichard Henderson                 break;
302125f49c5fSRichard Henderson 
302225f49c5fSRichard Henderson             default:
302325f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
302425f49c5fSRichard Henderson                     const TCGArgConstraint *ct = &def->args_ct[i];
302525f49c5fSRichard Henderson                     TCGRegSet set, *pset;
302625f49c5fSRichard Henderson 
302725f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
302825f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
302925f49c5fSRichard Henderson                     set = *pset;
303025f49c5fSRichard Henderson 
30319be0d080SRichard Henderson                     set &= ct->regs;
3032bc2b17e6SRichard Henderson                     if (ct->ialias) {
303331fd884bSRichard Henderson                         set &= output_pref(op, ct->alias_index);
303425f49c5fSRichard Henderson                     }
303525f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
303625f49c5fSRichard Henderson                     if (set == 0) {
30379be0d080SRichard Henderson                         set = ct->regs;
303825f49c5fSRichard Henderson                     }
303925f49c5fSRichard Henderson                     *pset = set;
304025f49c5fSRichard Henderson                 }
304125f49c5fSRichard Henderson                 break;
3042c896fe29Sbellard             }
3043c896fe29Sbellard             break;
3044c896fe29Sbellard         }
3045bee158cbSRichard Henderson         op->life = arg_life;
3046c896fe29Sbellard     }
30471ff0a2c5SEvgeny Voevodin }
3048c896fe29Sbellard 
30495a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
3050b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s)
30515a18407fSRichard Henderson {
30525a18407fSRichard Henderson     int nb_globals = s->nb_globals;
305315fa08f8SRichard Henderson     int nb_temps, i;
30545a18407fSRichard Henderson     bool changes = false;
305515fa08f8SRichard Henderson     TCGOp *op, *op_next;
30565a18407fSRichard Henderson 
30575a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
30585a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
30595a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
30605a18407fSRichard Henderson         if (its->indirect_reg) {
30615a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
30625a18407fSRichard Henderson             dts->type = its->type;
30635a18407fSRichard Henderson             dts->base_type = its->base_type;
3064c7482438SRichard Henderson             dts->kind = TEMP_EBB;
3065b83eabeaSRichard Henderson             its->state_ptr = dts;
3066b83eabeaSRichard Henderson         } else {
3067b83eabeaSRichard Henderson             its->state_ptr = NULL;
30685a18407fSRichard Henderson         }
3069b83eabeaSRichard Henderson         /* All globals begin dead.  */
3070b83eabeaSRichard Henderson         its->state = TS_DEAD;
30715a18407fSRichard Henderson     }
3072b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
3073b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
3074b83eabeaSRichard Henderson         its->state_ptr = NULL;
3075b83eabeaSRichard Henderson         its->state = TS_DEAD;
3076b83eabeaSRichard Henderson     }
30775a18407fSRichard Henderson 
307815fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
30795a18407fSRichard Henderson         TCGOpcode opc = op->opc;
30805a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
30815a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
30825a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
3083b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
30845a18407fSRichard Henderson 
30855a18407fSRichard Henderson         if (opc == INDEX_op_call) {
3086cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
3087cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
308890163900SRichard Henderson             call_flags = tcg_call_flags(op);
30895a18407fSRichard Henderson         } else {
30905a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
30915a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
30925a18407fSRichard Henderson 
30935a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
3094b4cb76e6SRichard Henderson             if (def->flags & TCG_OPF_COND_BRANCH) {
3095b4cb76e6SRichard Henderson                 /* Like reading globals: sync_globals */
3096b4cb76e6SRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
3097b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
30985a18407fSRichard Henderson                 /* Like writing globals: save_globals */
30995a18407fSRichard Henderson                 call_flags = 0;
31005a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
31015a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
31025a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
31035a18407fSRichard Henderson             } else {
31045a18407fSRichard Henderson                 /* No effect on globals.  */
31055a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
31065a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
31075a18407fSRichard Henderson             }
31085a18407fSRichard Henderson         }
31095a18407fSRichard Henderson 
31105a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
31115a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3112b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3113b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
3114b83eabeaSRichard Henderson             if (dir_ts && arg_ts->state == TS_DEAD) {
3115b83eabeaSRichard Henderson                 TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
31165a18407fSRichard Henderson                                   ? INDEX_op_ld_i32
31175a18407fSRichard Henderson                                   : INDEX_op_ld_i64);
3118d4478943SPhilippe Mathieu-Daudé                 TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3);
31195a18407fSRichard Henderson 
3120b83eabeaSRichard Henderson                 lop->args[0] = temp_arg(dir_ts);
3121b83eabeaSRichard Henderson                 lop->args[1] = temp_arg(arg_ts->mem_base);
3122b83eabeaSRichard Henderson                 lop->args[2] = arg_ts->mem_offset;
31235a18407fSRichard Henderson 
31245a18407fSRichard Henderson                 /* Loaded, but synced with memory.  */
3125b83eabeaSRichard Henderson                 arg_ts->state = TS_MEM;
31265a18407fSRichard Henderson             }
31275a18407fSRichard Henderson         }
31285a18407fSRichard Henderson 
31295a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
31305a18407fSRichard Henderson            No action is required except keeping temp_state up to date
31315a18407fSRichard Henderson            so that we reload when needed.  */
31325a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3133b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3134b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
3135b83eabeaSRichard Henderson             if (dir_ts) {
3136b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
31375a18407fSRichard Henderson                 changes = true;
31385a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3139b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
31405a18407fSRichard Henderson                 }
31415a18407fSRichard Henderson             }
31425a18407fSRichard Henderson         }
31435a18407fSRichard Henderson 
31445a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
31455a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
31465a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
31475a18407fSRichard Henderson             /* Nothing to do */
31485a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
31495a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
31505a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
31515a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
3152b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3153b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3154b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
31555a18407fSRichard Henderson             }
31565a18407fSRichard Henderson         } else {
31575a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
31585a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
31595a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
3160b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3161b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3162b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
31635a18407fSRichard Henderson             }
31645a18407fSRichard Henderson         }
31655a18407fSRichard Henderson 
31665a18407fSRichard Henderson         /* Outputs become available.  */
316761f15c48SRichard Henderson         if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) {
316861f15c48SRichard Henderson             arg_ts = arg_temp(op->args[0]);
316961f15c48SRichard Henderson             dir_ts = arg_ts->state_ptr;
317061f15c48SRichard Henderson             if (dir_ts) {
317161f15c48SRichard Henderson                 op->args[0] = temp_arg(dir_ts);
317261f15c48SRichard Henderson                 changes = true;
317361f15c48SRichard Henderson 
317461f15c48SRichard Henderson                 /* The output is now live and modified.  */
317561f15c48SRichard Henderson                 arg_ts->state = 0;
317661f15c48SRichard Henderson 
317761f15c48SRichard Henderson                 if (NEED_SYNC_ARG(0)) {
317861f15c48SRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
317961f15c48SRichard Henderson                                       ? INDEX_op_st_i32
318061f15c48SRichard Henderson                                       : INDEX_op_st_i64);
3181d4478943SPhilippe Mathieu-Daudé                     TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
318261f15c48SRichard Henderson                     TCGTemp *out_ts = dir_ts;
318361f15c48SRichard Henderson 
318461f15c48SRichard Henderson                     if (IS_DEAD_ARG(0)) {
318561f15c48SRichard Henderson                         out_ts = arg_temp(op->args[1]);
318661f15c48SRichard Henderson                         arg_ts->state = TS_DEAD;
318761f15c48SRichard Henderson                         tcg_op_remove(s, op);
318861f15c48SRichard Henderson                     } else {
318961f15c48SRichard Henderson                         arg_ts->state = TS_MEM;
319061f15c48SRichard Henderson                     }
319161f15c48SRichard Henderson 
319261f15c48SRichard Henderson                     sop->args[0] = temp_arg(out_ts);
319361f15c48SRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
319461f15c48SRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
319561f15c48SRichard Henderson                 } else {
319661f15c48SRichard Henderson                     tcg_debug_assert(!IS_DEAD_ARG(0));
319761f15c48SRichard Henderson                 }
319861f15c48SRichard Henderson             }
319961f15c48SRichard Henderson         } else {
32005a18407fSRichard Henderson             for (i = 0; i < nb_oargs; i++) {
3201b83eabeaSRichard Henderson                 arg_ts = arg_temp(op->args[i]);
3202b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3203b83eabeaSRichard Henderson                 if (!dir_ts) {
32045a18407fSRichard Henderson                     continue;
32055a18407fSRichard Henderson                 }
3206b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
32075a18407fSRichard Henderson                 changes = true;
32085a18407fSRichard Henderson 
32095a18407fSRichard Henderson                 /* The output is now live and modified.  */
3210b83eabeaSRichard Henderson                 arg_ts->state = 0;
32115a18407fSRichard Henderson 
32125a18407fSRichard Henderson                 /* Sync outputs upon their last write.  */
32135a18407fSRichard Henderson                 if (NEED_SYNC_ARG(i)) {
3214b83eabeaSRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
32155a18407fSRichard Henderson                                       ? INDEX_op_st_i32
32165a18407fSRichard Henderson                                       : INDEX_op_st_i64);
3217d4478943SPhilippe Mathieu-Daudé                     TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
32185a18407fSRichard Henderson 
3219b83eabeaSRichard Henderson                     sop->args[0] = temp_arg(dir_ts);
3220b83eabeaSRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
3221b83eabeaSRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
32225a18407fSRichard Henderson 
3223b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
32245a18407fSRichard Henderson                 }
32255a18407fSRichard Henderson                 /* Drop outputs that are dead.  */
32265a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3227b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
32285a18407fSRichard Henderson                 }
32295a18407fSRichard Henderson             }
32305a18407fSRichard Henderson         }
323161f15c48SRichard Henderson     }
32325a18407fSRichard Henderson 
32335a18407fSRichard Henderson     return changes;
32345a18407fSRichard Henderson }
32355a18407fSRichard Henderson 
32362272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
3237c896fe29Sbellard {
323831c96417SRichard Henderson     int size = tcg_type_size(ts->type);
323931c96417SRichard Henderson     int align;
324031c96417SRichard Henderson     intptr_t off;
3241c1c09194SRichard Henderson 
3242c1c09194SRichard Henderson     switch (ts->type) {
3243c1c09194SRichard Henderson     case TCG_TYPE_I32:
324431c96417SRichard Henderson         align = 4;
3245c1c09194SRichard Henderson         break;
3246c1c09194SRichard Henderson     case TCG_TYPE_I64:
3247c1c09194SRichard Henderson     case TCG_TYPE_V64:
324831c96417SRichard Henderson         align = 8;
3249c1c09194SRichard Henderson         break;
3250c1c09194SRichard Henderson     case TCG_TYPE_V128:
3251c1c09194SRichard Henderson     case TCG_TYPE_V256:
3252c1c09194SRichard Henderson         /* Note that we do not require aligned storage for V256. */
325331c96417SRichard Henderson         align = 16;
3254c1c09194SRichard Henderson         break;
3255c1c09194SRichard Henderson     default:
3256c1c09194SRichard Henderson         g_assert_not_reached();
3257b591dc59SBlue Swirl     }
3258c1c09194SRichard Henderson 
3259b9537d59SRichard Henderson     /*
3260b9537d59SRichard Henderson      * Assume the stack is sufficiently aligned.
3261b9537d59SRichard Henderson      * This affects e.g. ARM NEON, where we have 8 byte stack alignment
3262b9537d59SRichard Henderson      * and do not require 16 byte vector alignment.  This seems slightly
3263b9537d59SRichard Henderson      * easier than fully parameterizing the above switch statement.
3264b9537d59SRichard Henderson      */
3265b9537d59SRichard Henderson     align = MIN(TCG_TARGET_STACK_ALIGN, align);
3266c1c09194SRichard Henderson     off = ROUND_UP(s->current_frame_offset, align);
3267732d5897SRichard Henderson 
3268732d5897SRichard Henderson     /* If we've exhausted the stack frame, restart with a smaller TB. */
3269732d5897SRichard Henderson     if (off + size > s->frame_end) {
3270732d5897SRichard Henderson         tcg_raise_tb_overflow(s);
3271732d5897SRichard Henderson     }
3272c1c09194SRichard Henderson     s->current_frame_offset = off + size;
3273c1c09194SRichard Henderson 
3274c1c09194SRichard Henderson     ts->mem_offset = off;
32759defd1bdSRichard Henderson #if defined(__sparc__)
32769defd1bdSRichard Henderson     ts->mem_offset += TCG_TARGET_STACK_BIAS;
32779defd1bdSRichard Henderson #endif
3278b3a62939SRichard Henderson     ts->mem_base = s->frame_temp;
3279c896fe29Sbellard     ts->mem_allocated = 1;
3280c896fe29Sbellard }
3281c896fe29Sbellard 
3282098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */
3283098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg)
3284098859f1SRichard Henderson {
3285098859f1SRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
3286098859f1SRichard Henderson         TCGReg old = ts->reg;
3287098859f1SRichard Henderson         tcg_debug_assert(s->reg_to_temp[old] == ts);
3288098859f1SRichard Henderson         if (old == reg) {
3289098859f1SRichard Henderson             return;
3290098859f1SRichard Henderson         }
3291098859f1SRichard Henderson         s->reg_to_temp[old] = NULL;
3292098859f1SRichard Henderson     }
3293098859f1SRichard Henderson     tcg_debug_assert(s->reg_to_temp[reg] == NULL);
3294098859f1SRichard Henderson     s->reg_to_temp[reg] = ts;
3295098859f1SRichard Henderson     ts->val_type = TEMP_VAL_REG;
3296098859f1SRichard Henderson     ts->reg = reg;
3297098859f1SRichard Henderson }
3298098859f1SRichard Henderson 
3299098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */
3300098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type)
3301098859f1SRichard Henderson {
3302098859f1SRichard Henderson     tcg_debug_assert(type != TEMP_VAL_REG);
3303098859f1SRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
3304098859f1SRichard Henderson         TCGReg reg = ts->reg;
3305098859f1SRichard Henderson         tcg_debug_assert(s->reg_to_temp[reg] == ts);
3306098859f1SRichard Henderson         s->reg_to_temp[reg] = NULL;
3307098859f1SRichard Henderson     }
3308098859f1SRichard Henderson     ts->val_type = type;
3309098859f1SRichard Henderson }
3310098859f1SRichard Henderson 
3311b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
3312b3915dbbSRichard Henderson 
331359d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
331459d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
331559d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
3316c896fe29Sbellard {
3317c0522136SRichard Henderson     TCGTempVal new_type;
3318c0522136SRichard Henderson 
3319c0522136SRichard Henderson     switch (ts->kind) {
3320c0522136SRichard Henderson     case TEMP_FIXED:
332159d7c14eSRichard Henderson         return;
3322c0522136SRichard Henderson     case TEMP_GLOBAL:
3323c0522136SRichard Henderson     case TEMP_LOCAL:
3324c0522136SRichard Henderson         new_type = TEMP_VAL_MEM;
3325c0522136SRichard Henderson         break;
3326c0522136SRichard Henderson     case TEMP_NORMAL:
3327c7482438SRichard Henderson     case TEMP_EBB:
3328c0522136SRichard Henderson         new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD;
3329c0522136SRichard Henderson         break;
3330c0522136SRichard Henderson     case TEMP_CONST:
3331c0522136SRichard Henderson         new_type = TEMP_VAL_CONST;
3332c0522136SRichard Henderson         break;
3333c0522136SRichard Henderson     default:
3334c0522136SRichard Henderson         g_assert_not_reached();
333559d7c14eSRichard Henderson     }
3336098859f1SRichard Henderson     set_temp_val_nonreg(s, ts, new_type);
333759d7c14eSRichard Henderson }
3338c896fe29Sbellard 
333959d7c14eSRichard Henderson /* Mark a temporary as dead.  */
334059d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
334159d7c14eSRichard Henderson {
334259d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
334359d7c14eSRichard Henderson }
334459d7c14eSRichard Henderson 
334559d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
334659d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
334759d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
334859d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
334998b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
335098b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
335159d7c14eSRichard Henderson {
3352c0522136SRichard Henderson     if (!temp_readonly(ts) && !ts->mem_coherent) {
33537f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
33542272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
335559d7c14eSRichard Henderson         }
335659d7c14eSRichard Henderson         switch (ts->val_type) {
335759d7c14eSRichard Henderson         case TEMP_VAL_CONST:
335859d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
335959d7c14eSRichard Henderson                require it later in a register, so attempt to store the
336059d7c14eSRichard Henderson                constant to memory directly.  */
336159d7c14eSRichard Henderson             if (free_or_dead
336259d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
336359d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
336459d7c14eSRichard Henderson                 break;
336559d7c14eSRichard Henderson             }
336659d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
336798b4e186SRichard Henderson                       allocated_regs, preferred_regs);
336859d7c14eSRichard Henderson             /* fallthrough */
336959d7c14eSRichard Henderson 
337059d7c14eSRichard Henderson         case TEMP_VAL_REG:
337159d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
337259d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
337359d7c14eSRichard Henderson             break;
337459d7c14eSRichard Henderson 
337559d7c14eSRichard Henderson         case TEMP_VAL_MEM:
337659d7c14eSRichard Henderson             break;
337759d7c14eSRichard Henderson 
337859d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
337959d7c14eSRichard Henderson         default:
338059d7c14eSRichard Henderson             tcg_abort();
3381c896fe29Sbellard         }
33827f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
33837f6ceedfSAurelien Jarno     }
338459d7c14eSRichard Henderson     if (free_or_dead) {
338559d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
338659d7c14eSRichard Henderson     }
338759d7c14eSRichard Henderson }
33887f6ceedfSAurelien Jarno 
33897f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
3390b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
33917f6ceedfSAurelien Jarno {
3392f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
3393f8b2f202SRichard Henderson     if (ts != NULL) {
339498b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
3395c896fe29Sbellard     }
3396c896fe29Sbellard }
3397c896fe29Sbellard 
3398b016486eSRichard Henderson /**
3399b016486eSRichard Henderson  * tcg_reg_alloc:
3400b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
3401b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
3402b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
3403b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
3404b016486eSRichard Henderson  *
3405b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
3406b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
3407b016486eSRichard Henderson  */
3408b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
3409b016486eSRichard Henderson                             TCGRegSet allocated_regs,
3410b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
3411c896fe29Sbellard {
3412b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
3413b016486eSRichard Henderson     TCGRegSet reg_ct[2];
341491478cefSRichard Henderson     const int *order;
3415c896fe29Sbellard 
3416b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
3417b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
3418b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
3419b016486eSRichard Henderson 
3420b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
3421b016486eSRichard Henderson        or if the preference made no difference.  */
3422b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
3423b016486eSRichard Henderson 
342491478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
3425c896fe29Sbellard 
3426b016486eSRichard Henderson     /* Try free registers, preferences first.  */
3427b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3428b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3429b016486eSRichard Henderson 
3430b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3431b016486eSRichard Henderson             /* One register in the set.  */
3432b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3433b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
3434c896fe29Sbellard                 return reg;
3435c896fe29Sbellard             }
3436b016486eSRichard Henderson         } else {
343791478cefSRichard Henderson             for (i = 0; i < n; i++) {
3438b016486eSRichard Henderson                 TCGReg reg = order[i];
3439b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
3440b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
3441b016486eSRichard Henderson                     return reg;
3442b016486eSRichard Henderson                 }
3443b016486eSRichard Henderson             }
3444b016486eSRichard Henderson         }
3445b016486eSRichard Henderson     }
3446b016486eSRichard Henderson 
3447b016486eSRichard Henderson     /* We must spill something.  */
3448b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3449b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3450b016486eSRichard Henderson 
3451b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3452b016486eSRichard Henderson             /* One register in the set.  */
3453b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3454b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
3455c896fe29Sbellard             return reg;
3456b016486eSRichard Henderson         } else {
3457b016486eSRichard Henderson             for (i = 0; i < n; i++) {
3458b016486eSRichard Henderson                 TCGReg reg = order[i];
3459b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
3460b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
3461b016486eSRichard Henderson                     return reg;
3462b016486eSRichard Henderson                 }
3463b016486eSRichard Henderson             }
3464c896fe29Sbellard         }
3465c896fe29Sbellard     }
3466c896fe29Sbellard 
3467c896fe29Sbellard     tcg_abort();
3468c896fe29Sbellard }
3469c896fe29Sbellard 
347029f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs,
347129f5e925SRichard Henderson                                  TCGRegSet allocated_regs,
347229f5e925SRichard Henderson                                  TCGRegSet preferred_regs, bool rev)
347329f5e925SRichard Henderson {
347429f5e925SRichard Henderson     int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
347529f5e925SRichard Henderson     TCGRegSet reg_ct[2];
347629f5e925SRichard Henderson     const int *order;
347729f5e925SRichard Henderson 
347829f5e925SRichard Henderson     /* Ensure that if I is not in allocated_regs, I+1 is not either. */
347929f5e925SRichard Henderson     reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1));
348029f5e925SRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
348129f5e925SRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
348229f5e925SRichard Henderson 
348329f5e925SRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
348429f5e925SRichard Henderson 
348529f5e925SRichard Henderson     /*
348629f5e925SRichard Henderson      * Skip the preferred_regs option if it cannot be satisfied,
348729f5e925SRichard Henderson      * or if the preference made no difference.
348829f5e925SRichard Henderson      */
348929f5e925SRichard Henderson     k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
349029f5e925SRichard Henderson 
349129f5e925SRichard Henderson     /*
349229f5e925SRichard Henderson      * Minimize the number of flushes by looking for 2 free registers first,
349329f5e925SRichard Henderson      * then a single flush, then two flushes.
349429f5e925SRichard Henderson      */
349529f5e925SRichard Henderson     for (fmin = 2; fmin >= 0; fmin--) {
349629f5e925SRichard Henderson         for (j = k; j < 2; j++) {
349729f5e925SRichard Henderson             TCGRegSet set = reg_ct[j];
349829f5e925SRichard Henderson 
349929f5e925SRichard Henderson             for (i = 0; i < n; i++) {
350029f5e925SRichard Henderson                 TCGReg reg = order[i];
350129f5e925SRichard Henderson 
350229f5e925SRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
350329f5e925SRichard Henderson                     int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1];
350429f5e925SRichard Henderson                     if (f >= fmin) {
350529f5e925SRichard Henderson                         tcg_reg_free(s, reg, allocated_regs);
350629f5e925SRichard Henderson                         tcg_reg_free(s, reg + 1, allocated_regs);
350729f5e925SRichard Henderson                         return reg;
350829f5e925SRichard Henderson                     }
350929f5e925SRichard Henderson                 }
351029f5e925SRichard Henderson             }
351129f5e925SRichard Henderson         }
351229f5e925SRichard Henderson     }
351329f5e925SRichard Henderson     tcg_abort();
351429f5e925SRichard Henderson }
351529f5e925SRichard Henderson 
351640ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
351740ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
351840ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
3519b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
352040ae5c62SRichard Henderson {
352140ae5c62SRichard Henderson     TCGReg reg;
352240ae5c62SRichard Henderson 
352340ae5c62SRichard Henderson     switch (ts->val_type) {
352440ae5c62SRichard Henderson     case TEMP_VAL_REG:
352540ae5c62SRichard Henderson         return;
352640ae5c62SRichard Henderson     case TEMP_VAL_CONST:
3527b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3528b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
35290a6a8bc8SRichard Henderson         if (ts->type <= TCG_TYPE_I64) {
353040ae5c62SRichard Henderson             tcg_out_movi(s, ts->type, reg, ts->val);
35310a6a8bc8SRichard Henderson         } else {
35324e186175SRichard Henderson             uint64_t val = ts->val;
35334e186175SRichard Henderson             MemOp vece = MO_64;
35344e186175SRichard Henderson 
35354e186175SRichard Henderson             /*
35364e186175SRichard Henderson              * Find the minimal vector element that matches the constant.
35374e186175SRichard Henderson              * The targets will, in general, have to do this search anyway,
35384e186175SRichard Henderson              * do this generically.
35394e186175SRichard Henderson              */
35404e186175SRichard Henderson             if (val == dup_const(MO_8, val)) {
35414e186175SRichard Henderson                 vece = MO_8;
35424e186175SRichard Henderson             } else if (val == dup_const(MO_16, val)) {
35434e186175SRichard Henderson                 vece = MO_16;
35440b4286ddSRichard Henderson             } else if (val == dup_const(MO_32, val)) {
35454e186175SRichard Henderson                 vece = MO_32;
35464e186175SRichard Henderson             }
35474e186175SRichard Henderson 
35484e186175SRichard Henderson             tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val);
35490a6a8bc8SRichard Henderson         }
355040ae5c62SRichard Henderson         ts->mem_coherent = 0;
355140ae5c62SRichard Henderson         break;
355240ae5c62SRichard Henderson     case TEMP_VAL_MEM:
3553b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3554b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
355540ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
355640ae5c62SRichard Henderson         ts->mem_coherent = 1;
355740ae5c62SRichard Henderson         break;
355840ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
355940ae5c62SRichard Henderson     default:
356040ae5c62SRichard Henderson         tcg_abort();
356140ae5c62SRichard Henderson     }
3562098859f1SRichard Henderson     set_temp_val_reg(s, ts, reg);
356340ae5c62SRichard Henderson }
356440ae5c62SRichard Henderson 
356559d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
3566e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
356759d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
35681ad80729SAurelien Jarno {
35692c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
3570eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
3571e01fa97dSRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts));
35721ad80729SAurelien Jarno }
35731ad80729SAurelien Jarno 
35749814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
3575641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
3576641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
3577641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
3578641d5fbeSbellard {
3579ac3b8891SRichard Henderson     int i, n;
3580641d5fbeSbellard 
3581ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
3582b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
3583641d5fbeSbellard     }
3584e5097dc8Sbellard }
3585e5097dc8Sbellard 
35863d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
35873d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
35883d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
35893d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
35903d5c5f87SAurelien Jarno {
3591ac3b8891SRichard Henderson     int i, n;
35923d5c5f87SAurelien Jarno 
3593ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
359412b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
359512b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
3596ee17db83SRichard Henderson                          || ts->kind == TEMP_FIXED
359712b9b11aSRichard Henderson                          || ts->mem_coherent);
35983d5c5f87SAurelien Jarno     }
35993d5c5f87SAurelien Jarno }
36003d5c5f87SAurelien Jarno 
3601e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
3602e8996ee0Sbellard    all globals are stored at their canonical location. */
3603e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
3604e5097dc8Sbellard {
3605e5097dc8Sbellard     int i;
3606e5097dc8Sbellard 
3607c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
3608b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
3609c0522136SRichard Henderson 
3610c0522136SRichard Henderson         switch (ts->kind) {
3611c0522136SRichard Henderson         case TEMP_LOCAL:
3612b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
3613c0522136SRichard Henderson             break;
3614c0522136SRichard Henderson         case TEMP_NORMAL:
3615c7482438SRichard Henderson         case TEMP_EBB:
36162c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
3617eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
3618eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3619c0522136SRichard Henderson             break;
3620c0522136SRichard Henderson         case TEMP_CONST:
3621c0522136SRichard Henderson             /* Similarly, we should have freed any allocated register. */
3622c0522136SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_CONST);
3623c0522136SRichard Henderson             break;
3624c0522136SRichard Henderson         default:
3625c0522136SRichard Henderson             g_assert_not_reached();
3626c896fe29Sbellard         }
3627641d5fbeSbellard     }
3628e8996ee0Sbellard 
3629e8996ee0Sbellard     save_globals(s, allocated_regs);
3630c896fe29Sbellard }
3631c896fe29Sbellard 
3632bab1671fSRichard Henderson /*
3633c7482438SRichard Henderson  * At a conditional branch, we assume all temporaries are dead unless
3634c7482438SRichard Henderson  * explicitly live-across-conditional-branch; all globals and local
3635c7482438SRichard Henderson  * temps are synced to their location.
3636b4cb76e6SRichard Henderson  */
3637b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
3638b4cb76e6SRichard Henderson {
3639b4cb76e6SRichard Henderson     sync_globals(s, allocated_regs);
3640b4cb76e6SRichard Henderson 
3641b4cb76e6SRichard Henderson     for (int i = s->nb_globals; i < s->nb_temps; i++) {
3642b4cb76e6SRichard Henderson         TCGTemp *ts = &s->temps[i];
3643b4cb76e6SRichard Henderson         /*
3644b4cb76e6SRichard Henderson          * The liveness analysis already ensures that temps are dead.
3645b4cb76e6SRichard Henderson          * Keep tcg_debug_asserts for safety.
3646b4cb76e6SRichard Henderson          */
3647c0522136SRichard Henderson         switch (ts->kind) {
3648c0522136SRichard Henderson         case TEMP_LOCAL:
3649b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
3650c0522136SRichard Henderson             break;
3651c0522136SRichard Henderson         case TEMP_NORMAL:
3652b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3653c0522136SRichard Henderson             break;
3654c7482438SRichard Henderson         case TEMP_EBB:
3655c0522136SRichard Henderson         case TEMP_CONST:
3656c0522136SRichard Henderson             break;
3657c0522136SRichard Henderson         default:
3658c0522136SRichard Henderson             g_assert_not_reached();
3659b4cb76e6SRichard Henderson         }
3660b4cb76e6SRichard Henderson     }
3661b4cb76e6SRichard Henderson }
3662b4cb76e6SRichard Henderson 
3663b4cb76e6SRichard Henderson /*
3664c58f4c97SRichard Henderson  * Specialized code generation for INDEX_op_mov_* with a constant.
3665bab1671fSRichard Henderson  */
36660fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
3667ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
3668ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
3669e8996ee0Sbellard {
3670d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3671e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
367259d7c14eSRichard Henderson 
367359d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
3674098859f1SRichard Henderson     set_temp_val_nonreg(s, ots, TEMP_VAL_CONST);
3675e8996ee0Sbellard     ots->val = val;
367659d7c14eSRichard Henderson     ots->mem_coherent = 0;
3677ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
3678ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
367959d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
3680f8bf00f1SRichard Henderson         temp_dead(s, ots);
36814c4e1ab2SAurelien Jarno     }
3682e8996ee0Sbellard }
3683e8996ee0Sbellard 
3684bab1671fSRichard Henderson /*
3685bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
3686bab1671fSRichard Henderson  */
3687dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
3688c896fe29Sbellard {
3689dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
369069e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
3691c896fe29Sbellard     TCGTemp *ts, *ots;
3692450445d5SRichard Henderson     TCGType otype, itype;
3693098859f1SRichard Henderson     TCGReg oreg, ireg;
3694c896fe29Sbellard 
3695d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
369631fd884bSRichard Henderson     preferred_regs = output_pref(op, 0);
369743439139SRichard Henderson     ots = arg_temp(op->args[0]);
369843439139SRichard Henderson     ts = arg_temp(op->args[1]);
3699450445d5SRichard Henderson 
3700d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3701e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
3702d63e3b6eSRichard Henderson 
3703450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
3704450445d5SRichard Henderson     otype = ots->type;
3705450445d5SRichard Henderson     itype = ts->type;
3706c896fe29Sbellard 
37070fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
37080fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
37090fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
37100fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
37110fe4fca4SPaolo Bonzini             temp_dead(s, ts);
37120fe4fca4SPaolo Bonzini         }
371369e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
37140fe4fca4SPaolo Bonzini         return;
37150fe4fca4SPaolo Bonzini     }
37160fe4fca4SPaolo Bonzini 
37170fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
37180fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
37190fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
37200fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
37210fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
372269e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
372369e3706dSRichard Henderson                   allocated_regs, preferred_regs);
3724c29c1d7eSAurelien Jarno     }
37250fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
3726098859f1SRichard Henderson     ireg = ts->reg;
3727098859f1SRichard Henderson 
3728d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
3729c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
3730c29c1d7eSAurelien Jarno            liveness analysis disabled). */
3731eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
3732c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
37332272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
3734c29c1d7eSAurelien Jarno         }
3735098859f1SRichard Henderson         tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset);
3736c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
3737f8bf00f1SRichard Henderson             temp_dead(s, ts);
3738c29c1d7eSAurelien Jarno         }
3739f8bf00f1SRichard Henderson         temp_dead(s, ots);
3740098859f1SRichard Henderson         return;
3741098859f1SRichard Henderson     }
3742098859f1SRichard Henderson 
3743ee17db83SRichard Henderson     if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) {
3744098859f1SRichard Henderson         /*
3745098859f1SRichard Henderson          * The mov can be suppressed.  Kill input first, so that it
3746098859f1SRichard Henderson          * is unlinked from reg_to_temp, then set the output to the
3747098859f1SRichard Henderson          * reg that we saved from the input.
3748098859f1SRichard Henderson          */
3749f8bf00f1SRichard Henderson         temp_dead(s, ts);
3750098859f1SRichard Henderson         oreg = ireg;
3751c29c1d7eSAurelien Jarno     } else {
3752098859f1SRichard Henderson         if (ots->val_type == TEMP_VAL_REG) {
3753098859f1SRichard Henderson             oreg = ots->reg;
3754098859f1SRichard Henderson         } else {
3755098859f1SRichard Henderson             /* Make sure to not spill the input register during allocation. */
3756098859f1SRichard Henderson             oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
3757098859f1SRichard Henderson                                  allocated_regs | ((TCGRegSet)1 << ireg),
3758098859f1SRichard Henderson                                  preferred_regs, ots->indirect_base);
3759c29c1d7eSAurelien Jarno         }
3760098859f1SRichard Henderson         if (!tcg_out_mov(s, otype, oreg, ireg)) {
3761240c08d0SRichard Henderson             /*
3762240c08d0SRichard Henderson              * Cross register class move not supported.
3763240c08d0SRichard Henderson              * Store the source register into the destination slot
3764240c08d0SRichard Henderson              * and leave the destination temp as TEMP_VAL_MEM.
3765240c08d0SRichard Henderson              */
3766e01fa97dSRichard Henderson             assert(!temp_readonly(ots));
3767240c08d0SRichard Henderson             if (!ts->mem_allocated) {
3768240c08d0SRichard Henderson                 temp_allocate_frame(s, ots);
3769240c08d0SRichard Henderson             }
3770098859f1SRichard Henderson             tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset);
3771098859f1SRichard Henderson             set_temp_val_nonreg(s, ts, TEMP_VAL_MEM);
3772240c08d0SRichard Henderson             ots->mem_coherent = 1;
3773240c08d0SRichard Henderson             return;
377478113e83SRichard Henderson         }
3775c29c1d7eSAurelien Jarno     }
3776098859f1SRichard Henderson     set_temp_val_reg(s, ots, oreg);
3777c896fe29Sbellard     ots->mem_coherent = 0;
3778098859f1SRichard Henderson 
3779ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
378098b4e186SRichard Henderson         temp_sync(s, ots, allocated_regs, 0, 0);
3781c29c1d7eSAurelien Jarno     }
3782ec7a869dSAurelien Jarno }
3783c896fe29Sbellard 
3784bab1671fSRichard Henderson /*
3785bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
3786bab1671fSRichard Henderson  */
3787bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
3788bab1671fSRichard Henderson {
3789bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
3790bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
3791bab1671fSRichard Henderson     TCGTemp *its, *ots;
3792bab1671fSRichard Henderson     TCGType itype, vtype;
3793bab1671fSRichard Henderson     unsigned vece;
379431c96417SRichard Henderson     int lowpart_ofs;
3795bab1671fSRichard Henderson     bool ok;
3796bab1671fSRichard Henderson 
3797bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
3798bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
3799bab1671fSRichard Henderson 
3800bab1671fSRichard Henderson     /* ENV should not be modified.  */
3801e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
3802bab1671fSRichard Henderson 
3803bab1671fSRichard Henderson     itype = its->type;
3804bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
3805bab1671fSRichard Henderson     vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
3806bab1671fSRichard Henderson 
3807bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
3808bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
3809bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
3810bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
3811bab1671fSRichard Henderson             temp_dead(s, its);
3812bab1671fSRichard Henderson         }
381331fd884bSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0));
3814bab1671fSRichard Henderson         return;
3815bab1671fSRichard Henderson     }
3816bab1671fSRichard Henderson 
38179be0d080SRichard Henderson     dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
38189be0d080SRichard Henderson     dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs;
3819bab1671fSRichard Henderson 
3820bab1671fSRichard Henderson     /* Allocate the output register now.  */
3821bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
3822bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
3823098859f1SRichard Henderson         TCGReg oreg;
3824bab1671fSRichard Henderson 
3825bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
3826bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
3827bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
3828bab1671fSRichard Henderson         }
3829098859f1SRichard Henderson         oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
383031fd884bSRichard Henderson                              output_pref(op, 0), ots->indirect_base);
3831098859f1SRichard Henderson         set_temp_val_reg(s, ots, oreg);
3832bab1671fSRichard Henderson     }
3833bab1671fSRichard Henderson 
3834bab1671fSRichard Henderson     switch (its->val_type) {
3835bab1671fSRichard Henderson     case TEMP_VAL_REG:
3836bab1671fSRichard Henderson         /*
3837bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
3838bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
3839bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
3840bab1671fSRichard Henderson          */
3841bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
3842bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
3843bab1671fSRichard Henderson                 goto done;
3844bab1671fSRichard Henderson             }
3845bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
3846bab1671fSRichard Henderson         }
3847bab1671fSRichard Henderson         if (!its->mem_coherent) {
3848bab1671fSRichard Henderson             /*
3849bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
3850bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
3851bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
3852bab1671fSRichard Henderson              */
3853bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
3854bab1671fSRichard Henderson                 break;
3855bab1671fSRichard Henderson             }
3856bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
3857bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
3858bab1671fSRichard Henderson         }
3859bab1671fSRichard Henderson         /* fall through */
3860bab1671fSRichard Henderson 
3861bab1671fSRichard Henderson     case TEMP_VAL_MEM:
386231c96417SRichard Henderson         lowpart_ofs = 0;
386331c96417SRichard Henderson         if (HOST_BIG_ENDIAN) {
386431c96417SRichard Henderson             lowpart_ofs = tcg_type_size(itype) - (1 << vece);
386531c96417SRichard Henderson         }
3866d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
386731c96417SRichard Henderson                              its->mem_offset + lowpart_ofs)) {
3868d6ecb4a9SRichard Henderson             goto done;
3869d6ecb4a9SRichard Henderson         }
3870098859f1SRichard Henderson         /* Load the input into the destination vector register. */
3871bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
3872bab1671fSRichard Henderson         break;
3873bab1671fSRichard Henderson 
3874bab1671fSRichard Henderson     default:
3875bab1671fSRichard Henderson         g_assert_not_reached();
3876bab1671fSRichard Henderson     }
3877bab1671fSRichard Henderson 
3878bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
3879bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
3880bab1671fSRichard Henderson     tcg_debug_assert(ok);
3881bab1671fSRichard Henderson 
3882bab1671fSRichard Henderson  done:
388336f5539cSRichard Henderson     ots->mem_coherent = 0;
3884bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
3885bab1671fSRichard Henderson         temp_dead(s, its);
3886bab1671fSRichard Henderson     }
3887bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
3888bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
3889bab1671fSRichard Henderson     }
3890bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
3891bab1671fSRichard Henderson         temp_dead(s, ots);
3892bab1671fSRichard Henderson     }
3893bab1671fSRichard Henderson }
3894bab1671fSRichard Henderson 
3895dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
3896c896fe29Sbellard {
3897dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3898dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
389982790a87SRichard Henderson     TCGRegSet i_allocated_regs;
390082790a87SRichard Henderson     TCGRegSet o_allocated_regs;
3901b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
3902b6638662SRichard Henderson     TCGReg reg;
3903c896fe29Sbellard     TCGArg arg;
3904c896fe29Sbellard     const TCGArgConstraint *arg_ct;
3905c896fe29Sbellard     TCGTemp *ts;
3906c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
3907c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
3908c896fe29Sbellard 
3909c896fe29Sbellard     nb_oargs = def->nb_oargs;
3910c896fe29Sbellard     nb_iargs = def->nb_iargs;
3911c896fe29Sbellard 
3912c896fe29Sbellard     /* copy constants */
3913c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
3914dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
3915c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
3916c896fe29Sbellard 
3917d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
3918d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
391982790a87SRichard Henderson 
3920c896fe29Sbellard     /* satisfy input constraints */
3921c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
392229f5e925SRichard Henderson         TCGRegSet i_preferred_regs, i_required_regs;
392329f5e925SRichard Henderson         bool allocate_new_reg, copyto_new_reg;
392429f5e925SRichard Henderson         TCGTemp *ts2;
392529f5e925SRichard Henderson         int i1, i2;
3926d62816f2SRichard Henderson 
392766792f90SRichard Henderson         i = def->args_ct[nb_oargs + k].sort_index;
3928dd186292SRichard Henderson         arg = op->args[i];
3929c896fe29Sbellard         arg_ct = &def->args_ct[i];
393043439139SRichard Henderson         ts = arg_temp(arg);
393140ae5c62SRichard Henderson 
393240ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
3933a4fbbd77SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct->ct)) {
3934c896fe29Sbellard             /* constant is OK for instruction */
3935c896fe29Sbellard             const_args[i] = 1;
3936c896fe29Sbellard             new_args[i] = ts->val;
3937d62816f2SRichard Henderson             continue;
3938c896fe29Sbellard         }
393940ae5c62SRichard Henderson 
39401c1824dcSRichard Henderson         reg = ts->reg;
39411c1824dcSRichard Henderson         i_preferred_regs = 0;
394229f5e925SRichard Henderson         i_required_regs = arg_ct->regs;
39431c1824dcSRichard Henderson         allocate_new_reg = false;
394429f5e925SRichard Henderson         copyto_new_reg = false;
39451c1824dcSRichard Henderson 
394629f5e925SRichard Henderson         switch (arg_ct->pair) {
394729f5e925SRichard Henderson         case 0: /* not paired */
3948bc2b17e6SRichard Henderson             if (arg_ct->ialias) {
394931fd884bSRichard Henderson                 i_preferred_regs = output_pref(op, arg_ct->alias_index);
3950c0522136SRichard Henderson 
3951c0522136SRichard Henderson                 /*
3952c0522136SRichard Henderson                  * If the input is readonly, then it cannot also be an
3953c0522136SRichard Henderson                  * output and aliased to itself.  If the input is not
3954c0522136SRichard Henderson                  * dead after the instruction, we must allocate a new
3955c0522136SRichard Henderson                  * register and move it.
3956c0522136SRichard Henderson                  */
3957c0522136SRichard Henderson                 if (temp_readonly(ts) || !IS_DEAD_ARG(i)) {
39581c1824dcSRichard Henderson                     allocate_new_reg = true;
39591c1824dcSRichard Henderson                 } else if (ts->val_type == TEMP_VAL_REG) {
3960c0522136SRichard Henderson                     /*
39611c1824dcSRichard Henderson                      * Check if the current register has already been
39621c1824dcSRichard Henderson                      * allocated for another input.
3963c0522136SRichard Henderson                      */
396429f5e925SRichard Henderson                     allocate_new_reg =
396529f5e925SRichard Henderson                         tcg_regset_test_reg(i_allocated_regs, reg);
39667e1df267SAurelien Jarno                 }
39677e1df267SAurelien Jarno             }
39681c1824dcSRichard Henderson             if (!allocate_new_reg) {
396929f5e925SRichard Henderson                 temp_load(s, ts, i_required_regs, i_allocated_regs,
397029f5e925SRichard Henderson                           i_preferred_regs);
3971c896fe29Sbellard                 reg = ts->reg;
397229f5e925SRichard Henderson                 allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg);
39731c1824dcSRichard Henderson             }
39741c1824dcSRichard Henderson             if (allocate_new_reg) {
3975c0522136SRichard Henderson                 /*
3976c0522136SRichard Henderson                  * Allocate a new register matching the constraint
3977c0522136SRichard Henderson                  * and move the temporary register into it.
3978c0522136SRichard Henderson                  */
3979d62816f2SRichard Henderson                 temp_load(s, ts, tcg_target_available_regs[ts->type],
3980d62816f2SRichard Henderson                           i_allocated_regs, 0);
398129f5e925SRichard Henderson                 reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs,
39821c1824dcSRichard Henderson                                     i_preferred_regs, ts->indirect_base);
398329f5e925SRichard Henderson                 copyto_new_reg = true;
398429f5e925SRichard Henderson             }
398529f5e925SRichard Henderson             break;
398629f5e925SRichard Henderson 
398729f5e925SRichard Henderson         case 1:
398829f5e925SRichard Henderson             /* First of an input pair; if i1 == i2, the second is an output. */
398929f5e925SRichard Henderson             i1 = i;
399029f5e925SRichard Henderson             i2 = arg_ct->pair_index;
399129f5e925SRichard Henderson             ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL;
399229f5e925SRichard Henderson 
399329f5e925SRichard Henderson             /*
399429f5e925SRichard Henderson              * It is easier to default to allocating a new pair
399529f5e925SRichard Henderson              * and to identify a few cases where it's not required.
399629f5e925SRichard Henderson              */
399729f5e925SRichard Henderson             if (arg_ct->ialias) {
399831fd884bSRichard Henderson                 i_preferred_regs = output_pref(op, arg_ct->alias_index);
399929f5e925SRichard Henderson                 if (IS_DEAD_ARG(i1) &&
400029f5e925SRichard Henderson                     IS_DEAD_ARG(i2) &&
400129f5e925SRichard Henderson                     !temp_readonly(ts) &&
400229f5e925SRichard Henderson                     ts->val_type == TEMP_VAL_REG &&
400329f5e925SRichard Henderson                     ts->reg < TCG_TARGET_NB_REGS - 1 &&
400429f5e925SRichard Henderson                     tcg_regset_test_reg(i_required_regs, reg) &&
400529f5e925SRichard Henderson                     !tcg_regset_test_reg(i_allocated_regs, reg) &&
400629f5e925SRichard Henderson                     !tcg_regset_test_reg(i_allocated_regs, reg + 1) &&
400729f5e925SRichard Henderson                     (ts2
400829f5e925SRichard Henderson                      ? ts2->val_type == TEMP_VAL_REG &&
400929f5e925SRichard Henderson                        ts2->reg == reg + 1 &&
401029f5e925SRichard Henderson                        !temp_readonly(ts2)
401129f5e925SRichard Henderson                      : s->reg_to_temp[reg + 1] == NULL)) {
401229f5e925SRichard Henderson                     break;
401329f5e925SRichard Henderson                 }
401429f5e925SRichard Henderson             } else {
401529f5e925SRichard Henderson                 /* Without aliasing, the pair must also be an input. */
401629f5e925SRichard Henderson                 tcg_debug_assert(ts2);
401729f5e925SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG &&
401829f5e925SRichard Henderson                     ts2->val_type == TEMP_VAL_REG &&
401929f5e925SRichard Henderson                     ts2->reg == reg + 1 &&
402029f5e925SRichard Henderson                     tcg_regset_test_reg(i_required_regs, reg)) {
402129f5e925SRichard Henderson                     break;
402229f5e925SRichard Henderson                 }
402329f5e925SRichard Henderson             }
402429f5e925SRichard Henderson             reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs,
402529f5e925SRichard Henderson                                      0, ts->indirect_base);
402629f5e925SRichard Henderson             goto do_pair;
402729f5e925SRichard Henderson 
402829f5e925SRichard Henderson         case 2: /* pair second */
402929f5e925SRichard Henderson             reg = new_args[arg_ct->pair_index] + 1;
403029f5e925SRichard Henderson             goto do_pair;
403129f5e925SRichard Henderson 
403229f5e925SRichard Henderson         case 3: /* ialias with second output, no first input */
403329f5e925SRichard Henderson             tcg_debug_assert(arg_ct->ialias);
403431fd884bSRichard Henderson             i_preferred_regs = output_pref(op, arg_ct->alias_index);
403529f5e925SRichard Henderson 
403629f5e925SRichard Henderson             if (IS_DEAD_ARG(i) &&
403729f5e925SRichard Henderson                 !temp_readonly(ts) &&
403829f5e925SRichard Henderson                 ts->val_type == TEMP_VAL_REG &&
403929f5e925SRichard Henderson                 reg > 0 &&
404029f5e925SRichard Henderson                 s->reg_to_temp[reg - 1] == NULL &&
404129f5e925SRichard Henderson                 tcg_regset_test_reg(i_required_regs, reg) &&
404229f5e925SRichard Henderson                 !tcg_regset_test_reg(i_allocated_regs, reg) &&
404329f5e925SRichard Henderson                 !tcg_regset_test_reg(i_allocated_regs, reg - 1)) {
404429f5e925SRichard Henderson                 tcg_regset_set_reg(i_allocated_regs, reg - 1);
404529f5e925SRichard Henderson                 break;
404629f5e925SRichard Henderson             }
404729f5e925SRichard Henderson             reg = tcg_reg_alloc_pair(s, i_required_regs >> 1,
404829f5e925SRichard Henderson                                      i_allocated_regs, 0,
404929f5e925SRichard Henderson                                      ts->indirect_base);
405029f5e925SRichard Henderson             tcg_regset_set_reg(i_allocated_regs, reg);
405129f5e925SRichard Henderson             reg += 1;
405229f5e925SRichard Henderson             goto do_pair;
405329f5e925SRichard Henderson 
405429f5e925SRichard Henderson         do_pair:
405529f5e925SRichard Henderson             /*
405629f5e925SRichard Henderson              * If an aliased input is not dead after the instruction,
405729f5e925SRichard Henderson              * we must allocate a new register and move it.
405829f5e925SRichard Henderson              */
405929f5e925SRichard Henderson             if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) {
406029f5e925SRichard Henderson                 TCGRegSet t_allocated_regs = i_allocated_regs;
406129f5e925SRichard Henderson 
406229f5e925SRichard Henderson                 /*
406329f5e925SRichard Henderson                  * Because of the alias, and the continued life, make sure
406429f5e925SRichard Henderson                  * that the temp is somewhere *other* than the reg pair,
406529f5e925SRichard Henderson                  * and we get a copy in reg.
406629f5e925SRichard Henderson                  */
406729f5e925SRichard Henderson                 tcg_regset_set_reg(t_allocated_regs, reg);
406829f5e925SRichard Henderson                 tcg_regset_set_reg(t_allocated_regs, reg + 1);
406929f5e925SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) {
407029f5e925SRichard Henderson                     /* If ts was already in reg, copy it somewhere else. */
407129f5e925SRichard Henderson                     TCGReg nr;
407229f5e925SRichard Henderson                     bool ok;
407329f5e925SRichard Henderson 
407429f5e925SRichard Henderson                     tcg_debug_assert(ts->kind != TEMP_FIXED);
407529f5e925SRichard Henderson                     nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
407629f5e925SRichard Henderson                                        t_allocated_regs, 0, ts->indirect_base);
407729f5e925SRichard Henderson                     ok = tcg_out_mov(s, ts->type, nr, reg);
407829f5e925SRichard Henderson                     tcg_debug_assert(ok);
407929f5e925SRichard Henderson 
408029f5e925SRichard Henderson                     set_temp_val_reg(s, ts, nr);
408129f5e925SRichard Henderson                 } else {
408229f5e925SRichard Henderson                     temp_load(s, ts, tcg_target_available_regs[ts->type],
408329f5e925SRichard Henderson                               t_allocated_regs, 0);
408429f5e925SRichard Henderson                     copyto_new_reg = true;
408529f5e925SRichard Henderson                 }
408629f5e925SRichard Henderson             } else {
408729f5e925SRichard Henderson                 /* Preferably allocate to reg, otherwise copy. */
408829f5e925SRichard Henderson                 i_required_regs = (TCGRegSet)1 << reg;
408929f5e925SRichard Henderson                 temp_load(s, ts, i_required_regs, i_allocated_regs,
409029f5e925SRichard Henderson                           i_preferred_regs);
409129f5e925SRichard Henderson                 copyto_new_reg = ts->reg != reg;
409229f5e925SRichard Henderson             }
409329f5e925SRichard Henderson             break;
409429f5e925SRichard Henderson 
409529f5e925SRichard Henderson         default:
409629f5e925SRichard Henderson             g_assert_not_reached();
409729f5e925SRichard Henderson         }
409829f5e925SRichard Henderson 
409929f5e925SRichard Henderson         if (copyto_new_reg) {
410078113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4101240c08d0SRichard Henderson                 /*
4102240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
4103240c08d0SRichard Henderson                  * temp back to its slot and load from there.
4104240c08d0SRichard Henderson                  */
4105240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
4106240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
4107240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
410878113e83SRichard Henderson             }
4109c896fe29Sbellard         }
4110c896fe29Sbellard         new_args[i] = reg;
4111c896fe29Sbellard         const_args[i] = 0;
411282790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
4113c896fe29Sbellard     }
4114c896fe29Sbellard 
4115c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
4116866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
4117866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
411843439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4119c896fe29Sbellard         }
4120c896fe29Sbellard     }
4121c896fe29Sbellard 
4122b4cb76e6SRichard Henderson     if (def->flags & TCG_OPF_COND_BRANCH) {
4123b4cb76e6SRichard Henderson         tcg_reg_alloc_cbranch(s, i_allocated_regs);
4124b4cb76e6SRichard Henderson     } else if (def->flags & TCG_OPF_BB_END) {
412582790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
4126a52ad07eSAurelien Jarno     } else {
4127c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
4128b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
4129c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4130c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
413182790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
4132c896fe29Sbellard                 }
4133c896fe29Sbellard             }
41343d5c5f87SAurelien Jarno         }
41353d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
41363d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
41373d5c5f87SAurelien Jarno                an exception. */
413882790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
4139c896fe29Sbellard         }
4140c896fe29Sbellard 
4141c896fe29Sbellard         /* satisfy the output constraints */
4142c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
414366792f90SRichard Henderson             i = def->args_ct[k].sort_index;
4144dd186292SRichard Henderson             arg = op->args[i];
4145c896fe29Sbellard             arg_ct = &def->args_ct[i];
414643439139SRichard Henderson             ts = arg_temp(arg);
4147d63e3b6eSRichard Henderson 
4148d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
4149e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
4150d63e3b6eSRichard Henderson 
415129f5e925SRichard Henderson             switch (arg_ct->pair) {
415229f5e925SRichard Henderson             case 0: /* not paired */
4153bc2b17e6SRichard Henderson                 if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
41545ff9d6a4Sbellard                     reg = new_args[arg_ct->alias_index];
4155bc2b17e6SRichard Henderson                 } else if (arg_ct->newreg) {
41569be0d080SRichard Henderson                     reg = tcg_reg_alloc(s, arg_ct->regs,
415782790a87SRichard Henderson                                         i_allocated_regs | o_allocated_regs,
415831fd884bSRichard Henderson                                         output_pref(op, k), ts->indirect_base);
4159c896fe29Sbellard                 } else {
41609be0d080SRichard Henderson                     reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
416131fd884bSRichard Henderson                                         output_pref(op, k), ts->indirect_base);
4162c896fe29Sbellard                 }
416329f5e925SRichard Henderson                 break;
416429f5e925SRichard Henderson 
416529f5e925SRichard Henderson             case 1: /* first of pair */
416629f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
416729f5e925SRichard Henderson                 if (arg_ct->oalias) {
416829f5e925SRichard Henderson                     reg = new_args[arg_ct->alias_index];
416929f5e925SRichard Henderson                     break;
417029f5e925SRichard Henderson                 }
417129f5e925SRichard Henderson                 reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs,
417231fd884bSRichard Henderson                                          output_pref(op, k), ts->indirect_base);
417329f5e925SRichard Henderson                 break;
417429f5e925SRichard Henderson 
417529f5e925SRichard Henderson             case 2: /* second of pair */
417629f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
417729f5e925SRichard Henderson                 if (arg_ct->oalias) {
417829f5e925SRichard Henderson                     reg = new_args[arg_ct->alias_index];
417929f5e925SRichard Henderson                 } else {
418029f5e925SRichard Henderson                     reg = new_args[arg_ct->pair_index] + 1;
418129f5e925SRichard Henderson                 }
418229f5e925SRichard Henderson                 break;
418329f5e925SRichard Henderson 
418429f5e925SRichard Henderson             case 3: /* first of pair, aliasing with a second input */
418529f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
418629f5e925SRichard Henderson                 reg = new_args[arg_ct->pair_index] - 1;
418729f5e925SRichard Henderson                 break;
418829f5e925SRichard Henderson 
418929f5e925SRichard Henderson             default:
419029f5e925SRichard Henderson                 g_assert_not_reached();
419129f5e925SRichard Henderson             }
419282790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
4193098859f1SRichard Henderson             set_temp_val_reg(s, ts, reg);
4194c896fe29Sbellard             ts->mem_coherent = 0;
4195c896fe29Sbellard             new_args[i] = reg;
4196c896fe29Sbellard         }
4197e8996ee0Sbellard     }
4198c896fe29Sbellard 
4199c896fe29Sbellard     /* emit instruction */
4200d2fd745fSRichard Henderson     if (def->flags & TCG_OPF_VECTOR) {
4201d2fd745fSRichard Henderson         tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
4202d2fd745fSRichard Henderson                        new_args, const_args);
4203d2fd745fSRichard Henderson     } else {
4204dd186292SRichard Henderson         tcg_out_op(s, op->opc, new_args, const_args);
4205d2fd745fSRichard Henderson     }
4206c896fe29Sbellard 
4207c896fe29Sbellard     /* move the outputs in the correct register if needed */
4208c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
420943439139SRichard Henderson         ts = arg_temp(op->args[i]);
4210d63e3b6eSRichard Henderson 
4211d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
4212e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
4213d63e3b6eSRichard Henderson 
4214ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
421598b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
421659d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4217f8bf00f1SRichard Henderson             temp_dead(s, ts);
4218ec7a869dSAurelien Jarno         }
4219c896fe29Sbellard     }
4220c896fe29Sbellard }
4221c896fe29Sbellard 
4222efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op)
4223efe86b21SRichard Henderson {
4224efe86b21SRichard Henderson     const TCGLifeData arg_life = op->life;
4225efe86b21SRichard Henderson     TCGTemp *ots, *itsl, *itsh;
4226efe86b21SRichard Henderson     TCGType vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
4227efe86b21SRichard Henderson 
4228efe86b21SRichard Henderson     /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */
4229efe86b21SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 32);
4230efe86b21SRichard Henderson     tcg_debug_assert(TCGOP_VECE(op) == MO_64);
4231efe86b21SRichard Henderson 
4232efe86b21SRichard Henderson     ots = arg_temp(op->args[0]);
4233efe86b21SRichard Henderson     itsl = arg_temp(op->args[1]);
4234efe86b21SRichard Henderson     itsh = arg_temp(op->args[2]);
4235efe86b21SRichard Henderson 
4236efe86b21SRichard Henderson     /* ENV should not be modified.  */
4237efe86b21SRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4238efe86b21SRichard Henderson 
4239efe86b21SRichard Henderson     /* Allocate the output register now.  */
4240efe86b21SRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
4241efe86b21SRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
4242efe86b21SRichard Henderson         TCGRegSet dup_out_regs =
4243efe86b21SRichard Henderson             tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
4244098859f1SRichard Henderson         TCGReg oreg;
4245efe86b21SRichard Henderson 
4246efe86b21SRichard Henderson         /* Make sure to not spill the input registers. */
4247efe86b21SRichard Henderson         if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) {
4248efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsl->reg);
4249efe86b21SRichard Henderson         }
4250efe86b21SRichard Henderson         if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) {
4251efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsh->reg);
4252efe86b21SRichard Henderson         }
4253efe86b21SRichard Henderson 
4254098859f1SRichard Henderson         oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
425531fd884bSRichard Henderson                              output_pref(op, 0), ots->indirect_base);
4256098859f1SRichard Henderson         set_temp_val_reg(s, ots, oreg);
4257efe86b21SRichard Henderson     }
4258efe86b21SRichard Henderson 
4259efe86b21SRichard Henderson     /* Promote dup2 of immediates to dupi_vec. */
4260efe86b21SRichard Henderson     if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) {
4261efe86b21SRichard Henderson         uint64_t val = deposit64(itsl->val, 32, 32, itsh->val);
4262efe86b21SRichard Henderson         MemOp vece = MO_64;
4263efe86b21SRichard Henderson 
4264efe86b21SRichard Henderson         if (val == dup_const(MO_8, val)) {
4265efe86b21SRichard Henderson             vece = MO_8;
4266efe86b21SRichard Henderson         } else if (val == dup_const(MO_16, val)) {
4267efe86b21SRichard Henderson             vece = MO_16;
4268efe86b21SRichard Henderson         } else if (val == dup_const(MO_32, val)) {
4269efe86b21SRichard Henderson             vece = MO_32;
4270efe86b21SRichard Henderson         }
4271efe86b21SRichard Henderson 
4272efe86b21SRichard Henderson         tcg_out_dupi_vec(s, vtype, vece, ots->reg, val);
4273efe86b21SRichard Henderson         goto done;
4274efe86b21SRichard Henderson     }
4275efe86b21SRichard Henderson 
4276efe86b21SRichard Henderson     /* If the two inputs form one 64-bit value, try dupm_vec. */
4277aef85402SRichard Henderson     if (itsl->temp_subindex == HOST_BIG_ENDIAN &&
4278aef85402SRichard Henderson         itsh->temp_subindex == !HOST_BIG_ENDIAN &&
4279aef85402SRichard Henderson         itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) {
4280aef85402SRichard Henderson         TCGTemp *its = itsl - HOST_BIG_ENDIAN;
4281aef85402SRichard Henderson 
4282aef85402SRichard Henderson         temp_sync(s, its + 0, s->reserved_regs, 0, 0);
4283aef85402SRichard Henderson         temp_sync(s, its + 1, s->reserved_regs, 0, 0);
4284aef85402SRichard Henderson 
4285efe86b21SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg,
4286efe86b21SRichard Henderson                              its->mem_base->reg, its->mem_offset)) {
4287efe86b21SRichard Henderson             goto done;
4288efe86b21SRichard Henderson         }
4289efe86b21SRichard Henderson     }
4290efe86b21SRichard Henderson 
4291efe86b21SRichard Henderson     /* Fall back to generic expansion. */
4292efe86b21SRichard Henderson     return false;
4293efe86b21SRichard Henderson 
4294efe86b21SRichard Henderson  done:
429536f5539cSRichard Henderson     ots->mem_coherent = 0;
4296efe86b21SRichard Henderson     if (IS_DEAD_ARG(1)) {
4297efe86b21SRichard Henderson         temp_dead(s, itsl);
4298efe86b21SRichard Henderson     }
4299efe86b21SRichard Henderson     if (IS_DEAD_ARG(2)) {
4300efe86b21SRichard Henderson         temp_dead(s, itsh);
4301efe86b21SRichard Henderson     }
4302efe86b21SRichard Henderson     if (NEED_SYNC_ARG(0)) {
4303efe86b21SRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0));
4304efe86b21SRichard Henderson     } else if (IS_DEAD_ARG(0)) {
4305efe86b21SRichard Henderson         temp_dead(s, ots);
4306efe86b21SRichard Henderson     }
4307efe86b21SRichard Henderson     return true;
4308efe86b21SRichard Henderson }
4309efe86b21SRichard Henderson 
431039004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts,
431139004a71SRichard Henderson                          TCGRegSet allocated_regs)
4312c896fe29Sbellard {
4313c896fe29Sbellard     if (ts->val_type == TEMP_VAL_REG) {
4314c896fe29Sbellard         if (ts->reg != reg) {
43154250da10SRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
431678113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4317240c08d0SRichard Henderson                 /*
4318240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
4319240c08d0SRichard Henderson                  * temp back to its slot and load from there.
4320240c08d0SRichard Henderson                  */
4321240c08d0SRichard Henderson                 temp_sync(s, ts, allocated_regs, 0, 0);
4322240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
4323240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
432478113e83SRichard Henderson             }
4325c896fe29Sbellard         }
4326c896fe29Sbellard     } else {
4327ccb1bb66SRichard Henderson         TCGRegSet arg_set = 0;
432840ae5c62SRichard Henderson 
43294250da10SRichard Henderson         tcg_reg_free(s, reg, allocated_regs);
433040ae5c62SRichard Henderson         tcg_regset_set_reg(arg_set, reg);
4331b722452aSRichard Henderson         temp_load(s, ts, arg_set, allocated_regs, 0);
4332c896fe29Sbellard     }
433339004a71SRichard Henderson }
433440ae5c62SRichard Henderson 
433539004a71SRichard Henderson static void load_arg_stk(TCGContext *s, int stk_slot, TCGTemp *ts,
433639004a71SRichard Henderson                          TCGRegSet allocated_regs)
433739004a71SRichard Henderson {
433839004a71SRichard Henderson     /*
433939004a71SRichard Henderson      * When the destination is on the stack, load up the temp and store.
434039004a71SRichard Henderson      * If there are many call-saved registers, the temp might live to
434139004a71SRichard Henderson      * see another use; otherwise it'll be discarded.
434239004a71SRichard Henderson      */
434339004a71SRichard Henderson     temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0);
434439004a71SRichard Henderson     tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK,
434539004a71SRichard Henderson                TCG_TARGET_CALL_STACK_OFFSET +
434639004a71SRichard Henderson                stk_slot * sizeof(tcg_target_long));
434739004a71SRichard Henderson }
434839004a71SRichard Henderson 
434939004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l,
435039004a71SRichard Henderson                             TCGTemp *ts, TCGRegSet *allocated_regs)
435139004a71SRichard Henderson {
435239004a71SRichard Henderson     if (REG_P(l)) {
435339004a71SRichard Henderson         TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot];
435439004a71SRichard Henderson         load_arg_reg(s, reg, ts, *allocated_regs);
435539004a71SRichard Henderson         tcg_regset_set_reg(*allocated_regs, reg);
435639004a71SRichard Henderson     } else {
435739004a71SRichard Henderson         load_arg_stk(s, l->arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs),
435839004a71SRichard Henderson                      ts, *allocated_regs);
4359c896fe29Sbellard     }
436039cf05d3Sbellard }
4361c896fe29Sbellard 
436239004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
436339004a71SRichard Henderson {
436439004a71SRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
436539004a71SRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
436639004a71SRichard Henderson     const TCGLifeData arg_life = op->life;
436739004a71SRichard Henderson     const TCGHelperInfo *info = tcg_call_info(op);
436839004a71SRichard Henderson     TCGRegSet allocated_regs = s->reserved_regs;
436939004a71SRichard Henderson     int i;
437039004a71SRichard Henderson 
437139004a71SRichard Henderson     /*
437239004a71SRichard Henderson      * Move inputs into place in reverse order,
437339004a71SRichard Henderson      * so that we place stacked arguments first.
437439004a71SRichard Henderson      */
437539004a71SRichard Henderson     for (i = nb_iargs - 1; i >= 0; --i) {
437639004a71SRichard Henderson         const TCGCallArgumentLoc *loc = &info->in[i];
437739004a71SRichard Henderson         TCGTemp *ts = arg_temp(op->args[nb_oargs + i]);
437839004a71SRichard Henderson 
437939004a71SRichard Henderson         switch (loc->kind) {
438039004a71SRichard Henderson         case TCG_CALL_ARG_NORMAL:
438139004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
438239004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
438339004a71SRichard Henderson             load_arg_normal(s, loc, ts, &allocated_regs);
438439004a71SRichard Henderson             break;
438539004a71SRichard Henderson         default:
438639004a71SRichard Henderson             g_assert_not_reached();
438739004a71SRichard Henderson         }
438839004a71SRichard Henderson     }
438939004a71SRichard Henderson 
439039004a71SRichard Henderson     /* Mark dead temporaries and free the associated registers.  */
4391866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4392866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
439343439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4394c896fe29Sbellard         }
4395c896fe29Sbellard     }
4396c896fe29Sbellard 
439739004a71SRichard Henderson     /* Clobber call registers.  */
4398c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4399c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
4400b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
4401c896fe29Sbellard         }
4402c896fe29Sbellard     }
4403c896fe29Sbellard 
440439004a71SRichard Henderson     /*
440539004a71SRichard Henderson      * Save globals if they might be written by the helper,
440639004a71SRichard Henderson      * sync them if they might be read.
440739004a71SRichard Henderson      */
440839004a71SRichard Henderson     if (info->flags & TCG_CALL_NO_READ_GLOBALS) {
440978505279SAurelien Jarno         /* Nothing to do */
441039004a71SRichard Henderson     } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) {
441178505279SAurelien Jarno         sync_globals(s, allocated_regs);
441278505279SAurelien Jarno     } else {
4413e8996ee0Sbellard         save_globals(s, allocated_regs);
4414b9c18f56Saurel32     }
4415c896fe29Sbellard 
4416cee44b03SRichard Henderson     tcg_out_call(s, tcg_call_func(op), info);
4417c896fe29Sbellard 
441839004a71SRichard Henderson     /* Assign output registers and emit moves if needed.  */
441939004a71SRichard Henderson     switch (info->out_kind) {
442039004a71SRichard Henderson     case TCG_CALL_RET_NORMAL:
4421c896fe29Sbellard         for (i = 0; i < nb_oargs; i++) {
442239004a71SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
442339004a71SRichard Henderson             TCGReg reg = tcg_target_call_oarg_regs[i];
4424d63e3b6eSRichard Henderson 
4425d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
4426e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
4427d63e3b6eSRichard Henderson 
4428098859f1SRichard Henderson             set_temp_val_reg(s, ts, reg);
4429c896fe29Sbellard             ts->mem_coherent = 0;
443039004a71SRichard Henderson         }
443139004a71SRichard Henderson         break;
443239004a71SRichard Henderson     default:
443339004a71SRichard Henderson         g_assert_not_reached();
443439004a71SRichard Henderson     }
443539004a71SRichard Henderson 
443639004a71SRichard Henderson     /* Flush or discard output registers as needed. */
443739004a71SRichard Henderson     for (i = 0; i < nb_oargs; i++) {
443839004a71SRichard Henderson         TCGTemp *ts = arg_temp(op->args[i]);
4439ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
444039004a71SRichard Henderson             temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i));
444159d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4442f8bf00f1SRichard Henderson             temp_dead(s, ts);
4443c896fe29Sbellard         }
4444c896fe29Sbellard     }
44458c11ad25SAurelien Jarno }
4446c896fe29Sbellard 
4447c896fe29Sbellard #ifdef CONFIG_PROFILER
4448c896fe29Sbellard 
4449c3fac113SEmilio G. Cota /* avoid copy/paste errors */
4450c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field)                       \
4451c3fac113SEmilio G. Cota     do {                                                \
4452d73415a3SStefan Hajnoczi         (to)->field += qatomic_read(&((from)->field));  \
4453c3fac113SEmilio G. Cota     } while (0)
4454c896fe29Sbellard 
4455c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field)                                       \
4456c3fac113SEmilio G. Cota     do {                                                                \
4457d73415a3SStefan Hajnoczi         typeof((from)->field) val__ = qatomic_read(&((from)->field));   \
4458c3fac113SEmilio G. Cota         if (val__ > (to)->field) {                                      \
4459c3fac113SEmilio G. Cota             (to)->field = val__;                                        \
4460c3fac113SEmilio G. Cota         }                                                               \
4461c3fac113SEmilio G. Cota     } while (0)
4462c3fac113SEmilio G. Cota 
4463c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */
4464c3fac113SEmilio G. Cota static inline
4465c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
4466c896fe29Sbellard {
44670e2d61cfSRichard Henderson     unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
4468c3fac113SEmilio G. Cota     unsigned int i;
4469c3fac113SEmilio G. Cota 
44703468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4471d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
44723468b59eSEmilio G. Cota         const TCGProfile *orig = &s->prof;
4473c3fac113SEmilio G. Cota 
4474c3fac113SEmilio G. Cota         if (counters) {
447572fd2efbSEmilio G. Cota             PROF_ADD(prof, orig, cpu_exec_time);
4476c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count1);
4477c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count);
4478c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, op_count);
4479c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, op_count_max);
4480c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, temp_count);
4481c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, temp_count_max);
4482c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, del_op_count);
4483c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_in_len);
4484c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_out_len);
4485c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, search_out_len);
4486c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, interm_time);
4487c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_time);
4488c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, la_time);
4489c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, opt_time);
4490c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_count);
4491c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_time);
4492c3fac113SEmilio G. Cota         }
4493c3fac113SEmilio G. Cota         if (table) {
4494c896fe29Sbellard             int i;
4495d70724ceSzhanghailiang 
449615fc7daaSRichard Henderson             for (i = 0; i < NB_OPS; i++) {
4497c3fac113SEmilio G. Cota                 PROF_ADD(prof, orig, table_op_count[i]);
4498c3fac113SEmilio G. Cota             }
4499c3fac113SEmilio G. Cota         }
4500c3fac113SEmilio G. Cota     }
4501c3fac113SEmilio G. Cota }
4502c3fac113SEmilio G. Cota 
4503c3fac113SEmilio G. Cota #undef PROF_ADD
4504c3fac113SEmilio G. Cota #undef PROF_MAX
4505c3fac113SEmilio G. Cota 
4506c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof)
4507c3fac113SEmilio G. Cota {
4508c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, true, false);
4509c3fac113SEmilio G. Cota }
4510c3fac113SEmilio G. Cota 
4511c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof)
4512c3fac113SEmilio G. Cota {
4513c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, false, true);
4514c3fac113SEmilio G. Cota }
4515c3fac113SEmilio G. Cota 
4516b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf)
4517c3fac113SEmilio G. Cota {
4518c3fac113SEmilio G. Cota     TCGProfile prof = {};
4519c3fac113SEmilio G. Cota     int i;
4520c3fac113SEmilio G. Cota 
4521c3fac113SEmilio G. Cota     tcg_profile_snapshot_table(&prof);
4522c3fac113SEmilio G. Cota     for (i = 0; i < NB_OPS; i++) {
4523b6a7f3e0SDaniel P. Berrangé         g_string_append_printf(buf, "%s %" PRId64 "\n", tcg_op_defs[i].name,
4524c3fac113SEmilio G. Cota                                prof.table_op_count[i]);
4525c896fe29Sbellard     }
4526c896fe29Sbellard }
452772fd2efbSEmilio G. Cota 
452872fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
452972fd2efbSEmilio G. Cota {
45300e2d61cfSRichard Henderson     unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
453172fd2efbSEmilio G. Cota     unsigned int i;
453272fd2efbSEmilio G. Cota     int64_t ret = 0;
453372fd2efbSEmilio G. Cota 
453472fd2efbSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4535d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
453672fd2efbSEmilio G. Cota         const TCGProfile *prof = &s->prof;
453772fd2efbSEmilio G. Cota 
4538d73415a3SStefan Hajnoczi         ret += qatomic_read(&prof->cpu_exec_time);
453972fd2efbSEmilio G. Cota     }
454072fd2efbSEmilio G. Cota     return ret;
454172fd2efbSEmilio G. Cota }
4542246ae24dSMax Filippov #else
4543b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf)
4544246ae24dSMax Filippov {
4545b6a7f3e0SDaniel P. Berrangé     g_string_append_printf(buf, "[TCG profiler not compiled]\n");
4546246ae24dSMax Filippov }
454772fd2efbSEmilio G. Cota 
454872fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
454972fd2efbSEmilio G. Cota {
455072fd2efbSEmilio G. Cota     error_report("%s: TCG profiler not compiled", __func__);
455172fd2efbSEmilio G. Cota     exit(EXIT_FAILURE);
455272fd2efbSEmilio G. Cota }
4553c896fe29Sbellard #endif
4554c896fe29Sbellard 
4555c896fe29Sbellard 
4556fbf59aadSRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start)
4557c896fe29Sbellard {
4558c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER
4559c3fac113SEmilio G. Cota     TCGProfile *prof = &s->prof;
4560c3fac113SEmilio G. Cota #endif
456115fa08f8SRichard Henderson     int i, num_insns;
456215fa08f8SRichard Henderson     TCGOp *op;
4563c896fe29Sbellard 
456404fe6400SRichard Henderson #ifdef CONFIG_PROFILER
456504fe6400SRichard Henderson     {
4566c1f543b7SEmilio G. Cota         int n = 0;
456704fe6400SRichard Henderson 
456815fa08f8SRichard Henderson         QTAILQ_FOREACH(op, &s->ops, link) {
456915fa08f8SRichard Henderson             n++;
457015fa08f8SRichard Henderson         }
4571d73415a3SStefan Hajnoczi         qatomic_set(&prof->op_count, prof->op_count + n);
4572c3fac113SEmilio G. Cota         if (n > prof->op_count_max) {
4573d73415a3SStefan Hajnoczi             qatomic_set(&prof->op_count_max, n);
457404fe6400SRichard Henderson         }
457504fe6400SRichard Henderson 
457604fe6400SRichard Henderson         n = s->nb_temps;
4577d73415a3SStefan Hajnoczi         qatomic_set(&prof->temp_count, prof->temp_count + n);
4578c3fac113SEmilio G. Cota         if (n > prof->temp_count_max) {
4579d73415a3SStefan Hajnoczi             qatomic_set(&prof->temp_count_max, n);
458004fe6400SRichard Henderson         }
458104fe6400SRichard Henderson     }
458204fe6400SRichard Henderson #endif
458304fe6400SRichard Henderson 
4584c896fe29Sbellard #ifdef DEBUG_DISAS
4585d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
4586fbf59aadSRichard Henderson                  && qemu_log_in_addr_range(pc_start))) {
4587c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
458878b54858SRichard Henderson         if (logfile) {
458978b54858SRichard Henderson             fprintf(logfile, "OP:\n");
4590b7a83ff8SRichard Henderson             tcg_dump_ops(s, logfile, false);
459178b54858SRichard Henderson             fprintf(logfile, "\n");
4592fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
4593c896fe29Sbellard         }
459478b54858SRichard Henderson     }
4595c896fe29Sbellard #endif
4596c896fe29Sbellard 
4597bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
4598bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
4599bef16ab4SRichard Henderson     {
4600bef16ab4SRichard Henderson         TCGLabel *l;
4601bef16ab4SRichard Henderson         bool error = false;
4602bef16ab4SRichard Henderson 
4603bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
4604bef16ab4SRichard Henderson             if (unlikely(!l->present) && l->refs) {
4605bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
4606bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
4607bef16ab4SRichard Henderson                 error = true;
4608bef16ab4SRichard Henderson             }
4609bef16ab4SRichard Henderson         }
4610bef16ab4SRichard Henderson         assert(!error);
4611bef16ab4SRichard Henderson     }
4612bef16ab4SRichard Henderson #endif
4613bef16ab4SRichard Henderson 
4614c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
4615d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
4616c5cc28ffSAurelien Jarno #endif
4617c5cc28ffSAurelien Jarno 
46188f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
4619c45cb8bbSRichard Henderson     tcg_optimize(s);
46208f2e8c07SKirill Batuzov #endif
46218f2e8c07SKirill Batuzov 
4622a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4623d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
4624d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time - profile_getclock());
4625a23a9ec6Sbellard #endif
4626c5cc28ffSAurelien Jarno 
4627b4fc67c7SRichard Henderson     reachable_code_pass(s);
4628b83eabeaSRichard Henderson     liveness_pass_1(s);
46295a18407fSRichard Henderson 
46305a18407fSRichard Henderson     if (s->nb_indirects > 0) {
46315a18407fSRichard Henderson #ifdef DEBUG_DISAS
46325a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
4633fbf59aadSRichard Henderson                      && qemu_log_in_addr_range(pc_start))) {
4634c60f599bSRichard Henderson             FILE *logfile = qemu_log_trylock();
463578b54858SRichard Henderson             if (logfile) {
463678b54858SRichard Henderson                 fprintf(logfile, "OP before indirect lowering:\n");
4637b7a83ff8SRichard Henderson                 tcg_dump_ops(s, logfile, false);
463878b54858SRichard Henderson                 fprintf(logfile, "\n");
4639fc59d2d8SRobert Foley                 qemu_log_unlock(logfile);
46405a18407fSRichard Henderson             }
464178b54858SRichard Henderson         }
46425a18407fSRichard Henderson #endif
46435a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
4644b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
46455a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
4646b83eabeaSRichard Henderson             liveness_pass_1(s);
46475a18407fSRichard Henderson         }
46485a18407fSRichard Henderson     }
4649c5cc28ffSAurelien Jarno 
4650a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4651d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time + profile_getclock());
4652a23a9ec6Sbellard #endif
4653c896fe29Sbellard 
4654c896fe29Sbellard #ifdef DEBUG_DISAS
4655d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
4656fbf59aadSRichard Henderson                  && qemu_log_in_addr_range(pc_start))) {
4657c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
465878b54858SRichard Henderson         if (logfile) {
465978b54858SRichard Henderson             fprintf(logfile, "OP after optimization and liveness analysis:\n");
4660b7a83ff8SRichard Henderson             tcg_dump_ops(s, logfile, true);
466178b54858SRichard Henderson             fprintf(logfile, "\n");
4662fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
4663c896fe29Sbellard         }
466478b54858SRichard Henderson     }
4665c896fe29Sbellard #endif
4666c896fe29Sbellard 
466735abb009SRichard Henderson     /* Initialize goto_tb jump offsets. */
466835abb009SRichard Henderson     tb->jmp_reset_offset[0] = TB_JMP_RESET_OFFSET_INVALID;
466935abb009SRichard Henderson     tb->jmp_reset_offset[1] = TB_JMP_RESET_OFFSET_INVALID;
467035abb009SRichard Henderson     tcg_ctx->tb_jmp_reset_offset = tb->jmp_reset_offset;
467135abb009SRichard Henderson     if (TCG_TARGET_HAS_direct_jump) {
467235abb009SRichard Henderson         tcg_ctx->tb_jmp_insn_offset = tb->jmp_target_arg;
467335abb009SRichard Henderson         tcg_ctx->tb_jmp_target_addr = NULL;
467435abb009SRichard Henderson     } else {
467535abb009SRichard Henderson         tcg_ctx->tb_jmp_insn_offset = NULL;
467635abb009SRichard Henderson         tcg_ctx->tb_jmp_target_addr = tb->jmp_target_arg;
467735abb009SRichard Henderson     }
467835abb009SRichard Henderson 
4679c896fe29Sbellard     tcg_reg_alloc_start(s);
4680c896fe29Sbellard 
4681db0c51a3SRichard Henderson     /*
4682db0c51a3SRichard Henderson      * Reset the buffer pointers when restarting after overflow.
4683db0c51a3SRichard Henderson      * TODO: Move this into translate-all.c with the rest of the
4684db0c51a3SRichard Henderson      * buffer management.  Having only this done here is confusing.
4685db0c51a3SRichard Henderson      */
4686db0c51a3SRichard Henderson     s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr);
4687db0c51a3SRichard Henderson     s->code_ptr = s->code_buf;
4688c896fe29Sbellard 
4689659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
46906001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
4691659ef5cbSRichard Henderson #endif
469257a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
469357a26946SRichard Henderson     s->pool_labels = NULL;
469457a26946SRichard Henderson #endif
46959ecefc84SRichard Henderson 
4696fca8a500SRichard Henderson     num_insns = -1;
469715fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
4698c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
4699b3db8758Sblueswir1 
4700c896fe29Sbellard #ifdef CONFIG_PROFILER
4701d73415a3SStefan Hajnoczi         qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
4702c896fe29Sbellard #endif
4703c45cb8bbSRichard Henderson 
4704c896fe29Sbellard         switch (opc) {
4705c896fe29Sbellard         case INDEX_op_mov_i32:
4706c896fe29Sbellard         case INDEX_op_mov_i64:
4707d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
4708dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
4709c896fe29Sbellard             break;
4710bab1671fSRichard Henderson         case INDEX_op_dup_vec:
4711bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
4712bab1671fSRichard Henderson             break;
4713765b842aSRichard Henderson         case INDEX_op_insn_start:
4714fca8a500SRichard Henderson             if (num_insns >= 0) {
47159f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
47169f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
47179f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
47189f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
4719fca8a500SRichard Henderson             }
4720fca8a500SRichard Henderson             num_insns++;
4721bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
4722bad729e2SRichard Henderson                 target_ulong a;
4723bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
4724efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
4725bad729e2SRichard Henderson #else
4726efee3746SRichard Henderson                 a = op->args[i];
4727bad729e2SRichard Henderson #endif
4728fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
4729bad729e2SRichard Henderson             }
4730c896fe29Sbellard             break;
47315ff9d6a4Sbellard         case INDEX_op_discard:
473243439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
47335ff9d6a4Sbellard             break;
4734c896fe29Sbellard         case INDEX_op_set_label:
4735e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
473692ab8e7dSRichard Henderson             tcg_out_label(s, arg_label(op->args[0]));
4737c896fe29Sbellard             break;
4738c896fe29Sbellard         case INDEX_op_call:
4739dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
4740c45cb8bbSRichard Henderson             break;
4741b55a8d9dSRichard Henderson         case INDEX_op_exit_tb:
4742b55a8d9dSRichard Henderson             tcg_out_exit_tb(s, op->args[0]);
4743b55a8d9dSRichard Henderson             break;
4744efe86b21SRichard Henderson         case INDEX_op_dup2_vec:
4745efe86b21SRichard Henderson             if (tcg_reg_alloc_dup2(s, op)) {
4746efe86b21SRichard Henderson                 break;
4747efe86b21SRichard Henderson             }
4748efe86b21SRichard Henderson             /* fall through */
4749c896fe29Sbellard         default:
475025c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
4751be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
4752c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
4753c896fe29Sbellard                faster to have specialized register allocator functions for
4754c896fe29Sbellard                some common argument patterns */
4755dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
4756c896fe29Sbellard             break;
4757c896fe29Sbellard         }
4758b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
4759b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
4760b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
4761b125f9dcSRichard Henderson            generating code without having to check during generation.  */
4762644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
4763b125f9dcSRichard Henderson             return -1;
4764b125f9dcSRichard Henderson         }
47656e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
47666e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
47676e6c4efeSRichard Henderson             return -2;
47686e6c4efeSRichard Henderson         }
4769c896fe29Sbellard     }
4770fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
4771fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
4772c45cb8bbSRichard Henderson 
4773b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
4774659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
4775aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
4776aeee05f5SRichard Henderson     if (i < 0) {
4777aeee05f5SRichard Henderson         return i;
477823dceda6SRichard Henderson     }
4779659ef5cbSRichard Henderson #endif
478057a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
47811768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
47821768987bSRichard Henderson     if (i < 0) {
47831768987bSRichard Henderson         return i;
478457a26946SRichard Henderson     }
478557a26946SRichard Henderson #endif
47867ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
47877ecd02a0SRichard Henderson         return -2;
47887ecd02a0SRichard Henderson     }
4789c896fe29Sbellard 
4790df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
4791c896fe29Sbellard     /* flush instruction cache */
4792db0c51a3SRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
4793db0c51a3SRichard Henderson                         (uintptr_t)s->code_buf,
47941da8de39SRichard Henderson                         tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
4795df5d2b16SRichard Henderson #endif
47962aeabc08SStefan Weil 
47971813e175SRichard Henderson     return tcg_current_code_size(s);
4798c896fe29Sbellard }
4799c896fe29Sbellard 
4800a23a9ec6Sbellard #ifdef CONFIG_PROFILER
48013a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf)
4802a23a9ec6Sbellard {
4803c3fac113SEmilio G. Cota     TCGProfile prof = {};
4804c3fac113SEmilio G. Cota     const TCGProfile *s;
4805c3fac113SEmilio G. Cota     int64_t tb_count;
4806c3fac113SEmilio G. Cota     int64_t tb_div_count;
4807c3fac113SEmilio G. Cota     int64_t tot;
4808c3fac113SEmilio G. Cota 
4809c3fac113SEmilio G. Cota     tcg_profile_snapshot_counters(&prof);
4810c3fac113SEmilio G. Cota     s = &prof;
4811c3fac113SEmilio G. Cota     tb_count = s->tb_count;
4812c3fac113SEmilio G. Cota     tb_div_count = tb_count ? tb_count : 1;
4813c3fac113SEmilio G. Cota     tot = s->interm_time + s->code_time;
4814a23a9ec6Sbellard 
48153a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "JIT cycles          %" PRId64
48163a841ab5SDaniel P. Berrangé                            " (%0.3f s at 2.4 GHz)\n",
4817a23a9ec6Sbellard                            tot, tot / 2.4e9);
48183a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "translated TBs      %" PRId64
48193a841ab5SDaniel P. Berrangé                            " (aborted=%" PRId64 " %0.1f%%)\n",
4820fca8a500SRichard Henderson                            tb_count, s->tb_count1 - tb_count,
4821fca8a500SRichard Henderson                            (double)(s->tb_count1 - s->tb_count)
4822fca8a500SRichard Henderson                            / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
48233a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg ops/TB          %0.1f max=%d\n",
4824fca8a500SRichard Henderson                            (double)s->op_count / tb_div_count, s->op_count_max);
48253a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "deleted ops/TB      %0.2f\n",
4826fca8a500SRichard Henderson                            (double)s->del_op_count / tb_div_count);
48273a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg temps/TB        %0.2f max=%d\n",
48283a841ab5SDaniel P. Berrangé                            (double)s->temp_count / tb_div_count,
48293a841ab5SDaniel P. Berrangé                            s->temp_count_max);
48303a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg host code/TB    %0.1f\n",
4831fca8a500SRichard Henderson                            (double)s->code_out_len / tb_div_count);
48323a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg search data/TB  %0.1f\n",
4833fca8a500SRichard Henderson                            (double)s->search_out_len / tb_div_count);
4834a23a9ec6Sbellard 
48353a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/op           %0.1f\n",
4836a23a9ec6Sbellard                            s->op_count ? (double)tot / s->op_count : 0);
48373a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/in byte      %0.1f\n",
4838a23a9ec6Sbellard                            s->code_in_len ? (double)tot / s->code_in_len : 0);
48393a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/out byte     %0.1f\n",
4840a23a9ec6Sbellard                            s->code_out_len ? (double)tot / s->code_out_len : 0);
48413a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/search byte     %0.1f\n",
48423a841ab5SDaniel P. Berrangé                            s->search_out_len ?
48433a841ab5SDaniel P. Berrangé                            (double)tot / s->search_out_len : 0);
4844fca8a500SRichard Henderson     if (tot == 0) {
4845a23a9ec6Sbellard         tot = 1;
4846fca8a500SRichard Henderson     }
48473a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "  gen_interm time   %0.1f%%\n",
4848a23a9ec6Sbellard                            (double)s->interm_time / tot * 100.0);
48493a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "  gen_code time     %0.1f%%\n",
4850a23a9ec6Sbellard                            (double)s->code_time / tot * 100.0);
48513a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "optim./code time    %0.1f%%\n",
48523a841ab5SDaniel P. Berrangé                            (double)s->opt_time / (s->code_time ?
48533a841ab5SDaniel P. Berrangé                                                   s->code_time : 1)
4854c5cc28ffSAurelien Jarno                            * 100.0);
48553a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "liveness/code time  %0.1f%%\n",
48563a841ab5SDaniel P. Berrangé                            (double)s->la_time / (s->code_time ?
48573a841ab5SDaniel P. Berrangé                                                  s->code_time : 1) * 100.0);
48583a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cpu_restore count   %" PRId64 "\n",
4859a23a9ec6Sbellard                            s->restore_count);
48603a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "  avg cycles        %0.1f\n",
48613a841ab5SDaniel P. Berrangé                            s->restore_count ?
48623a841ab5SDaniel P. Berrangé                            (double)s->restore_time / s->restore_count : 0);
4863a23a9ec6Sbellard }
4864a23a9ec6Sbellard #else
48653a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf)
4866a23a9ec6Sbellard {
48673a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "[TCG profiler not compiled]\n");
4868a23a9ec6Sbellard }
4869a23a9ec6Sbellard #endif
4870813da627SRichard Henderson 
4871813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
48725872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
48735872bbf2SRichard Henderson 
48745872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
48755872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
48765872bbf2SRichard Henderson 
48775872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
48785872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
48795872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
48805872bbf2SRichard Henderson 
48815872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
48825872bbf2SRichard Henderson */
4883813da627SRichard Henderson 
4884813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
4885813da627SRichard Henderson typedef enum {
4886813da627SRichard Henderson     JIT_NOACTION = 0,
4887813da627SRichard Henderson     JIT_REGISTER_FN,
4888813da627SRichard Henderson     JIT_UNREGISTER_FN
4889813da627SRichard Henderson } jit_actions_t;
4890813da627SRichard Henderson 
4891813da627SRichard Henderson struct jit_code_entry {
4892813da627SRichard Henderson     struct jit_code_entry *next_entry;
4893813da627SRichard Henderson     struct jit_code_entry *prev_entry;
4894813da627SRichard Henderson     const void *symfile_addr;
4895813da627SRichard Henderson     uint64_t symfile_size;
4896813da627SRichard Henderson };
4897813da627SRichard Henderson 
4898813da627SRichard Henderson struct jit_descriptor {
4899813da627SRichard Henderson     uint32_t version;
4900813da627SRichard Henderson     uint32_t action_flag;
4901813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
4902813da627SRichard Henderson     struct jit_code_entry *first_entry;
4903813da627SRichard Henderson };
4904813da627SRichard Henderson 
4905813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
4906813da627SRichard Henderson void __jit_debug_register_code(void)
4907813da627SRichard Henderson {
4908813da627SRichard Henderson     asm("");
4909813da627SRichard Henderson }
4910813da627SRichard Henderson 
4911813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
4912813da627SRichard Henderson    the version before we can set it.  */
4913813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
4914813da627SRichard Henderson 
4915813da627SRichard Henderson /* End GDB interface.  */
4916813da627SRichard Henderson 
4917813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
4918813da627SRichard Henderson {
4919813da627SRichard Henderson     const char *p = strtab + 1;
4920813da627SRichard Henderson 
4921813da627SRichard Henderson     while (1) {
4922813da627SRichard Henderson         if (strcmp(p, str) == 0) {
4923813da627SRichard Henderson             return p - strtab;
4924813da627SRichard Henderson         }
4925813da627SRichard Henderson         p += strlen(p) + 1;
4926813da627SRichard Henderson     }
4927813da627SRichard Henderson }
4928813da627SRichard Henderson 
4929755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size,
49302c90784aSRichard Henderson                                  const void *debug_frame,
49312c90784aSRichard Henderson                                  size_t debug_frame_size)
4932813da627SRichard Henderson {
49335872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
49345872bbf2SRichard Henderson         uint32_t  len;
49355872bbf2SRichard Henderson         uint16_t  version;
49365872bbf2SRichard Henderson         uint32_t  abbrev;
49375872bbf2SRichard Henderson         uint8_t   ptr_size;
49385872bbf2SRichard Henderson         uint8_t   cu_die;
49395872bbf2SRichard Henderson         uint16_t  cu_lang;
49405872bbf2SRichard Henderson         uintptr_t cu_low_pc;
49415872bbf2SRichard Henderson         uintptr_t cu_high_pc;
49425872bbf2SRichard Henderson         uint8_t   fn_die;
49435872bbf2SRichard Henderson         char      fn_name[16];
49445872bbf2SRichard Henderson         uintptr_t fn_low_pc;
49455872bbf2SRichard Henderson         uintptr_t fn_high_pc;
49465872bbf2SRichard Henderson         uint8_t   cu_eoc;
49475872bbf2SRichard Henderson     };
4948813da627SRichard Henderson 
4949813da627SRichard Henderson     struct ElfImage {
4950813da627SRichard Henderson         ElfW(Ehdr) ehdr;
4951813da627SRichard Henderson         ElfW(Phdr) phdr;
49525872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
49535872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
49545872bbf2SRichard Henderson         struct DebugInfo di;
49555872bbf2SRichard Henderson         uint8_t    da[24];
49565872bbf2SRichard Henderson         char       str[80];
49575872bbf2SRichard Henderson     };
49585872bbf2SRichard Henderson 
49595872bbf2SRichard Henderson     struct ElfImage *img;
49605872bbf2SRichard Henderson 
49615872bbf2SRichard Henderson     static const struct ElfImage img_template = {
49625872bbf2SRichard Henderson         .ehdr = {
49635872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
49645872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
49655872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
49665872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
49675872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
49685872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
49695872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
49705872bbf2SRichard Henderson             .e_type = ET_EXEC,
49715872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
49725872bbf2SRichard Henderson             .e_version = EV_CURRENT,
49735872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
49745872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
49755872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
49765872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
49775872bbf2SRichard Henderson             .e_phnum = 1,
49785872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
49795872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
49805872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
4981abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
4982abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
4983abbb3eaeSRichard Henderson #endif
4984abbb3eaeSRichard Henderson #ifdef ELF_OSABI
4985abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
4986abbb3eaeSRichard Henderson #endif
49875872bbf2SRichard Henderson         },
49885872bbf2SRichard Henderson         .phdr = {
49895872bbf2SRichard Henderson             .p_type = PT_LOAD,
49905872bbf2SRichard Henderson             .p_flags = PF_X,
49915872bbf2SRichard Henderson         },
49925872bbf2SRichard Henderson         .shdr = {
49935872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
49945872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
49955872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
49965872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
49975872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
49985872bbf2SRichard Henderson             [1] = { /* .text */
49995872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
50005872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
50015872bbf2SRichard Henderson             },
50025872bbf2SRichard Henderson             [2] = { /* .debug_info */
50035872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
50045872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
50055872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
50065872bbf2SRichard Henderson             },
50075872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
50085872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
50095872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
50105872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
50115872bbf2SRichard Henderson             },
50125872bbf2SRichard Henderson             [4] = { /* .debug_frame */
50135872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
50145872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
50155872bbf2SRichard Henderson             },
50165872bbf2SRichard Henderson             [5] = { /* .symtab */
50175872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
50185872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
50195872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
50205872bbf2SRichard Henderson                 .sh_info = 1,
50215872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
50225872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
50235872bbf2SRichard Henderson             },
50245872bbf2SRichard Henderson             [6] = { /* .strtab */
50255872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
50265872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
50275872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
50285872bbf2SRichard Henderson             }
50295872bbf2SRichard Henderson         },
50305872bbf2SRichard Henderson         .sym = {
50315872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
50325872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
50335872bbf2SRichard Henderson                 .st_shndx = 1,
50345872bbf2SRichard Henderson             }
50355872bbf2SRichard Henderson         },
50365872bbf2SRichard Henderson         .di = {
50375872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
50385872bbf2SRichard Henderson             .version = 2,
50395872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
50405872bbf2SRichard Henderson             .cu_die = 1,
50415872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
50425872bbf2SRichard Henderson             .fn_die = 2,
50435872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
50445872bbf2SRichard Henderson         },
50455872bbf2SRichard Henderson         .da = {
50465872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
50475872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
50485872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
50495872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
50505872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
50515872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
50525872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
50535872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
50545872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
50555872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
50565872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
50575872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
50585872bbf2SRichard Henderson             0           /* no more abbrev */
50595872bbf2SRichard Henderson         },
50605872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
50615872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
5062813da627SRichard Henderson     };
5063813da627SRichard Henderson 
5064813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
5065813da627SRichard Henderson     static struct jit_code_entry one_entry;
5066813da627SRichard Henderson 
50675872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
5068813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
50692c90784aSRichard Henderson     DebugFrameHeader *dfh;
5070813da627SRichard Henderson 
50715872bbf2SRichard Henderson     img = g_malloc(img_size);
50725872bbf2SRichard Henderson     *img = img_template;
5073813da627SRichard Henderson 
50745872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
50755872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
50765872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
5077813da627SRichard Henderson 
50785872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
50795872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
50805872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
5081813da627SRichard Henderson 
50825872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
50835872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
50845872bbf2SRichard Henderson 
50855872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
50865872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
50875872bbf2SRichard Henderson 
50885872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
50895872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
50905872bbf2SRichard Henderson 
50915872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
50925872bbf2SRichard Henderson     img->sym[1].st_value = buf;
50935872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
50945872bbf2SRichard Henderson 
50955872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
509645aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
50975872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
509845aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
5099813da627SRichard Henderson 
51002c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
51012c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
51022c90784aSRichard Henderson     dfh->fde.func_start = buf;
51032c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
51042c90784aSRichard Henderson 
5105813da627SRichard Henderson #ifdef DEBUG_JIT
5106813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
5107813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
5108813da627SRichard Henderson     {
5109eb6b2edfSBin Meng         g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir());
5110eb6b2edfSBin Meng         FILE *f = fopen(jit, "w+b");
5111813da627SRichard Henderson         if (f) {
51125872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
5113813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
5114813da627SRichard Henderson             }
5115813da627SRichard Henderson             fclose(f);
5116813da627SRichard Henderson         }
5117813da627SRichard Henderson     }
5118813da627SRichard Henderson #endif
5119813da627SRichard Henderson 
5120813da627SRichard Henderson     one_entry.symfile_addr = img;
5121813da627SRichard Henderson     one_entry.symfile_size = img_size;
5122813da627SRichard Henderson 
5123813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
5124813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
5125813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
5126813da627SRichard Henderson     __jit_debug_register_code();
5127813da627SRichard Henderson }
5128813da627SRichard Henderson #else
51295872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
51305872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
5131813da627SRichard Henderson 
5132755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
51332c90784aSRichard Henderson                                  const void *debug_frame,
51342c90784aSRichard Henderson                                  size_t debug_frame_size)
5135813da627SRichard Henderson {
5136813da627SRichard Henderson }
5137813da627SRichard Henderson 
5138755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size)
5139813da627SRichard Henderson {
5140813da627SRichard Henderson }
5141813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
5142db432672SRichard Henderson 
5143db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
5144db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
5145db432672SRichard Henderson {
5146db432672SRichard Henderson     g_assert_not_reached();
5147db432672SRichard Henderson }
5148db432672SRichard Henderson #endif
5149