xref: /qemu/tcg/tcg.c (revision 9da6079b2695dcffd8b18890db6cafdf4dc373db)
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);
108cf7d6b8eSRichard Henderson static void tcg_out_goto_tb(TCGContext *s, int which);
1095e8892dbSMiroslav Rezanina static void tcg_out_op(TCGContext *s, TCGOpcode opc,
1105e8892dbSMiroslav Rezanina                        const TCGArg args[TCG_MAX_OP_ARGS],
1115e8892dbSMiroslav Rezanina                        const int const_args[TCG_MAX_OP_ARGS]);
112d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec
113e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
114e7632cfaSRichard Henderson                             TCGReg dst, TCGReg src);
115d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
116d6ecb4a9SRichard Henderson                              TCGReg dst, TCGReg base, intptr_t offset);
1174e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1184e186175SRichard Henderson                              TCGReg dst, int64_t arg);
1195e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1205e8892dbSMiroslav Rezanina                            unsigned vecl, unsigned vece,
1215e8892dbSMiroslav Rezanina                            const TCGArg args[TCG_MAX_OP_ARGS],
1225e8892dbSMiroslav Rezanina                            const int const_args[TCG_MAX_OP_ARGS]);
123d2fd745fSRichard Henderson #else
124e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
125e7632cfaSRichard Henderson                                    TCGReg dst, TCGReg src)
126e7632cfaSRichard Henderson {
127e7632cfaSRichard Henderson     g_assert_not_reached();
128e7632cfaSRichard Henderson }
129d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
130d6ecb4a9SRichard Henderson                                     TCGReg dst, TCGReg base, intptr_t offset)
131d6ecb4a9SRichard Henderson {
132d6ecb4a9SRichard Henderson     g_assert_not_reached();
133d6ecb4a9SRichard Henderson }
1344e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1354e186175SRichard Henderson                                     TCGReg dst, int64_t arg)
136e7632cfaSRichard Henderson {
137e7632cfaSRichard Henderson     g_assert_not_reached();
138e7632cfaSRichard Henderson }
1395e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1405e8892dbSMiroslav Rezanina                                   unsigned vecl, unsigned vece,
1415e8892dbSMiroslav Rezanina                                   const TCGArg args[TCG_MAX_OP_ARGS],
1425e8892dbSMiroslav Rezanina                                   const int const_args[TCG_MAX_OP_ARGS])
143d2fd745fSRichard Henderson {
144d2fd745fSRichard Henderson     g_assert_not_reached();
145d2fd745fSRichard Henderson }
146d2fd745fSRichard Henderson #endif
1472a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
148a05b5b9bSRichard Henderson                        intptr_t arg2);
14959d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
15059d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
1517b7d8b2dSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target,
152cee44b03SRichard Henderson                          const TCGHelperInfo *info);
153a4fbbd77SRichard Henderson static bool tcg_target_const_match(int64_t val, TCGType type, int ct);
154659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
155aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s);
156659ef5cbSRichard Henderson #endif
157c896fe29Sbellard 
15842eb6dfcSRichard Henderson TCGContext tcg_init_ctx;
15942eb6dfcSRichard Henderson __thread TCGContext *tcg_ctx;
16042eb6dfcSRichard Henderson 
1615ff7258cSRichard Henderson TCGContext **tcg_ctxs;
1620e2d61cfSRichard Henderson unsigned int tcg_cur_ctxs;
1630e2d61cfSRichard Henderson unsigned int tcg_max_ctxs;
1641c2adb95SRichard Henderson TCGv_env cpu_env = 0;
165c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue;
166db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff;
167df2cce29SEmilio G. Cota 
168b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
169b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec;
170b91ccb31SRichard Henderson #endif
171b91ccb31SRichard Henderson 
172d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
173b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
174c896fe29Sbellard 
1751813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
1764196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
177c896fe29Sbellard {
178c896fe29Sbellard     *s->code_ptr++ = v;
179c896fe29Sbellard }
180c896fe29Sbellard 
1814196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
1824196dca6SPeter Maydell                                                       uint8_t v)
1835c53bb81SPeter Maydell {
1841813e175SRichard Henderson     *p = v;
1855c53bb81SPeter Maydell }
1861813e175SRichard Henderson #endif
1875c53bb81SPeter Maydell 
1881813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
1894196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
190c896fe29Sbellard {
1911813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
1921813e175SRichard Henderson         *s->code_ptr++ = v;
1931813e175SRichard Henderson     } else {
1941813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
1954387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
1961813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
1971813e175SRichard Henderson     }
198c896fe29Sbellard }
199c896fe29Sbellard 
2004196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2014196dca6SPeter Maydell                                                        uint16_t v)
2025c53bb81SPeter Maydell {
2031813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2041813e175SRichard Henderson         *p = v;
2051813e175SRichard Henderson     } else {
2065c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2075c53bb81SPeter Maydell     }
2081813e175SRichard Henderson }
2091813e175SRichard Henderson #endif
2105c53bb81SPeter Maydell 
2111813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
2124196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
213c896fe29Sbellard {
2141813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2151813e175SRichard Henderson         *s->code_ptr++ = v;
2161813e175SRichard Henderson     } else {
2171813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2184387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2191813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
2201813e175SRichard Henderson     }
221c896fe29Sbellard }
222c896fe29Sbellard 
2234196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
2244196dca6SPeter Maydell                                                        uint32_t v)
2255c53bb81SPeter Maydell {
2261813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2271813e175SRichard Henderson         *p = v;
2281813e175SRichard Henderson     } else {
2295c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2305c53bb81SPeter Maydell     }
2311813e175SRichard Henderson }
2321813e175SRichard Henderson #endif
2335c53bb81SPeter Maydell 
2341813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
2354196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
236ac26eb69SRichard Henderson {
2371813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2381813e175SRichard Henderson         *s->code_ptr++ = v;
2391813e175SRichard Henderson     } else {
2401813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2414387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2421813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
2431813e175SRichard Henderson     }
244ac26eb69SRichard Henderson }
245ac26eb69SRichard Henderson 
2464196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
2474196dca6SPeter Maydell                                                        uint64_t v)
2485c53bb81SPeter Maydell {
2491813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2501813e175SRichard Henderson         *p = v;
2511813e175SRichard Henderson     } else {
2525c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2535c53bb81SPeter Maydell     }
2541813e175SRichard Henderson }
2551813e175SRichard Henderson #endif
2565c53bb81SPeter Maydell 
257c896fe29Sbellard /* label relocation processing */
258c896fe29Sbellard 
2591813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
260bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
261c896fe29Sbellard {
2627ecd02a0SRichard Henderson     TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation));
263c896fe29Sbellard 
264c896fe29Sbellard     r->type = type;
265c896fe29Sbellard     r->ptr = code_ptr;
266c896fe29Sbellard     r->addend = addend;
2677ecd02a0SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
268c896fe29Sbellard }
269c896fe29Sbellard 
27092ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l)
271c896fe29Sbellard {
272eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
273c896fe29Sbellard     l->has_value = 1;
27492ab8e7dSRichard Henderson     l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr);
275c896fe29Sbellard }
276c896fe29Sbellard 
27742a268c2SRichard Henderson TCGLabel *gen_new_label(void)
278c896fe29Sbellard {
279b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
28051e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
281c896fe29Sbellard 
2827ecd02a0SRichard Henderson     memset(l, 0, sizeof(TCGLabel));
2837ecd02a0SRichard Henderson     l->id = s->nb_labels++;
2847ecd02a0SRichard Henderson     QSIMPLEQ_INIT(&l->relocs);
2857ecd02a0SRichard Henderson 
286bef16ab4SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
28742a268c2SRichard Henderson 
28842a268c2SRichard Henderson     return l;
289c896fe29Sbellard }
290c896fe29Sbellard 
2917ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s)
2927ecd02a0SRichard Henderson {
2937ecd02a0SRichard Henderson     TCGLabel *l;
2947ecd02a0SRichard Henderson 
2957ecd02a0SRichard Henderson     QSIMPLEQ_FOREACH(l, &s->labels, next) {
2967ecd02a0SRichard Henderson         TCGRelocation *r;
2977ecd02a0SRichard Henderson         uintptr_t value = l->u.value;
2987ecd02a0SRichard Henderson 
2997ecd02a0SRichard Henderson         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
3007ecd02a0SRichard Henderson             if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
3017ecd02a0SRichard Henderson                 return false;
3027ecd02a0SRichard Henderson             }
3037ecd02a0SRichard Henderson         }
3047ecd02a0SRichard Henderson     }
3057ecd02a0SRichard Henderson     return true;
3067ecd02a0SRichard Henderson }
3077ecd02a0SRichard Henderson 
3089f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3099f754620SRichard Henderson {
310f14bed3fSRichard Henderson     /*
311f14bed3fSRichard Henderson      * We will check for overflow at the end of the opcode loop in
312f14bed3fSRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
313f14bed3fSRichard Henderson      */
314b7e4afbdSRichard Henderson     s->gen_tb->jmp_reset_offset[which] = tcg_current_code_size(s);
3159f754620SRichard Henderson }
3169f754620SRichard Henderson 
317b52a2c03SRichard Henderson static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which)
318b52a2c03SRichard Henderson {
319b52a2c03SRichard Henderson     /*
320b52a2c03SRichard Henderson      * We will check for overflow at the end of the opcode loop in
321b52a2c03SRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
322b52a2c03SRichard Henderson      */
323b52a2c03SRichard Henderson     tcg_debug_assert(TCG_TARGET_HAS_direct_jump);
324*9da6079bSRichard Henderson     s->gen_tb->jmp_insn_offset[which] = tcg_current_code_size(s);
325b52a2c03SRichard Henderson }
326b52a2c03SRichard Henderson 
327becc452aSRichard Henderson static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which)
328becc452aSRichard Henderson {
329becc452aSRichard Henderson     /*
330becc452aSRichard Henderson      * Return the read-execute version of the pointer, for the benefit
331becc452aSRichard Henderson      * of any pc-relative addressing mode.
332becc452aSRichard Henderson      */
333*9da6079bSRichard Henderson     return (uintptr_t)tcg_splitwx_to_rx(&s->gen_tb->jmp_target_addr[which]);
334becc452aSRichard Henderson }
335becc452aSRichard Henderson 
336db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */
3378905770bSMarc-André Lureau static G_NORETURN
3388905770bSMarc-André Lureau void tcg_raise_tb_overflow(TCGContext *s)
339db6b7d0cSRichard Henderson {
340db6b7d0cSRichard Henderson     siglongjmp(s->jmp_trans, -2);
341db6b7d0cSRichard Henderson }
342db6b7d0cSRichard Henderson 
3434c22e840SRichard Henderson #define C_PFX1(P, A)                    P##A
3444c22e840SRichard Henderson #define C_PFX2(P, A, B)                 P##A##_##B
3454c22e840SRichard Henderson #define C_PFX3(P, A, B, C)              P##A##_##B##_##C
3464c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D)           P##A##_##B##_##C##_##D
3474c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E)        P##A##_##B##_##C##_##D##_##E
3484c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F)     P##A##_##B##_##C##_##D##_##E##_##F
3494c22e840SRichard Henderson 
3504c22e840SRichard Henderson /* Define an enumeration for the various combinations. */
3514c22e840SRichard Henderson 
3524c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1),
3534c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2),
3544c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3),
3554c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4),
3564c22e840SRichard Henderson 
3574c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1),
3584c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2),
3594c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3),
3604c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4),
3614c22e840SRichard Henderson 
3624c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2),
3634c22e840SRichard Henderson 
3644c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1),
3654c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2),
3664c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3),
3674c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4),
3684c22e840SRichard Henderson 
3694c22e840SRichard Henderson typedef enum {
3704c22e840SRichard Henderson #include "tcg-target-con-set.h"
3714c22e840SRichard Henderson } TCGConstraintSetIndex;
3724c22e840SRichard Henderson 
3734c22e840SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode);
3744c22e840SRichard Henderson 
3754c22e840SRichard Henderson #undef C_O0_I1
3764c22e840SRichard Henderson #undef C_O0_I2
3774c22e840SRichard Henderson #undef C_O0_I3
3784c22e840SRichard Henderson #undef C_O0_I4
3794c22e840SRichard Henderson #undef C_O1_I1
3804c22e840SRichard Henderson #undef C_O1_I2
3814c22e840SRichard Henderson #undef C_O1_I3
3824c22e840SRichard Henderson #undef C_O1_I4
3834c22e840SRichard Henderson #undef C_N1_I2
3844c22e840SRichard Henderson #undef C_O2_I1
3854c22e840SRichard Henderson #undef C_O2_I2
3864c22e840SRichard Henderson #undef C_O2_I3
3874c22e840SRichard Henderson #undef C_O2_I4
3884c22e840SRichard Henderson 
3894c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */
3904c22e840SRichard Henderson 
3914c22e840SRichard Henderson #define C_O0_I1(I1)                     { .args_ct_str = { #I1 } },
3924c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 { .args_ct_str = { #I1, #I2 } },
3934c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             { .args_ct_str = { #I1, #I2, #I3 } },
3944c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         { .args_ct_str = { #I1, #I2, #I3, #I4 } },
3954c22e840SRichard Henderson 
3964c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 { .args_ct_str = { #O1, #I1 } },
3974c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             { .args_ct_str = { #O1, #I1, #I2 } },
3984c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         { .args_ct_str = { #O1, #I1, #I2, #I3 } },
3994c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } },
4004c22e840SRichard Henderson 
4014c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             { .args_ct_str = { "&" #O1, #I1, #I2 } },
4024c22e840SRichard Henderson 
4034c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             { .args_ct_str = { #O1, #O2, #I1 } },
4044c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         { .args_ct_str = { #O1, #O2, #I1, #I2 } },
4054c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } },
4064c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } },
4074c22e840SRichard Henderson 
4084c22e840SRichard Henderson static const TCGTargetOpDef constraint_sets[] = {
4094c22e840SRichard Henderson #include "tcg-target-con-set.h"
4104c22e840SRichard Henderson };
4114c22e840SRichard Henderson 
4124c22e840SRichard Henderson 
4134c22e840SRichard Henderson #undef C_O0_I1
4144c22e840SRichard Henderson #undef C_O0_I2
4154c22e840SRichard Henderson #undef C_O0_I3
4164c22e840SRichard Henderson #undef C_O0_I4
4174c22e840SRichard Henderson #undef C_O1_I1
4184c22e840SRichard Henderson #undef C_O1_I2
4194c22e840SRichard Henderson #undef C_O1_I3
4204c22e840SRichard Henderson #undef C_O1_I4
4214c22e840SRichard Henderson #undef C_N1_I2
4224c22e840SRichard Henderson #undef C_O2_I1
4234c22e840SRichard Henderson #undef C_O2_I2
4244c22e840SRichard Henderson #undef C_O2_I3
4254c22e840SRichard Henderson #undef C_O2_I4
4264c22e840SRichard Henderson 
4274c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */
4284c22e840SRichard Henderson 
4294c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1)
4304c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2)
4314c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3)
4324c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4)
4334c22e840SRichard Henderson 
4344c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1)
4354c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2)
4364c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3)
4374c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4)
4384c22e840SRichard Henderson 
4394c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2)
4404c22e840SRichard Henderson 
4414c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1)
4424c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2)
4434c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3)
4444c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4)
4454c22e840SRichard Henderson 
446139c1837SPaolo Bonzini #include "tcg-target.c.inc"
447c896fe29Sbellard 
44838b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s)
44938b47b19SEmilio G. Cota {
45038b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
45138b47b19SEmilio G. Cota     s->plugin_tb = g_new0(struct qemu_plugin_tb, 1);
45238b47b19SEmilio G. Cota     s->plugin_tb->insns =
45338b47b19SEmilio G. Cota         g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn);
45438b47b19SEmilio G. Cota #endif
45538b47b19SEmilio G. Cota }
45638b47b19SEmilio G. Cota 
457e8feb96fSEmilio G. Cota /*
4583468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
4593468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
4603468b59eSEmilio G. Cota  * before initiating translation.
4613468b59eSEmilio G. Cota  *
4623468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
4633468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
4643468b59eSEmilio G. Cota  *
4653468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
4663468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
4673468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
4683468b59eSEmilio G. Cota  *
4693468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
4703468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
4713468b59eSEmilio G. Cota  */
4723468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
4733468b59eSEmilio G. Cota void tcg_register_thread(void)
4743468b59eSEmilio G. Cota {
4753468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
4763468b59eSEmilio G. Cota }
4773468b59eSEmilio G. Cota #else
4783468b59eSEmilio G. Cota void tcg_register_thread(void)
4793468b59eSEmilio G. Cota {
4803468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
4813468b59eSEmilio G. Cota     unsigned int i, n;
4823468b59eSEmilio G. Cota 
4833468b59eSEmilio G. Cota     *s = tcg_init_ctx;
4843468b59eSEmilio G. Cota 
4853468b59eSEmilio G. Cota     /* Relink mem_base.  */
4863468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
4873468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
4883468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
4893468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
4903468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
4913468b59eSEmilio G. Cota         }
4923468b59eSEmilio G. Cota     }
4933468b59eSEmilio G. Cota 
4943468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
4950e2d61cfSRichard Henderson     n = qatomic_fetch_inc(&tcg_cur_ctxs);
4960e2d61cfSRichard Henderson     g_assert(n < tcg_max_ctxs);
497d73415a3SStefan Hajnoczi     qatomic_set(&tcg_ctxs[n], s);
4983468b59eSEmilio G. Cota 
49938b47b19SEmilio G. Cota     if (n > 0) {
50038b47b19SEmilio G. Cota         alloc_tcg_plugin_context(s);
501bf042e8eSRichard Henderson         tcg_region_initial_alloc(s);
50238b47b19SEmilio G. Cota     }
50338b47b19SEmilio G. Cota 
5043468b59eSEmilio G. Cota     tcg_ctx = s;
5053468b59eSEmilio G. Cota }
5063468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
5073468b59eSEmilio G. Cota 
508c896fe29Sbellard /* pool based memory allocation */
509c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
510c896fe29Sbellard {
511c896fe29Sbellard     TCGPool *p;
512c896fe29Sbellard     int pool_size;
513c896fe29Sbellard 
514c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
515c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
5167267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
517c896fe29Sbellard         p->size = size;
5184055299eSKirill Batuzov         p->next = s->pool_first_large;
5194055299eSKirill Batuzov         s->pool_first_large = p;
5204055299eSKirill Batuzov         return p->data;
521c896fe29Sbellard     } else {
522c896fe29Sbellard         p = s->pool_current;
523c896fe29Sbellard         if (!p) {
524c896fe29Sbellard             p = s->pool_first;
525c896fe29Sbellard             if (!p)
526c896fe29Sbellard                 goto new_pool;
527c896fe29Sbellard         } else {
528c896fe29Sbellard             if (!p->next) {
529c896fe29Sbellard             new_pool:
530c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
5317267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
532c896fe29Sbellard                 p->size = pool_size;
533c896fe29Sbellard                 p->next = NULL;
534a813e36fSRichard Henderson                 if (s->pool_current) {
535c896fe29Sbellard                     s->pool_current->next = p;
536a813e36fSRichard Henderson                 } else {
537c896fe29Sbellard                     s->pool_first = p;
538a813e36fSRichard Henderson                 }
539c896fe29Sbellard             } else {
540c896fe29Sbellard                 p = p->next;
541c896fe29Sbellard             }
542c896fe29Sbellard         }
543c896fe29Sbellard     }
544c896fe29Sbellard     s->pool_current = p;
545c896fe29Sbellard     s->pool_cur = p->data + size;
546c896fe29Sbellard     s->pool_end = p->data + p->size;
547c896fe29Sbellard     return p->data;
548c896fe29Sbellard }
549c896fe29Sbellard 
550c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
551c896fe29Sbellard {
5524055299eSKirill Batuzov     TCGPool *p, *t;
5534055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
5544055299eSKirill Batuzov         t = p->next;
5554055299eSKirill Batuzov         g_free(p);
5564055299eSKirill Batuzov     }
5574055299eSKirill Batuzov     s->pool_first_large = NULL;
558c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
559c896fe29Sbellard     s->pool_current = NULL;
560c896fe29Sbellard }
561c896fe29Sbellard 
5622ef6175aSRichard Henderson #include "exec/helper-proto.h"
5632ef6175aSRichard Henderson 
56439004a71SRichard Henderson static TCGHelperInfo all_helpers[] = {
5652ef6175aSRichard Henderson #include "exec/helper-tcg.h"
566100b5e01SRichard Henderson };
567619205fdSEmilio G. Cota static GHashTable *helper_table;
568100b5e01SRichard Henderson 
56922f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
570c6ef8c7bSPhilippe Mathieu-Daudé static ffi_type *typecode_to_ffi(int argmask)
571c6ef8c7bSPhilippe Mathieu-Daudé {
572c6ef8c7bSPhilippe Mathieu-Daudé     switch (argmask) {
573c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_void:
574c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_void;
575c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_i32:
576c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_uint32;
577c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_s32:
578c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_sint32;
579c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_i64:
580c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_uint64;
581c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_s64:
582c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_sint64;
583c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_ptr:
584c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_pointer;
585c6ef8c7bSPhilippe Mathieu-Daudé     }
586c6ef8c7bSPhilippe Mathieu-Daudé     g_assert_not_reached();
587c6ef8c7bSPhilippe Mathieu-Daudé }
5880c22e176SPhilippe Mathieu-Daudé 
5890c22e176SPhilippe Mathieu-Daudé static void init_ffi_layouts(void)
5900c22e176SPhilippe Mathieu-Daudé {
5910c22e176SPhilippe Mathieu-Daudé     /* g_direct_hash/equal for direct comparisons on uint32_t.  */
592f9c4bb80SRichard Henderson     GHashTable *ffi_table = g_hash_table_new(NULL, NULL);
593f9c4bb80SRichard Henderson 
5940c22e176SPhilippe Mathieu-Daudé     for (int i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
595f9c4bb80SRichard Henderson         TCGHelperInfo *info = &all_helpers[i];
596f9c4bb80SRichard Henderson         unsigned typemask = info->typemask;
5970c22e176SPhilippe Mathieu-Daudé         gpointer hash = (gpointer)(uintptr_t)typemask;
5980c22e176SPhilippe Mathieu-Daudé         struct {
5990c22e176SPhilippe Mathieu-Daudé             ffi_cif cif;
6000c22e176SPhilippe Mathieu-Daudé             ffi_type *args[];
6010c22e176SPhilippe Mathieu-Daudé         } *ca;
6020c22e176SPhilippe Mathieu-Daudé         ffi_status status;
6030c22e176SPhilippe Mathieu-Daudé         int nargs;
604f9c4bb80SRichard Henderson         ffi_cif *cif;
6050c22e176SPhilippe Mathieu-Daudé 
606f9c4bb80SRichard Henderson         cif = g_hash_table_lookup(ffi_table, hash);
607f9c4bb80SRichard Henderson         if (cif) {
608f9c4bb80SRichard Henderson             info->cif = cif;
6090c22e176SPhilippe Mathieu-Daudé             continue;
6100c22e176SPhilippe Mathieu-Daudé         }
6110c22e176SPhilippe Mathieu-Daudé 
6120c22e176SPhilippe Mathieu-Daudé         /* Ignoring the return type, find the last non-zero field. */
6130c22e176SPhilippe Mathieu-Daudé         nargs = 32 - clz32(typemask >> 3);
6140c22e176SPhilippe Mathieu-Daudé         nargs = DIV_ROUND_UP(nargs, 3);
6150c22e176SPhilippe Mathieu-Daudé 
6160c22e176SPhilippe Mathieu-Daudé         ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *));
6170c22e176SPhilippe Mathieu-Daudé         ca->cif.rtype = typecode_to_ffi(typemask & 7);
6180c22e176SPhilippe Mathieu-Daudé         ca->cif.nargs = nargs;
6190c22e176SPhilippe Mathieu-Daudé 
6200c22e176SPhilippe Mathieu-Daudé         if (nargs != 0) {
6210c22e176SPhilippe Mathieu-Daudé             ca->cif.arg_types = ca->args;
6220c22e176SPhilippe Mathieu-Daudé             for (int j = 0; j < nargs; ++j) {
6230c22e176SPhilippe Mathieu-Daudé                 int typecode = extract32(typemask, (j + 1) * 3, 3);
6240c22e176SPhilippe Mathieu-Daudé                 ca->args[j] = typecode_to_ffi(typecode);
6250c22e176SPhilippe Mathieu-Daudé             }
6260c22e176SPhilippe Mathieu-Daudé         }
6270c22e176SPhilippe Mathieu-Daudé 
6280c22e176SPhilippe Mathieu-Daudé         status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs,
6290c22e176SPhilippe Mathieu-Daudé                               ca->cif.rtype, ca->cif.arg_types);
6300c22e176SPhilippe Mathieu-Daudé         assert(status == FFI_OK);
6310c22e176SPhilippe Mathieu-Daudé 
632f9c4bb80SRichard Henderson         cif = &ca->cif;
633f9c4bb80SRichard Henderson         info->cif = cif;
634f9c4bb80SRichard Henderson         g_hash_table_insert(ffi_table, hash, (gpointer)cif);
6350c22e176SPhilippe Mathieu-Daudé     }
636f9c4bb80SRichard Henderson 
637f9c4bb80SRichard Henderson     g_hash_table_destroy(ffi_table);
6380c22e176SPhilippe Mathieu-Daudé }
6390c22e176SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG_INTERPRETER */
64022f15579SRichard Henderson 
64139004a71SRichard Henderson typedef struct TCGCumulativeArgs {
64239004a71SRichard Henderson     int arg_idx;                /* tcg_gen_callN args[] */
64339004a71SRichard Henderson     int info_in_idx;            /* TCGHelperInfo in[] */
64439004a71SRichard Henderson     int arg_slot;               /* regs+stack slot */
64539004a71SRichard Henderson     int ref_slot;               /* stack slots for references */
64639004a71SRichard Henderson } TCGCumulativeArgs;
64739004a71SRichard Henderson 
64839004a71SRichard Henderson static void layout_arg_even(TCGCumulativeArgs *cum)
64939004a71SRichard Henderson {
65039004a71SRichard Henderson     cum->arg_slot += cum->arg_slot & 1;
65139004a71SRichard Henderson }
65239004a71SRichard Henderson 
65339004a71SRichard Henderson static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info,
65439004a71SRichard Henderson                          TCGCallArgumentKind kind)
65539004a71SRichard Henderson {
65639004a71SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
65739004a71SRichard Henderson 
65839004a71SRichard Henderson     *loc = (TCGCallArgumentLoc){
65939004a71SRichard Henderson         .kind = kind,
66039004a71SRichard Henderson         .arg_idx = cum->arg_idx,
66139004a71SRichard Henderson         .arg_slot = cum->arg_slot,
66239004a71SRichard Henderson     };
66339004a71SRichard Henderson     cum->info_in_idx++;
66439004a71SRichard Henderson     cum->arg_slot++;
66539004a71SRichard Henderson }
66639004a71SRichard Henderson 
66739004a71SRichard Henderson static void layout_arg_normal_n(TCGCumulativeArgs *cum,
66839004a71SRichard Henderson                                 TCGHelperInfo *info, int n)
66939004a71SRichard Henderson {
67039004a71SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
67139004a71SRichard Henderson 
67239004a71SRichard Henderson     for (int i = 0; i < n; ++i) {
67339004a71SRichard Henderson         /* Layout all using the same arg_idx, adjusting the subindex. */
67439004a71SRichard Henderson         loc[i] = (TCGCallArgumentLoc){
67539004a71SRichard Henderson             .kind = TCG_CALL_ARG_NORMAL,
67639004a71SRichard Henderson             .arg_idx = cum->arg_idx,
67739004a71SRichard Henderson             .tmp_subindex = i,
67839004a71SRichard Henderson             .arg_slot = cum->arg_slot + i,
67939004a71SRichard Henderson         };
68039004a71SRichard Henderson     }
68139004a71SRichard Henderson     cum->info_in_idx += n;
68239004a71SRichard Henderson     cum->arg_slot += n;
68339004a71SRichard Henderson }
68439004a71SRichard Henderson 
68539004a71SRichard Henderson static void init_call_layout(TCGHelperInfo *info)
68639004a71SRichard Henderson {
68739004a71SRichard Henderson     int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs);
68839004a71SRichard Henderson     int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long);
68939004a71SRichard Henderson     unsigned typemask = info->typemask;
69039004a71SRichard Henderson     unsigned typecode;
69139004a71SRichard Henderson     TCGCumulativeArgs cum = { };
69239004a71SRichard Henderson 
69339004a71SRichard Henderson     /*
69439004a71SRichard Henderson      * Parse and place any function return value.
69539004a71SRichard Henderson      */
69639004a71SRichard Henderson     typecode = typemask & 7;
69739004a71SRichard Henderson     switch (typecode) {
69839004a71SRichard Henderson     case dh_typecode_void:
69939004a71SRichard Henderson         info->nr_out = 0;
70039004a71SRichard Henderson         break;
70139004a71SRichard Henderson     case dh_typecode_i32:
70239004a71SRichard Henderson     case dh_typecode_s32:
70339004a71SRichard Henderson     case dh_typecode_ptr:
70439004a71SRichard Henderson         info->nr_out = 1;
70539004a71SRichard Henderson         info->out_kind = TCG_CALL_RET_NORMAL;
70639004a71SRichard Henderson         break;
70739004a71SRichard Henderson     case dh_typecode_i64:
70839004a71SRichard Henderson     case dh_typecode_s64:
70939004a71SRichard Henderson         info->nr_out = 64 / TCG_TARGET_REG_BITS;
71039004a71SRichard Henderson         info->out_kind = TCG_CALL_RET_NORMAL;
71139004a71SRichard Henderson         break;
71239004a71SRichard Henderson     default:
71339004a71SRichard Henderson         g_assert_not_reached();
71439004a71SRichard Henderson     }
71539004a71SRichard Henderson     assert(info->nr_out <= ARRAY_SIZE(tcg_target_call_oarg_regs));
71639004a71SRichard Henderson 
71739004a71SRichard Henderson     /*
71839004a71SRichard Henderson      * Parse and place function arguments.
71939004a71SRichard Henderson      */
72039004a71SRichard Henderson     for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) {
72139004a71SRichard Henderson         TCGCallArgumentKind kind;
72239004a71SRichard Henderson         TCGType type;
72339004a71SRichard Henderson 
72439004a71SRichard Henderson         typecode = typemask & 7;
72539004a71SRichard Henderson         switch (typecode) {
72639004a71SRichard Henderson         case dh_typecode_i32:
72739004a71SRichard Henderson         case dh_typecode_s32:
72839004a71SRichard Henderson             type = TCG_TYPE_I32;
72939004a71SRichard Henderson             break;
73039004a71SRichard Henderson         case dh_typecode_i64:
73139004a71SRichard Henderson         case dh_typecode_s64:
73239004a71SRichard Henderson             type = TCG_TYPE_I64;
73339004a71SRichard Henderson             break;
73439004a71SRichard Henderson         case dh_typecode_ptr:
73539004a71SRichard Henderson             type = TCG_TYPE_PTR;
73639004a71SRichard Henderson             break;
73739004a71SRichard Henderson         default:
73839004a71SRichard Henderson             g_assert_not_reached();
73939004a71SRichard Henderson         }
74039004a71SRichard Henderson 
74139004a71SRichard Henderson         switch (type) {
74239004a71SRichard Henderson         case TCG_TYPE_I32:
74339004a71SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I32) {
74439004a71SRichard Henderson             case TCG_CALL_ARG_EVEN:
74539004a71SRichard Henderson                 layout_arg_even(&cum);
74639004a71SRichard Henderson                 /* fall through */
74739004a71SRichard Henderson             case TCG_CALL_ARG_NORMAL:
74839004a71SRichard Henderson                 layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
74939004a71SRichard Henderson                 break;
75039004a71SRichard Henderson             case TCG_CALL_ARG_EXTEND:
75139004a71SRichard Henderson                 kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1);
75239004a71SRichard Henderson                 layout_arg_1(&cum, info, kind);
75339004a71SRichard Henderson                 break;
75439004a71SRichard Henderson             default:
75539004a71SRichard Henderson                 qemu_build_not_reached();
75639004a71SRichard Henderson             }
75739004a71SRichard Henderson             break;
75839004a71SRichard Henderson 
75939004a71SRichard Henderson         case TCG_TYPE_I64:
76039004a71SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I64) {
76139004a71SRichard Henderson             case TCG_CALL_ARG_EVEN:
76239004a71SRichard Henderson                 layout_arg_even(&cum);
76339004a71SRichard Henderson                 /* fall through */
76439004a71SRichard Henderson             case TCG_CALL_ARG_NORMAL:
76539004a71SRichard Henderson                 if (TCG_TARGET_REG_BITS == 32) {
76639004a71SRichard Henderson                     layout_arg_normal_n(&cum, info, 2);
76739004a71SRichard Henderson                 } else {
76839004a71SRichard Henderson                     layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
76939004a71SRichard Henderson                 }
77039004a71SRichard Henderson                 break;
77139004a71SRichard Henderson             default:
77239004a71SRichard Henderson                 qemu_build_not_reached();
77339004a71SRichard Henderson             }
77439004a71SRichard Henderson             break;
77539004a71SRichard Henderson 
77639004a71SRichard Henderson         default:
77739004a71SRichard Henderson             g_assert_not_reached();
77839004a71SRichard Henderson         }
77939004a71SRichard Henderson     }
78039004a71SRichard Henderson     info->nr_in = cum.info_in_idx;
78139004a71SRichard Henderson 
78239004a71SRichard Henderson     /* Validate that we didn't overrun the input array. */
78339004a71SRichard Henderson     assert(cum.info_in_idx <= ARRAY_SIZE(info->in));
78439004a71SRichard Henderson     /* Validate the backend has enough argument space. */
78539004a71SRichard Henderson     assert(cum.arg_slot <= max_reg_slots + max_stk_slots);
78639004a71SRichard Henderson     assert(cum.ref_slot <= max_stk_slots);
78739004a71SRichard Henderson }
78839004a71SRichard Henderson 
78991478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
790f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
7911c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
7921c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
79391478cefSRichard Henderson 
79443b972b7SRichard Henderson static void tcg_context_init(unsigned max_cpus)
795c896fe29Sbellard {
796a76aabd3SRichard Henderson     TCGContext *s = &tcg_init_ctx;
797100b5e01SRichard Henderson     int op, total_args, n, i;
798c896fe29Sbellard     TCGOpDef *def;
799c896fe29Sbellard     TCGArgConstraint *args_ct;
8001c2adb95SRichard Henderson     TCGTemp *ts;
801c896fe29Sbellard 
802c896fe29Sbellard     memset(s, 0, sizeof(*s));
803c896fe29Sbellard     s->nb_globals = 0;
804c896fe29Sbellard 
805c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
806c896fe29Sbellard        space */
807c896fe29Sbellard     total_args = 0;
808c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
809c896fe29Sbellard         def = &tcg_op_defs[op];
810c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
811c896fe29Sbellard         total_args += n;
812c896fe29Sbellard     }
813c896fe29Sbellard 
814bc2b17e6SRichard Henderson     args_ct = g_new0(TCGArgConstraint, total_args);
815c896fe29Sbellard 
816c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
817c896fe29Sbellard         def = &tcg_op_defs[op];
818c896fe29Sbellard         def->args_ct = args_ct;
819c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
820c896fe29Sbellard         args_ct += n;
821c896fe29Sbellard     }
822c896fe29Sbellard 
8235cd8f621SRichard Henderson     /* Register helpers.  */
82484fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
825619205fdSEmilio G. Cota     helper_table = g_hash_table_new(NULL, NULL);
82684fd9dd3SRichard Henderson 
827100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
82839004a71SRichard Henderson         init_call_layout(&all_helpers[i]);
82984fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
83072866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
831100b5e01SRichard Henderson     }
8325cd8f621SRichard Henderson 
83322f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
8340c22e176SPhilippe Mathieu-Daudé     init_ffi_layouts();
83522f15579SRichard Henderson #endif
83622f15579SRichard Henderson 
837c896fe29Sbellard     tcg_target_init(s);
838f69d277eSRichard Henderson     process_op_defs(s);
83991478cefSRichard Henderson 
84091478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
84191478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
84291478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
84391478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
84491478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
84591478cefSRichard Henderson             break;
84691478cefSRichard Henderson         }
84791478cefSRichard Henderson     }
84891478cefSRichard Henderson     for (i = 0; i < n; ++i) {
84991478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
85091478cefSRichard Henderson     }
85191478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
85291478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
85391478cefSRichard Henderson     }
854b1311c4aSEmilio G. Cota 
85538b47b19SEmilio G. Cota     alloc_tcg_plugin_context(s);
85638b47b19SEmilio G. Cota 
857b1311c4aSEmilio G. Cota     tcg_ctx = s;
8583468b59eSEmilio G. Cota     /*
8593468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
8603468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
8613468b59eSEmilio G. Cota      * reasoning behind this.
8623468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
8633468b59eSEmilio G. Cota      */
8643468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
865df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
8660e2d61cfSRichard Henderson     tcg_cur_ctxs = 1;
8670e2d61cfSRichard Henderson     tcg_max_ctxs = 1;
8683468b59eSEmilio G. Cota #else
8690e2d61cfSRichard Henderson     tcg_max_ctxs = max_cpus;
8700e2d61cfSRichard Henderson     tcg_ctxs = g_new0(TCGContext *, max_cpus);
8713468b59eSEmilio G. Cota #endif
8721c2adb95SRichard Henderson 
8731c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
8741c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
8751c2adb95SRichard Henderson     cpu_env = temp_tcgv_ptr(ts);
8769002ec79SRichard Henderson }
877b03cce8eSbellard 
87843b972b7SRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus)
879a76aabd3SRichard Henderson {
88043b972b7SRichard Henderson     tcg_context_init(max_cpus);
88143b972b7SRichard Henderson     tcg_region_init(tb_size, splitwx, max_cpus);
882a76aabd3SRichard Henderson }
883a76aabd3SRichard Henderson 
8846e3b2bfdSEmilio G. Cota /*
8856e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
8866e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
8876e3b2bfdSEmilio G. Cota  */
8886e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
8896e3b2bfdSEmilio G. Cota {
8906e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
8916e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
8926e3b2bfdSEmilio G. Cota     void *next;
8936e3b2bfdSEmilio G. Cota 
894e8feb96fSEmilio G. Cota  retry:
8956e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
8966e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
8976e3b2bfdSEmilio G. Cota 
8986e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
899e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
9006e3b2bfdSEmilio G. Cota             return NULL;
9016e3b2bfdSEmilio G. Cota         }
902e8feb96fSEmilio G. Cota         goto retry;
903e8feb96fSEmilio G. Cota     }
904d73415a3SStefan Hajnoczi     qatomic_set(&s->code_gen_ptr, next);
90557a26946SRichard Henderson     s->data_gen_ptr = NULL;
9066e3b2bfdSEmilio G. Cota     return tb;
9076e3b2bfdSEmilio G. Cota }
9086e3b2bfdSEmilio G. Cota 
9099002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
9109002ec79SRichard Henderson {
911b0a0794aSRichard Henderson     size_t prologue_size;
9128163b749SRichard Henderson 
913b0a0794aSRichard Henderson     s->code_ptr = s->code_gen_ptr;
914b0a0794aSRichard Henderson     s->code_buf = s->code_gen_ptr;
9155b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
916b91ccb31SRichard Henderson 
917b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
918b0a0794aSRichard Henderson     tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr);
919b91ccb31SRichard Henderson #endif
9208163b749SRichard Henderson 
9215b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
9225b38ee31SRichard Henderson     s->pool_labels = NULL;
9235b38ee31SRichard Henderson #endif
9245b38ee31SRichard Henderson 
925653b87ebSRoman Bolshakov     qemu_thread_jit_write();
9268163b749SRichard Henderson     /* Generate the prologue.  */
927b03cce8eSbellard     tcg_target_qemu_prologue(s);
9285b38ee31SRichard Henderson 
9295b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
9305b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
9315b38ee31SRichard Henderson     {
9321768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
9331768987bSRichard Henderson         tcg_debug_assert(result == 0);
9345b38ee31SRichard Henderson     }
9355b38ee31SRichard Henderson #endif
9365b38ee31SRichard Henderson 
937b0a0794aSRichard Henderson     prologue_size = tcg_current_code_size(s);
9385584e2dbSIlya Leoshkevich     perf_report_prologue(s->code_gen_ptr, prologue_size);
939b0a0794aSRichard Henderson 
940df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
941b0a0794aSRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
942b0a0794aSRichard Henderson                         (uintptr_t)s->code_buf, prologue_size);
943df5d2b16SRichard Henderson #endif
9448163b749SRichard Henderson 
945d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
946d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
947c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
94878b54858SRichard Henderson         if (logfile) {
94978b54858SRichard Henderson             fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size);
9505b38ee31SRichard Henderson             if (s->data_gen_ptr) {
951b0a0794aSRichard Henderson                 size_t code_size = s->data_gen_ptr - s->code_gen_ptr;
9525b38ee31SRichard Henderson                 size_t data_size = prologue_size - code_size;
9535b38ee31SRichard Henderson                 size_t i;
9545b38ee31SRichard Henderson 
95578b54858SRichard Henderson                 disas(logfile, s->code_gen_ptr, code_size);
9565b38ee31SRichard Henderson 
9575b38ee31SRichard Henderson                 for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
9585b38ee31SRichard Henderson                     if (sizeof(tcg_target_ulong) == 8) {
95978b54858SRichard Henderson                         fprintf(logfile,
96078b54858SRichard Henderson                                 "0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
9615b38ee31SRichard Henderson                                 (uintptr_t)s->data_gen_ptr + i,
9625b38ee31SRichard Henderson                                 *(uint64_t *)(s->data_gen_ptr + i));
9635b38ee31SRichard Henderson                     } else {
96478b54858SRichard Henderson                         fprintf(logfile,
96578b54858SRichard Henderson                                 "0x%08" PRIxPTR ":  .long  0x%08x\n",
9665b38ee31SRichard Henderson                                 (uintptr_t)s->data_gen_ptr + i,
9675b38ee31SRichard Henderson                                 *(uint32_t *)(s->data_gen_ptr + i));
9685b38ee31SRichard Henderson                     }
9695b38ee31SRichard Henderson                 }
9705b38ee31SRichard Henderson             } else {
97178b54858SRichard Henderson                 disas(logfile, s->code_gen_ptr, prologue_size);
9725b38ee31SRichard Henderson             }
97378b54858SRichard Henderson             fprintf(logfile, "\n");
974fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
975d6b64b2bSRichard Henderson         }
97678b54858SRichard Henderson     }
977d6b64b2bSRichard Henderson #endif
978cedbcb01SEmilio G. Cota 
9796eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
9806eea0434SRichard Henderson     /*
9816eea0434SRichard Henderson      * Assert that goto_ptr is implemented completely, setting an epilogue.
9826eea0434SRichard Henderson      * For tci, we use NULL as the signal to return from the interpreter,
9836eea0434SRichard Henderson      * so skip this check.
9846eea0434SRichard Henderson      */
9858b5c2b62SRichard Henderson     tcg_debug_assert(tcg_code_gen_epilogue != NULL);
9866eea0434SRichard Henderson #endif
987d1c74ab3SRichard Henderson 
988d1c74ab3SRichard Henderson     tcg_region_prologue_set(s);
989c896fe29Sbellard }
990c896fe29Sbellard 
991c896fe29Sbellard void tcg_func_start(TCGContext *s)
992c896fe29Sbellard {
993c896fe29Sbellard     tcg_pool_reset(s);
994c896fe29Sbellard     s->nb_temps = s->nb_globals;
9950ec9eabcSRichard Henderson 
9960ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
9970ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
9980ec9eabcSRichard Henderson 
999c0522136SRichard Henderson     /* No constant temps have been previously allocated. */
1000c0522136SRichard Henderson     for (int i = 0; i < TCG_TYPE_COUNT; ++i) {
1001c0522136SRichard Henderson         if (s->const_table[i]) {
1002c0522136SRichard Henderson             g_hash_table_remove_all(s->const_table[i]);
1003c0522136SRichard Henderson         }
1004c0522136SRichard Henderson     }
1005c0522136SRichard Henderson 
1006abebf925SRichard Henderson     s->nb_ops = 0;
1007c896fe29Sbellard     s->nb_labels = 0;
1008c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1009c896fe29Sbellard 
10100a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
10110a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
10120a209d4bSRichard Henderson #endif
10130a209d4bSRichard Henderson 
101415fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
101515fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
1016bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
1017c896fe29Sbellard }
1018c896fe29Sbellard 
1019ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s)
10207ca4b752SRichard Henderson {
10217ca4b752SRichard Henderson     int n = s->nb_temps++;
1022ae30e866SRichard Henderson 
1023ae30e866SRichard Henderson     if (n >= TCG_MAX_TEMPS) {
1024db6b7d0cSRichard Henderson         tcg_raise_tb_overflow(s);
1025ae30e866SRichard Henderson     }
10267ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
10277ca4b752SRichard Henderson }
10287ca4b752SRichard Henderson 
1029ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s)
10307ca4b752SRichard Henderson {
1031fa477d25SRichard Henderson     TCGTemp *ts;
1032fa477d25SRichard Henderson 
10337ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
1034ae30e866SRichard Henderson     tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS);
10357ca4b752SRichard Henderson     s->nb_globals++;
1036fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1037ee17db83SRichard Henderson     ts->kind = TEMP_GLOBAL;
1038fa477d25SRichard Henderson 
1039fa477d25SRichard Henderson     return ts;
1040c896fe29Sbellard }
1041c896fe29Sbellard 
1042085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1043b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1044c896fe29Sbellard {
1045c896fe29Sbellard     TCGTemp *ts;
1046c896fe29Sbellard 
1047b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
1048c896fe29Sbellard         tcg_abort();
1049b3a62939SRichard Henderson     }
10507ca4b752SRichard Henderson 
10517ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1052c896fe29Sbellard     ts->base_type = type;
1053c896fe29Sbellard     ts->type = type;
1054ee17db83SRichard Henderson     ts->kind = TEMP_FIXED;
1055c896fe29Sbellard     ts->reg = reg;
1056c896fe29Sbellard     ts->name = name;
1057c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
10587ca4b752SRichard Henderson 
1059085272b3SRichard Henderson     return ts;
1060a7812ae4Spbrook }
1061a7812ae4Spbrook 
1062b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1063a7812ae4Spbrook {
1064b3a62939SRichard Henderson     s->frame_start = start;
1065b3a62939SRichard Henderson     s->frame_end = start + size;
1066085272b3SRichard Henderson     s->frame_temp
1067085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1068b3a62939SRichard Henderson }
1069a7812ae4Spbrook 
1070085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
1071e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
1072c896fe29Sbellard {
1073b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1074dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
10757ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1076aef85402SRichard Henderson     int indirect_reg = 0;
1077c896fe29Sbellard 
1078c0522136SRichard Henderson     switch (base_ts->kind) {
1079c0522136SRichard Henderson     case TEMP_FIXED:
1080c0522136SRichard Henderson         break;
1081c0522136SRichard Henderson     case TEMP_GLOBAL:
10825a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
10835a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1084b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
10855a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
10865a18407fSRichard Henderson                             ? 2 : 1);
10875a18407fSRichard Henderson         indirect_reg = 1;
1088c0522136SRichard Henderson         break;
1089c0522136SRichard Henderson     default:
1090c0522136SRichard Henderson         g_assert_not_reached();
1091b3915dbbSRichard Henderson     }
1092b3915dbbSRichard Henderson 
10937ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
10947ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1095c896fe29Sbellard         char buf[64];
10967ca4b752SRichard Henderson 
10977ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1098c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1099b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1100c896fe29Sbellard         ts->mem_allocated = 1;
1101b3a62939SRichard Henderson         ts->mem_base = base_ts;
1102aef85402SRichard Henderson         ts->mem_offset = offset;
1103c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1104c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1105c896fe29Sbellard         ts->name = strdup(buf);
1106c896fe29Sbellard 
11077ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
11087ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
11097ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1110b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
11117ca4b752SRichard Henderson         ts2->mem_allocated = 1;
11127ca4b752SRichard Henderson         ts2->mem_base = base_ts;
1113aef85402SRichard Henderson         ts2->mem_offset = offset + 4;
1114fac87bd2SRichard Henderson         ts2->temp_subindex = 1;
1115c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1116c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1117120c1084SRichard Henderson         ts2->name = strdup(buf);
11187ca4b752SRichard Henderson     } else {
1119c896fe29Sbellard         ts->base_type = type;
1120c896fe29Sbellard         ts->type = type;
1121b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1122c896fe29Sbellard         ts->mem_allocated = 1;
1123b3a62939SRichard Henderson         ts->mem_base = base_ts;
1124c896fe29Sbellard         ts->mem_offset = offset;
1125c896fe29Sbellard         ts->name = name;
1126c896fe29Sbellard     }
1127085272b3SRichard Henderson     return ts;
1128c896fe29Sbellard }
1129c896fe29Sbellard 
11305bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local)
1131c896fe29Sbellard {
1132b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1133ee17db83SRichard Henderson     TCGTempKind kind = temp_local ? TEMP_LOCAL : TEMP_NORMAL;
1134c896fe29Sbellard     TCGTemp *ts;
1135641d5fbeSbellard     int idx, k;
1136c896fe29Sbellard 
11370ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
11380ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
11390ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
11400ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
11410ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
11420ec9eabcSRichard Henderson 
1143e8996ee0Sbellard         ts = &s->temps[idx];
1144e8996ee0Sbellard         ts->temp_allocated = 1;
11457ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
1146ee17db83SRichard Henderson         tcg_debug_assert(ts->kind == kind);
1147e8996ee0Sbellard     } else {
11487ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
11497ca4b752SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
11507ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
11517ca4b752SRichard Henderson 
1152c896fe29Sbellard             ts->base_type = type;
1153c896fe29Sbellard             ts->type = TCG_TYPE_I32;
1154e8996ee0Sbellard             ts->temp_allocated = 1;
1155ee17db83SRichard Henderson             ts->kind = kind;
11567ca4b752SRichard Henderson 
11577ca4b752SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
11587ca4b752SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
11597ca4b752SRichard Henderson             ts2->type = TCG_TYPE_I32;
11607ca4b752SRichard Henderson             ts2->temp_allocated = 1;
1161fac87bd2SRichard Henderson             ts2->temp_subindex = 1;
1162ee17db83SRichard Henderson             ts2->kind = kind;
11637ca4b752SRichard Henderson         } else {
1164c896fe29Sbellard             ts->base_type = type;
1165c896fe29Sbellard             ts->type = type;
1166e8996ee0Sbellard             ts->temp_allocated = 1;
1167ee17db83SRichard Henderson             ts->kind = kind;
1168c896fe29Sbellard         }
1169e8996ee0Sbellard     }
117027bfd83cSPeter Maydell 
117127bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
117227bfd83cSPeter Maydell     s->temps_in_use++;
117327bfd83cSPeter Maydell #endif
1174085272b3SRichard Henderson     return ts;
1175c896fe29Sbellard }
1176c896fe29Sbellard 
1177d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1178d2fd745fSRichard Henderson {
1179d2fd745fSRichard Henderson     TCGTemp *t;
1180d2fd745fSRichard Henderson 
1181d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1182d2fd745fSRichard Henderson     switch (type) {
1183d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1184d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1185d2fd745fSRichard Henderson         break;
1186d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1187d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1188d2fd745fSRichard Henderson         break;
1189d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1190d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1191d2fd745fSRichard Henderson         break;
1192d2fd745fSRichard Henderson     default:
1193d2fd745fSRichard Henderson         g_assert_not_reached();
1194d2fd745fSRichard Henderson     }
1195d2fd745fSRichard Henderson #endif
1196d2fd745fSRichard Henderson 
1197d2fd745fSRichard Henderson     t = tcg_temp_new_internal(type, 0);
1198d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1199d2fd745fSRichard Henderson }
1200d2fd745fSRichard Henderson 
1201d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1202d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1203d2fd745fSRichard Henderson {
1204d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1205d2fd745fSRichard Henderson 
1206d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1207d2fd745fSRichard Henderson 
1208d2fd745fSRichard Henderson     t = tcg_temp_new_internal(t->base_type, 0);
1209d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1210d2fd745fSRichard Henderson }
1211d2fd745fSRichard Henderson 
12125bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1213c896fe29Sbellard {
1214b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1215085272b3SRichard Henderson     int k, idx;
1216c896fe29Sbellard 
1217c7482438SRichard Henderson     switch (ts->kind) {
1218c7482438SRichard Henderson     case TEMP_CONST:
1219c7482438SRichard Henderson         /*
1220c7482438SRichard Henderson          * In order to simplify users of tcg_constant_*,
1221c7482438SRichard Henderson          * silently ignore free.
1222c7482438SRichard Henderson          */
1223c0522136SRichard Henderson         return;
1224c7482438SRichard Henderson     case TEMP_NORMAL:
1225c7482438SRichard Henderson     case TEMP_LOCAL:
1226c7482438SRichard Henderson         break;
1227c7482438SRichard Henderson     default:
1228c7482438SRichard Henderson         g_assert_not_reached();
1229c0522136SRichard Henderson     }
1230c0522136SRichard Henderson 
123127bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
123227bfd83cSPeter Maydell     s->temps_in_use--;
123327bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
123427bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
123527bfd83cSPeter Maydell     }
123627bfd83cSPeter Maydell #endif
123727bfd83cSPeter Maydell 
1238eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
1239e8996ee0Sbellard     ts->temp_allocated = 0;
12400ec9eabcSRichard Henderson 
1241085272b3SRichard Henderson     idx = temp_idx(ts);
1242ee17db83SRichard Henderson     k = ts->base_type + (ts->kind == TEMP_NORMAL ? 0 : TCG_TYPE_COUNT);
12430ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
1244e8996ee0Sbellard }
1245e8996ee0Sbellard 
1246c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val)
1247c0522136SRichard Henderson {
1248c0522136SRichard Henderson     TCGContext *s = tcg_ctx;
1249c0522136SRichard Henderson     GHashTable *h = s->const_table[type];
1250c0522136SRichard Henderson     TCGTemp *ts;
1251c0522136SRichard Henderson 
1252c0522136SRichard Henderson     if (h == NULL) {
1253c0522136SRichard Henderson         h = g_hash_table_new(g_int64_hash, g_int64_equal);
1254c0522136SRichard Henderson         s->const_table[type] = h;
1255c0522136SRichard Henderson     }
1256c0522136SRichard Henderson 
1257c0522136SRichard Henderson     ts = g_hash_table_lookup(h, &val);
1258c0522136SRichard Henderson     if (ts == NULL) {
1259aef85402SRichard Henderson         int64_t *val_ptr;
1260aef85402SRichard Henderson 
1261c0522136SRichard Henderson         ts = tcg_temp_alloc(s);
1262c0522136SRichard Henderson 
1263c0522136SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
1264c0522136SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
1265c0522136SRichard Henderson 
1266aef85402SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
1267aef85402SRichard Henderson 
1268c0522136SRichard Henderson             ts->base_type = TCG_TYPE_I64;
1269c0522136SRichard Henderson             ts->type = TCG_TYPE_I32;
1270c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1271c0522136SRichard Henderson             ts->temp_allocated = 1;
1272c0522136SRichard Henderson 
1273c0522136SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
1274c0522136SRichard Henderson             ts2->type = TCG_TYPE_I32;
1275c0522136SRichard Henderson             ts2->kind = TEMP_CONST;
1276c0522136SRichard Henderson             ts2->temp_allocated = 1;
1277fac87bd2SRichard Henderson             ts2->temp_subindex = 1;
1278aef85402SRichard Henderson 
1279aef85402SRichard Henderson             /*
1280aef85402SRichard Henderson              * Retain the full value of the 64-bit constant in the low
1281aef85402SRichard Henderson              * part, so that the hash table works.  Actual uses will
1282aef85402SRichard Henderson              * truncate the value to the low part.
1283aef85402SRichard Henderson              */
1284aef85402SRichard Henderson             ts[HOST_BIG_ENDIAN].val = val;
1285aef85402SRichard Henderson             ts[!HOST_BIG_ENDIAN].val = val >> 32;
1286aef85402SRichard Henderson             val_ptr = &ts[HOST_BIG_ENDIAN].val;
1287c0522136SRichard Henderson         } else {
1288c0522136SRichard Henderson             ts->base_type = type;
1289c0522136SRichard Henderson             ts->type = type;
1290c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1291c0522136SRichard Henderson             ts->temp_allocated = 1;
1292c0522136SRichard Henderson             ts->val = val;
1293aef85402SRichard Henderson             val_ptr = &ts->val;
1294c0522136SRichard Henderson         }
1295aef85402SRichard Henderson         g_hash_table_insert(h, val_ptr, ts);
1296c0522136SRichard Henderson     }
1297c0522136SRichard Henderson 
1298c0522136SRichard Henderson     return ts;
1299c0522136SRichard Henderson }
1300c0522136SRichard Henderson 
1301c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val)
1302c0522136SRichard Henderson {
1303c0522136SRichard Henderson     val = dup_const(vece, val);
1304c0522136SRichard Henderson     return temp_tcgv_vec(tcg_constant_internal(type, val));
1305c0522136SRichard Henderson }
1306c0522136SRichard Henderson 
130788d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val)
130888d4005bSRichard Henderson {
130988d4005bSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
131088d4005bSRichard Henderson 
131188d4005bSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
131288d4005bSRichard Henderson     return tcg_constant_vec(t->base_type, vece, val);
131388d4005bSRichard Henderson }
131488d4005bSRichard Henderson 
1315a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
1316a7812ae4Spbrook {
1317a7812ae4Spbrook     TCGv_i32 t0;
1318a7812ae4Spbrook     t0 = tcg_temp_new_i32();
1319e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
1320e8996ee0Sbellard     return t0;
1321c896fe29Sbellard }
1322c896fe29Sbellard 
1323a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
1324c896fe29Sbellard {
1325a7812ae4Spbrook     TCGv_i64 t0;
1326a7812ae4Spbrook     t0 = tcg_temp_new_i64();
1327e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
1328e8996ee0Sbellard     return t0;
1329c896fe29Sbellard }
1330c896fe29Sbellard 
1331a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
1332bdffd4a9Saurel32 {
1333a7812ae4Spbrook     TCGv_i32 t0;
1334a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
1335bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
1336bdffd4a9Saurel32     return t0;
1337bdffd4a9Saurel32 }
1338bdffd4a9Saurel32 
1339a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
1340bdffd4a9Saurel32 {
1341a7812ae4Spbrook     TCGv_i64 t0;
1342a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
1343bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
1344bdffd4a9Saurel32     return t0;
1345bdffd4a9Saurel32 }
1346bdffd4a9Saurel32 
134727bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
134827bfd83cSPeter Maydell void tcg_clear_temp_count(void)
134927bfd83cSPeter Maydell {
1350b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
135127bfd83cSPeter Maydell     s->temps_in_use = 0;
135227bfd83cSPeter Maydell }
135327bfd83cSPeter Maydell 
135427bfd83cSPeter Maydell int tcg_check_temp_count(void)
135527bfd83cSPeter Maydell {
1356b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
135727bfd83cSPeter Maydell     if (s->temps_in_use) {
135827bfd83cSPeter Maydell         /* Clear the count so that we don't give another
135927bfd83cSPeter Maydell          * warning immediately next time around.
136027bfd83cSPeter Maydell          */
136127bfd83cSPeter Maydell         s->temps_in_use = 0;
136227bfd83cSPeter Maydell         return 1;
136327bfd83cSPeter Maydell     }
136427bfd83cSPeter Maydell     return 0;
136527bfd83cSPeter Maydell }
136627bfd83cSPeter Maydell #endif
136727bfd83cSPeter Maydell 
1368be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1369be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1370be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1371be0f34b5SRichard Henderson {
1372d2fd745fSRichard Henderson     const bool have_vec
1373d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1374d2fd745fSRichard Henderson 
1375be0f34b5SRichard Henderson     switch (op) {
1376be0f34b5SRichard Henderson     case INDEX_op_discard:
1377be0f34b5SRichard Henderson     case INDEX_op_set_label:
1378be0f34b5SRichard Henderson     case INDEX_op_call:
1379be0f34b5SRichard Henderson     case INDEX_op_br:
1380be0f34b5SRichard Henderson     case INDEX_op_mb:
1381be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1382be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1383be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1384f4e01e30SRichard Henderson     case INDEX_op_goto_ptr:
1385be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i32:
1386be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i32:
1387be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i64:
1388be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i64:
1389be0f34b5SRichard Henderson         return true;
1390be0f34b5SRichard Henderson 
139107ce0b05SRichard Henderson     case INDEX_op_qemu_st8_i32:
139207ce0b05SRichard Henderson         return TCG_TARGET_HAS_qemu_st8_i32;
139307ce0b05SRichard Henderson 
1394be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1395be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1396be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1397be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1398be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1399be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1400be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1401be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1402be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1403be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1404be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1405be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1406be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1407be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1408be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1409be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1410be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1411be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1412be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1413be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1414be0f34b5SRichard Henderson         return true;
1415be0f34b5SRichard Henderson 
1416be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1417be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1418be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1419be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1420be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1421be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1422be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1423be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1424be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1425be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1426be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1427be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1428be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1429be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1430be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1431be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1432be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1433be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1434be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1435be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1436fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
1437fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
1438be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1439be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1440be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1441be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1442be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1443be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1444be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1445be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1446be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1447be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1448be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1449be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1450be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1451be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1452be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1453be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1454be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1455be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1456be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1457be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1458be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1459be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1460be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1461be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1462be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1463be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1464be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1465be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1466be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1467be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1468be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1469be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1470be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1471be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1472be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1473be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1474be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1475be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1476be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1477be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1478be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1479be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1480be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1481be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1482be0f34b5SRichard Henderson 
1483be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1484be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1485be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1486be0f34b5SRichard Henderson 
1487be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1488be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1489be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1490be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1491be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1492be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1493be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1494be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1495be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1496be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1497be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1498be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1499be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1500be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1501be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1502be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1503be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1504be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1505be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1506be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1507be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1508be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1509be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1510be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1511be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1512be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1513be0f34b5SRichard Henderson 
1514be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1515be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1516be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1517be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1518be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1519be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1520be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1521be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1522be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1523be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
1524be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
1525be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
1526be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
1527be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
1528be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
1529be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
1530be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
1531be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
1532be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
1533be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
1534fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
1535fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
1536be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
1537be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrl_i64_i32;
1538be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
1539be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrh_i64_i32;
1540be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
1541be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
1542be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
1543be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
1544be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
1545be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
1546be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
1547be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
1548be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
1549be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
1550be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
1551be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
1552be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
1553be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
1554be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
1555be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
1556be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
1557be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
1558be0f34b5SRichard Henderson     case INDEX_op_not_i64:
1559be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
1560be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
1561be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
1562be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
1563be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
1564be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
1565be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
1566be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
1567be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
1568be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
1569be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
1570be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
1571be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
1572be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
1573be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
1574be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
1575be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
1576be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
1577be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
1578be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
1579be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
1580be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
1581be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
1582be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
1583be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
1584be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
1585be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
1586be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
1587be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
1588be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
1589be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
1590be0f34b5SRichard Henderson 
1591d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
1592d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
159337ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
1594d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
1595d2fd745fSRichard Henderson     case INDEX_op_st_vec:
1596d2fd745fSRichard Henderson     case INDEX_op_add_vec:
1597d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
1598d2fd745fSRichard Henderson     case INDEX_op_and_vec:
1599d2fd745fSRichard Henderson     case INDEX_op_or_vec:
1600d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
1601212be173SRichard Henderson     case INDEX_op_cmp_vec:
1602d2fd745fSRichard Henderson         return have_vec;
1603d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
1604d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
1605d2fd745fSRichard Henderson     case INDEX_op_not_vec:
1606d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
1607d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
1608d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
1609bcefc902SRichard Henderson     case INDEX_op_abs_vec:
1610bcefc902SRichard Henderson         return have_vec && TCG_TARGET_HAS_abs_vec;
1611d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
1612d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
1613d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
1614d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
1615ed523473SRichard Henderson     case INDEX_op_nand_vec:
1616ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_nand_vec;
1617ed523473SRichard Henderson     case INDEX_op_nor_vec:
1618ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_nor_vec;
1619ed523473SRichard Henderson     case INDEX_op_eqv_vec:
1620ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_eqv_vec;
16213774030aSRichard Henderson     case INDEX_op_mul_vec:
16223774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
1623d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
1624d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
1625d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
1626d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
1627d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
1628d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
1629d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
1630d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
1631d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
1632d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
1633d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
1634d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
1635b0f7e744SRichard Henderson     case INDEX_op_rotli_vec:
1636b0f7e744SRichard Henderson         return have_vec && TCG_TARGET_HAS_roti_vec;
163723850a74SRichard Henderson     case INDEX_op_rotls_vec:
163823850a74SRichard Henderson         return have_vec && TCG_TARGET_HAS_rots_vec;
16395d0ceda9SRichard Henderson     case INDEX_op_rotlv_vec:
16405d0ceda9SRichard Henderson     case INDEX_op_rotrv_vec:
16415d0ceda9SRichard Henderson         return have_vec && TCG_TARGET_HAS_rotv_vec;
16428afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
16438afaf050SRichard Henderson     case INDEX_op_usadd_vec:
16448afaf050SRichard Henderson     case INDEX_op_sssub_vec:
16458afaf050SRichard Henderson     case INDEX_op_ussub_vec:
16468afaf050SRichard Henderson         return have_vec && TCG_TARGET_HAS_sat_vec;
1647dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
1648dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
1649dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
1650dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
1651dd0a0fcdSRichard Henderson         return have_vec && TCG_TARGET_HAS_minmax_vec;
165238dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
165338dc1294SRichard Henderson         return have_vec && TCG_TARGET_HAS_bitsel_vec;
1654f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
1655f75da298SRichard Henderson         return have_vec && TCG_TARGET_HAS_cmpsel_vec;
1656d2fd745fSRichard Henderson 
1657db432672SRichard Henderson     default:
1658db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
1659db432672SRichard Henderson         return true;
1660be0f34b5SRichard Henderson     }
1661be0f34b5SRichard Henderson }
1662be0f34b5SRichard Henderson 
166339004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs);
166439004a71SRichard Henderson 
1665ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
1666c896fe29Sbellard {
16673e92aa34SRichard Henderson     const TCGHelperInfo *info;
166839004a71SRichard Henderson     TCGv_i64 extend_free[MAX_CALL_IARGS];
166939004a71SRichard Henderson     int n_extend = 0;
167075e8b9b7SRichard Henderson     TCGOp *op;
167139004a71SRichard Henderson     int i, n, pi = 0, total_args;
1672afb49896SRichard Henderson 
1673619205fdSEmilio G. Cota     info = g_hash_table_lookup(helper_table, (gpointer)func);
167439004a71SRichard Henderson     total_args = info->nr_out + info->nr_in + 2;
167539004a71SRichard Henderson     op = tcg_op_alloc(INDEX_op_call, total_args);
16762bece2c8SRichard Henderson 
167738b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
167838b47b19SEmilio G. Cota     /* detect non-plugin helpers */
167938b47b19SEmilio G. Cota     if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) {
168038b47b19SEmilio G. Cota         tcg_ctx->plugin_insn->calls_helpers = true;
168138b47b19SEmilio G. Cota     }
168238b47b19SEmilio G. Cota #endif
168338b47b19SEmilio G. Cota 
168439004a71SRichard Henderson     TCGOP_CALLO(op) = n = info->nr_out;
168539004a71SRichard Henderson     switch (n) {
168639004a71SRichard Henderson     case 0:
168739004a71SRichard Henderson         tcg_debug_assert(ret == NULL);
168839004a71SRichard Henderson         break;
168939004a71SRichard Henderson     case 1:
169039004a71SRichard Henderson         tcg_debug_assert(ret != NULL);
169139004a71SRichard Henderson         op->args[pi++] = temp_arg(ret);
169239004a71SRichard Henderson         break;
169339004a71SRichard Henderson     case 2:
169439004a71SRichard Henderson         tcg_debug_assert(ret != NULL);
169539004a71SRichard Henderson         tcg_debug_assert(ret->base_type == ret->type + 1);
169639004a71SRichard Henderson         tcg_debug_assert(ret->temp_subindex == 0);
169739004a71SRichard Henderson         op->args[pi++] = temp_arg(ret);
169839004a71SRichard Henderson         op->args[pi++] = temp_arg(ret + 1);
169939004a71SRichard Henderson         break;
170039004a71SRichard Henderson     default:
170139004a71SRichard Henderson         g_assert_not_reached();
170239004a71SRichard Henderson     }
17037319d83aSRichard Henderson 
170439004a71SRichard Henderson     TCGOP_CALLI(op) = n = info->nr_in;
170539004a71SRichard Henderson     for (i = 0; i < n; i++) {
170639004a71SRichard Henderson         const TCGCallArgumentLoc *loc = &info->in[i];
170739004a71SRichard Henderson         TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex;
170839004a71SRichard Henderson 
170939004a71SRichard Henderson         switch (loc->kind) {
171039004a71SRichard Henderson         case TCG_CALL_ARG_NORMAL:
171139004a71SRichard Henderson             op->args[pi++] = temp_arg(ts);
171239004a71SRichard Henderson             break;
171339004a71SRichard Henderson 
171439004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
171539004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
171639004a71SRichard Henderson             {
17172bece2c8SRichard Henderson                 TCGv_i64 temp = tcg_temp_new_i64();
171839004a71SRichard Henderson                 TCGv_i32 orig = temp_tcgv_i32(ts);
171939004a71SRichard Henderson 
172039004a71SRichard Henderson                 if (loc->kind == TCG_CALL_ARG_EXTEND_S) {
172118cf3d07SRichard Henderson                     tcg_gen_ext_i32_i64(temp, orig);
17222bece2c8SRichard Henderson                 } else {
172318cf3d07SRichard Henderson                     tcg_gen_extu_i32_i64(temp, orig);
17242bece2c8SRichard Henderson                 }
172539004a71SRichard Henderson                 op->args[pi++] = tcgv_i64_arg(temp);
172639004a71SRichard Henderson                 extend_free[n_extend++] = temp;
17272bece2c8SRichard Henderson             }
172839004a71SRichard Henderson             break;
17292bece2c8SRichard Henderson 
1730e2a9dd6bSRichard Henderson         default:
1731e2a9dd6bSRichard Henderson             g_assert_not_reached();
1732e2a9dd6bSRichard Henderson         }
1733c896fe29Sbellard     }
173475e8b9b7SRichard Henderson     op->args[pi++] = (uintptr_t)func;
17353e92aa34SRichard Henderson     op->args[pi++] = (uintptr_t)info;
173639004a71SRichard Henderson     tcg_debug_assert(pi == total_args);
1737a7812ae4Spbrook 
173839004a71SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
17392bece2c8SRichard Henderson 
174039004a71SRichard Henderson     tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free));
174139004a71SRichard Henderson     for (i = 0; i < n_extend; ++i) {
174239004a71SRichard Henderson         tcg_temp_free_i64(extend_free[i]);
1743eb8b0224SRichard Henderson     }
1744a7812ae4Spbrook }
1745c896fe29Sbellard 
17468fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
1747c896fe29Sbellard {
1748ac3b8891SRichard Henderson     int i, n;
1749ac3b8891SRichard Henderson 
1750ee17db83SRichard Henderson     for (i = 0, n = s->nb_temps; i < n; i++) {
1751ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
1752ee17db83SRichard Henderson         TCGTempVal val = TEMP_VAL_MEM;
1753ee17db83SRichard Henderson 
1754ee17db83SRichard Henderson         switch (ts->kind) {
1755c0522136SRichard Henderson         case TEMP_CONST:
1756c0522136SRichard Henderson             val = TEMP_VAL_CONST;
1757c0522136SRichard Henderson             break;
1758ee17db83SRichard Henderson         case TEMP_FIXED:
1759ee17db83SRichard Henderson             val = TEMP_VAL_REG;
1760ee17db83SRichard Henderson             break;
1761ee17db83SRichard Henderson         case TEMP_GLOBAL:
1762ee17db83SRichard Henderson             break;
1763ee17db83SRichard Henderson         case TEMP_NORMAL:
1764c7482438SRichard Henderson         case TEMP_EBB:
1765ee17db83SRichard Henderson             val = TEMP_VAL_DEAD;
1766ee17db83SRichard Henderson             /* fall through */
1767ee17db83SRichard Henderson         case TEMP_LOCAL:
1768e8996ee0Sbellard             ts->mem_allocated = 0;
1769ee17db83SRichard Henderson             break;
1770ee17db83SRichard Henderson         default:
1771ee17db83SRichard Henderson             g_assert_not_reached();
1772ee17db83SRichard Henderson         }
1773ee17db83SRichard Henderson         ts->val_type = val;
1774e8996ee0Sbellard     }
1775f8b2f202SRichard Henderson 
1776f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
1777c896fe29Sbellard }
1778c896fe29Sbellard 
1779f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
1780f8b2f202SRichard Henderson                                  TCGTemp *ts)
1781c896fe29Sbellard {
17821807f4c4SRichard Henderson     int idx = temp_idx(ts);
1783ac56dd48Spbrook 
1784ee17db83SRichard Henderson     switch (ts->kind) {
1785ee17db83SRichard Henderson     case TEMP_FIXED:
1786ee17db83SRichard Henderson     case TEMP_GLOBAL:
1787ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
1788ee17db83SRichard Henderson         break;
1789ee17db83SRichard Henderson     case TEMP_LOCAL:
1790641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
1791ee17db83SRichard Henderson         break;
1792c7482438SRichard Henderson     case TEMP_EBB:
1793c7482438SRichard Henderson         snprintf(buf, buf_size, "ebb%d", idx - s->nb_globals);
1794c7482438SRichard Henderson         break;
1795ee17db83SRichard Henderson     case TEMP_NORMAL:
1796ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
1797ee17db83SRichard Henderson         break;
1798c0522136SRichard Henderson     case TEMP_CONST:
1799c0522136SRichard Henderson         switch (ts->type) {
1800c0522136SRichard Henderson         case TCG_TYPE_I32:
1801c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val);
1802c0522136SRichard Henderson             break;
1803c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32
1804c0522136SRichard Henderson         case TCG_TYPE_I64:
1805c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%" PRIx64, ts->val);
1806c0522136SRichard Henderson             break;
1807c0522136SRichard Henderson #endif
1808c0522136SRichard Henderson         case TCG_TYPE_V64:
1809c0522136SRichard Henderson         case TCG_TYPE_V128:
1810c0522136SRichard Henderson         case TCG_TYPE_V256:
1811c0522136SRichard Henderson             snprintf(buf, buf_size, "v%d$0x%" PRIx64,
1812c0522136SRichard Henderson                      64 << (ts->type - TCG_TYPE_V64), ts->val);
1813c0522136SRichard Henderson             break;
1814c0522136SRichard Henderson         default:
1815c0522136SRichard Henderson             g_assert_not_reached();
1816c0522136SRichard Henderson         }
1817c0522136SRichard Henderson         break;
1818c896fe29Sbellard     }
1819c896fe29Sbellard     return buf;
1820c896fe29Sbellard }
1821c896fe29Sbellard 
182243439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
182343439139SRichard Henderson                              int buf_size, TCGArg arg)
1824f8b2f202SRichard Henderson {
182543439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
1826f8b2f202SRichard Henderson }
1827f8b2f202SRichard Henderson 
1828f48f3edeSblueswir1 static const char * const cond_name[] =
1829f48f3edeSblueswir1 {
18300aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
18310aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
1832f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
1833f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
1834f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
1835f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
1836f48f3edeSblueswir1     [TCG_COND_LE] = "le",
1837f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
1838f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
1839f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
1840f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
1841f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
1842f48f3edeSblueswir1 };
1843f48f3edeSblueswir1 
1844f713d6adSRichard Henderson static const char * const ldst_name[] =
1845f713d6adSRichard Henderson {
1846f713d6adSRichard Henderson     [MO_UB]   = "ub",
1847f713d6adSRichard Henderson     [MO_SB]   = "sb",
1848f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
1849f713d6adSRichard Henderson     [MO_LESW] = "lesw",
1850f713d6adSRichard Henderson     [MO_LEUL] = "leul",
1851f713d6adSRichard Henderson     [MO_LESL] = "lesl",
1852fc313c64SFrédéric Pétrot     [MO_LEUQ] = "leq",
1853f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
1854f713d6adSRichard Henderson     [MO_BESW] = "besw",
1855f713d6adSRichard Henderson     [MO_BEUL] = "beul",
1856f713d6adSRichard Henderson     [MO_BESL] = "besl",
1857fc313c64SFrédéric Pétrot     [MO_BEUQ] = "beq",
1858f713d6adSRichard Henderson };
1859f713d6adSRichard Henderson 
18601f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
186152bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY
18621f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
18631f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
18641f00b27fSSergey Sorokin #else
18651f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
18661f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
18671f00b27fSSergey Sorokin #endif
18681f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
18691f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
18701f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
18711f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
18721f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
18731f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
18741f00b27fSSergey Sorokin };
18751f00b27fSSergey Sorokin 
1876587195bdSRichard Henderson static const char bswap_flag_name[][6] = {
1877587195bdSRichard Henderson     [TCG_BSWAP_IZ] = "iz",
1878587195bdSRichard Henderson     [TCG_BSWAP_OZ] = "oz",
1879587195bdSRichard Henderson     [TCG_BSWAP_OS] = "os",
1880587195bdSRichard Henderson     [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz",
1881587195bdSRichard Henderson     [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os",
1882587195bdSRichard Henderson };
1883587195bdSRichard Henderson 
1884b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
1885b016486eSRichard Henderson {
1886b016486eSRichard Henderson     return (d & (d - 1)) == 0;
1887b016486eSRichard Henderson }
1888b016486eSRichard Henderson 
1889b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
1890b016486eSRichard Henderson {
1891b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
1892b016486eSRichard Henderson         return ctz32(d);
1893b016486eSRichard Henderson     } else {
1894b016486eSRichard Henderson         return ctz64(d);
1895b016486eSRichard Henderson     }
1896b016486eSRichard Henderson }
1897b016486eSRichard Henderson 
1898b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */
1899b7a83ff8SRichard Henderson #define ne_fprintf(...) \
1900b7a83ff8SRichard Henderson     ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; })
1901b7a83ff8SRichard Henderson 
1902b7a83ff8SRichard Henderson static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
1903c896fe29Sbellard {
1904c896fe29Sbellard     char buf[128];
1905c45cb8bbSRichard Henderson     TCGOp *op;
1906c896fe29Sbellard 
190715fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
1908c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
1909c45cb8bbSRichard Henderson         const TCGOpDef *def;
1910c45cb8bbSRichard Henderson         TCGOpcode c;
1911bdfb460eSRichard Henderson         int col = 0;
1912c45cb8bbSRichard Henderson 
1913c45cb8bbSRichard Henderson         c = op->opc;
1914c896fe29Sbellard         def = &tcg_op_defs[c];
1915c45cb8bbSRichard Henderson 
1916765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
1917b016486eSRichard Henderson             nb_oargs = 0;
1918b7a83ff8SRichard Henderson             col += ne_fprintf(f, "\n ----");
19199aef40edSRichard Henderson 
19209aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
19219aef40edSRichard Henderson                 target_ulong a;
19227e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
1923efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
19247e4597d7Sbellard #else
1925efee3746SRichard Henderson                 a = op->args[i];
19267e4597d7Sbellard #endif
1927b7a83ff8SRichard Henderson                 col += ne_fprintf(f, " " TARGET_FMT_lx, a);
1928eeacee4dSBlue Swirl             }
19297e4597d7Sbellard         } else if (c == INDEX_op_call) {
19303e92aa34SRichard Henderson             const TCGHelperInfo *info = tcg_call_info(op);
1931fa52e660SRichard Henderson             void *func = tcg_call_func(op);
19323e92aa34SRichard Henderson 
1933c896fe29Sbellard             /* variable number of arguments */
1934cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
1935cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
1936c896fe29Sbellard             nb_cargs = def->nb_cargs;
1937b03cce8eSbellard 
1938b7a83ff8SRichard Henderson             col += ne_fprintf(f, " %s ", def->name);
19393e92aa34SRichard Henderson 
19403e92aa34SRichard Henderson             /*
19413e92aa34SRichard Henderson              * Print the function name from TCGHelperInfo, if available.
19423e92aa34SRichard Henderson              * Note that plugins have a template function for the info,
19433e92aa34SRichard Henderson              * but the actual function pointer comes from the plugin.
19443e92aa34SRichard Henderson              */
19453e92aa34SRichard Henderson             if (func == info->func) {
1946b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s", info->name);
19473e92aa34SRichard Henderson             } else {
1948b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "plugin(%p)", func);
19493e92aa34SRichard Henderson             }
19503e92aa34SRichard Henderson 
1951b7a83ff8SRichard Henderson             col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs);
1952b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
1953b7a83ff8SRichard Henderson                 col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf),
1954efee3746SRichard Henderson                                                             op->args[i]));
1955b03cce8eSbellard             }
1956cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
1957efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
195839004a71SRichard Henderson                 const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
1959b7a83ff8SRichard Henderson                 col += ne_fprintf(f, ",%s", t);
1960e8996ee0Sbellard             }
1961b03cce8eSbellard         } else {
1962b7a83ff8SRichard Henderson             col += ne_fprintf(f, " %s ", def->name);
1963c45cb8bbSRichard Henderson 
1964c896fe29Sbellard             nb_oargs = def->nb_oargs;
1965c896fe29Sbellard             nb_iargs = def->nb_iargs;
1966c896fe29Sbellard             nb_cargs = def->nb_cargs;
1967c896fe29Sbellard 
1968d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
1969b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "v%d,e%d,", 64 << TCGOP_VECL(op),
1970d2fd745fSRichard Henderson                                   8 << TCGOP_VECE(op));
1971d2fd745fSRichard Henderson             }
1972d2fd745fSRichard Henderson 
1973c896fe29Sbellard             k = 0;
1974c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
1975b7a83ff8SRichard Henderson                 const char *sep =  k ? "," : "";
1976b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s%s", sep,
1977b7a83ff8SRichard Henderson                                   tcg_get_arg_str(s, buf, sizeof(buf),
1978efee3746SRichard Henderson                                                   op->args[k++]));
1979c896fe29Sbellard             }
1980c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
1981b7a83ff8SRichard Henderson                 const char *sep =  k ? "," : "";
1982b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s%s", sep,
1983b7a83ff8SRichard Henderson                                   tcg_get_arg_str(s, buf, sizeof(buf),
1984efee3746SRichard Henderson                                                   op->args[k++]));
1985c896fe29Sbellard             }
1986be210acbSRichard Henderson             switch (c) {
1987be210acbSRichard Henderson             case INDEX_op_brcond_i32:
1988ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
1989ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
1990be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
1991be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
1992ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
1993be210acbSRichard Henderson             case INDEX_op_setcond_i64:
1994ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
1995212be173SRichard Henderson             case INDEX_op_cmp_vec:
1996f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
1997efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
1998efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
1999b7a83ff8SRichard Henderson                     col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]);
2000eeacee4dSBlue Swirl                 } else {
2001b7a83ff8SRichard Henderson                     col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]);
2002eeacee4dSBlue Swirl                 }
2003f48f3edeSblueswir1                 i = 1;
2004be210acbSRichard Henderson                 break;
2005f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
2006f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
200707ce0b05SRichard Henderson             case INDEX_op_qemu_st8_i32:
2008f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
2009f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
201059227d5dSRichard Henderson                 {
20119002ffcbSRichard Henderson                     MemOpIdx oi = op->args[k++];
201214776ab5STony Nguyen                     MemOp op = get_memop(oi);
201359227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
201459227d5dSRichard Henderson 
201559c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
2016b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",$0x%x,%u", op, ix);
201759c4b7e8SRichard Henderson                     } else {
20181f00b27fSSergey Sorokin                         const char *s_al, *s_op;
20191f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
202059c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
2021b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",%s%s,%u", s_al, s_op, ix);
2022f713d6adSRichard Henderson                     }
2023f713d6adSRichard Henderson                     i = 1;
202459227d5dSRichard Henderson                 }
2025f713d6adSRichard Henderson                 break;
2026587195bdSRichard Henderson             case INDEX_op_bswap16_i32:
2027587195bdSRichard Henderson             case INDEX_op_bswap16_i64:
2028587195bdSRichard Henderson             case INDEX_op_bswap32_i32:
2029587195bdSRichard Henderson             case INDEX_op_bswap32_i64:
2030587195bdSRichard Henderson             case INDEX_op_bswap64_i64:
2031587195bdSRichard Henderson                 {
2032587195bdSRichard Henderson                     TCGArg flags = op->args[k];
2033587195bdSRichard Henderson                     const char *name = NULL;
2034587195bdSRichard Henderson 
2035587195bdSRichard Henderson                     if (flags < ARRAY_SIZE(bswap_flag_name)) {
2036587195bdSRichard Henderson                         name = bswap_flag_name[flags];
2037587195bdSRichard Henderson                     }
2038587195bdSRichard Henderson                     if (name) {
2039b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",%s", name);
2040587195bdSRichard Henderson                     } else {
2041b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags);
2042587195bdSRichard Henderson                     }
2043587195bdSRichard Henderson                     i = k = 1;
2044587195bdSRichard Henderson                 }
2045587195bdSRichard Henderson                 break;
2046be210acbSRichard Henderson             default:
2047f48f3edeSblueswir1                 i = 0;
2048be210acbSRichard Henderson                 break;
2049be210acbSRichard Henderson             }
205051e3972cSRichard Henderson             switch (c) {
205151e3972cSRichard Henderson             case INDEX_op_set_label:
205251e3972cSRichard Henderson             case INDEX_op_br:
205351e3972cSRichard Henderson             case INDEX_op_brcond_i32:
205451e3972cSRichard Henderson             case INDEX_op_brcond_i64:
205551e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2056b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s$L%d", k ? "," : "",
2057efee3746SRichard Henderson                                   arg_label(op->args[k])->id);
205851e3972cSRichard Henderson                 i++, k++;
205951e3972cSRichard Henderson                 break;
206051e3972cSRichard Henderson             default:
206151e3972cSRichard Henderson                 break;
2062eeacee4dSBlue Swirl             }
206351e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
2064b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "",
2065b7a83ff8SRichard Henderson                                   op->args[k]);
2066bdfb460eSRichard Henderson             }
2067bdfb460eSRichard Henderson         }
2068bdfb460eSRichard Henderson 
20691894f69aSRichard Henderson         if (have_prefs || op->life) {
20701894f69aSRichard Henderson             for (; col < 40; ++col) {
2071b7a83ff8SRichard Henderson                 putc(' ', f);
2072bdfb460eSRichard Henderson             }
20731894f69aSRichard Henderson         }
20741894f69aSRichard Henderson 
20751894f69aSRichard Henderson         if (op->life) {
20761894f69aSRichard Henderson             unsigned life = op->life;
2077bdfb460eSRichard Henderson 
2078bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
2079b7a83ff8SRichard Henderson                 ne_fprintf(f, "  sync:");
2080bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
2081bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
2082b7a83ff8SRichard Henderson                         ne_fprintf(f, " %d", i);
2083bdfb460eSRichard Henderson                     }
2084bdfb460eSRichard Henderson                 }
2085bdfb460eSRichard Henderson             }
2086bdfb460eSRichard Henderson             life /= DEAD_ARG;
2087bdfb460eSRichard Henderson             if (life) {
2088b7a83ff8SRichard Henderson                 ne_fprintf(f, "  dead:");
2089bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
2090bdfb460eSRichard Henderson                     if (life & 1) {
2091b7a83ff8SRichard Henderson                         ne_fprintf(f, " %d", i);
2092bdfb460eSRichard Henderson                     }
2093bdfb460eSRichard Henderson                 }
2094c896fe29Sbellard             }
2095b03cce8eSbellard         }
20961894f69aSRichard Henderson 
20971894f69aSRichard Henderson         if (have_prefs) {
20981894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
209931fd884bSRichard Henderson                 TCGRegSet set = output_pref(op, i);
21001894f69aSRichard Henderson 
21011894f69aSRichard Henderson                 if (i == 0) {
2102b7a83ff8SRichard Henderson                     ne_fprintf(f, "  pref=");
21031894f69aSRichard Henderson                 } else {
2104b7a83ff8SRichard Henderson                     ne_fprintf(f, ",");
21051894f69aSRichard Henderson                 }
21061894f69aSRichard Henderson                 if (set == 0) {
2107b7a83ff8SRichard Henderson                     ne_fprintf(f, "none");
21081894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
2109b7a83ff8SRichard Henderson                     ne_fprintf(f, "all");
21101894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
21111894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
21121894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
2113b7a83ff8SRichard Henderson                     ne_fprintf(f, "%s", tcg_target_reg_names[reg]);
21141894f69aSRichard Henderson #endif
21151894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
2116b7a83ff8SRichard Henderson                     ne_fprintf(f, "0x%x", (uint32_t)set);
21171894f69aSRichard Henderson                 } else {
2118b7a83ff8SRichard Henderson                     ne_fprintf(f, "0x%" PRIx64, (uint64_t)set);
21191894f69aSRichard Henderson                 }
21201894f69aSRichard Henderson             }
21211894f69aSRichard Henderson         }
21221894f69aSRichard Henderson 
2123b7a83ff8SRichard Henderson         putc('\n', f);
2124c896fe29Sbellard     }
2125c896fe29Sbellard }
2126c896fe29Sbellard 
2127c896fe29Sbellard /* we give more priority to constraints with less registers */
2128c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2129c896fe29Sbellard {
213074a11790SRichard Henderson     const TCGArgConstraint *arg_ct = &def->args_ct[k];
213129f5e925SRichard Henderson     int n = ctpop64(arg_ct->regs);
2132c896fe29Sbellard 
213329f5e925SRichard Henderson     /*
213429f5e925SRichard Henderson      * Sort constraints of a single register first, which includes output
213529f5e925SRichard Henderson      * aliases (which must exactly match the input already allocated).
213629f5e925SRichard Henderson      */
213729f5e925SRichard Henderson     if (n == 1 || arg_ct->oalias) {
213829f5e925SRichard Henderson         return INT_MAX;
2139c896fe29Sbellard     }
214029f5e925SRichard Henderson 
214129f5e925SRichard Henderson     /*
214229f5e925SRichard Henderson      * Sort register pairs next, first then second immediately after.
214329f5e925SRichard Henderson      * Arbitrarily sort multiple pairs by the index of the first reg;
214429f5e925SRichard Henderson      * there shouldn't be many pairs.
214529f5e925SRichard Henderson      */
214629f5e925SRichard Henderson     switch (arg_ct->pair) {
214729f5e925SRichard Henderson     case 1:
214829f5e925SRichard Henderson     case 3:
214929f5e925SRichard Henderson         return (k + 1) * 2;
215029f5e925SRichard Henderson     case 2:
215129f5e925SRichard Henderson         return (arg_ct->pair_index + 1) * 2 - 1;
215229f5e925SRichard Henderson     }
215329f5e925SRichard Henderson 
215429f5e925SRichard Henderson     /* Finally, sort by decreasing register count. */
215529f5e925SRichard Henderson     assert(n > 1);
215629f5e925SRichard Henderson     return -n;
2157c896fe29Sbellard }
2158c896fe29Sbellard 
2159c896fe29Sbellard /* sort from highest priority to lowest */
2160c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2161c896fe29Sbellard {
216266792f90SRichard Henderson     int i, j;
216366792f90SRichard Henderson     TCGArgConstraint *a = def->args_ct;
2164c896fe29Sbellard 
216566792f90SRichard Henderson     for (i = 0; i < n; i++) {
216666792f90SRichard Henderson         a[start + i].sort_index = start + i;
216766792f90SRichard Henderson     }
216866792f90SRichard Henderson     if (n <= 1) {
2169c896fe29Sbellard         return;
217066792f90SRichard Henderson     }
2171c896fe29Sbellard     for (i = 0; i < n - 1; i++) {
2172c896fe29Sbellard         for (j = i + 1; j < n; j++) {
217366792f90SRichard Henderson             int p1 = get_constraint_priority(def, a[start + i].sort_index);
217466792f90SRichard Henderson             int p2 = get_constraint_priority(def, a[start + j].sort_index);
2175c896fe29Sbellard             if (p1 < p2) {
217666792f90SRichard Henderson                 int tmp = a[start + i].sort_index;
217766792f90SRichard Henderson                 a[start + i].sort_index = a[start + j].sort_index;
217866792f90SRichard Henderson                 a[start + j].sort_index = tmp;
2179c896fe29Sbellard             }
2180c896fe29Sbellard         }
2181c896fe29Sbellard     }
2182c896fe29Sbellard }
2183c896fe29Sbellard 
2184f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2185c896fe29Sbellard {
2186a9751609SRichard Henderson     TCGOpcode op;
2187c896fe29Sbellard 
2188f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
2189f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
2190f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
219129f5e925SRichard Henderson         bool saw_alias_pair = false;
219229f5e925SRichard Henderson         int i, o, i2, o2, nb_args;
2193f69d277eSRichard Henderson 
2194f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
2195f69d277eSRichard Henderson             continue;
2196f69d277eSRichard Henderson         }
2197f69d277eSRichard Henderson 
2198c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
2199f69d277eSRichard Henderson         if (nb_args == 0) {
2200f69d277eSRichard Henderson             continue;
2201f69d277eSRichard Henderson         }
2202f69d277eSRichard Henderson 
22034c22e840SRichard Henderson         /*
22044c22e840SRichard Henderson          * Macro magic should make it impossible, but double-check that
22054c22e840SRichard Henderson          * the array index is in range.  Since the signness of an enum
22064c22e840SRichard Henderson          * is implementation defined, force the result to unsigned.
22074c22e840SRichard Henderson          */
22084c22e840SRichard Henderson         unsigned con_set = tcg_target_op_def(op);
22094c22e840SRichard Henderson         tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets));
22104c22e840SRichard Henderson         tdefs = &constraint_sets[con_set];
2211f69d277eSRichard Henderson 
2212c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2213f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
22148940ea0dSPhilippe Mathieu-Daudé             bool input_p = i >= def->nb_oargs;
22158940ea0dSPhilippe Mathieu-Daudé 
2216f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2217eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2218f69d277eSRichard Henderson 
221917280ff4SRichard Henderson             switch (*ct_str) {
222017280ff4SRichard Henderson             case '0' ... '9':
22218940ea0dSPhilippe Mathieu-Daudé                 o = *ct_str - '0';
22228940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(input_p);
22238940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(o < def->nb_oargs);
22248940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(def->args_ct[o].regs != 0);
22258940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(!def->args_ct[o].oalias);
22268940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i] = def->args_ct[o];
2227bc2b17e6SRichard Henderson                 /* The output sets oalias.  */
22288940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[o].oalias = 1;
22298940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[o].alias_index = i;
2230bc2b17e6SRichard Henderson                 /* The input sets ialias. */
22318940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i].ialias = 1;
22328940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i].alias_index = o;
223329f5e925SRichard Henderson                 if (def->args_ct[i].pair) {
223429f5e925SRichard Henderson                     saw_alias_pair = true;
223529f5e925SRichard Henderson                 }
22368940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(ct_str[1] == '\0');
22378940ea0dSPhilippe Mathieu-Daudé                 continue;
22388940ea0dSPhilippe Mathieu-Daudé 
223982790a87SRichard Henderson             case '&':
22408940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(!input_p);
2241bc2b17e6SRichard Henderson                 def->args_ct[i].newreg = true;
224282790a87SRichard Henderson                 ct_str++;
224382790a87SRichard Henderson                 break;
224429f5e925SRichard Henderson 
224529f5e925SRichard Henderson             case 'p': /* plus */
224629f5e925SRichard Henderson                 /* Allocate to the register after the previous. */
224729f5e925SRichard Henderson                 tcg_debug_assert(i > (input_p ? def->nb_oargs : 0));
224829f5e925SRichard Henderson                 o = i - 1;
224929f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].pair);
225029f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].ct);
225129f5e925SRichard Henderson                 def->args_ct[i] = (TCGArgConstraint){
225229f5e925SRichard Henderson                     .pair = 2,
225329f5e925SRichard Henderson                     .pair_index = o,
225429f5e925SRichard Henderson                     .regs = def->args_ct[o].regs << 1,
225529f5e925SRichard Henderson                 };
225629f5e925SRichard Henderson                 def->args_ct[o].pair = 1;
225729f5e925SRichard Henderson                 def->args_ct[o].pair_index = i;
225829f5e925SRichard Henderson                 tcg_debug_assert(ct_str[1] == '\0');
225929f5e925SRichard Henderson                 continue;
226029f5e925SRichard Henderson 
226129f5e925SRichard Henderson             case 'm': /* minus */
226229f5e925SRichard Henderson                 /* Allocate to the register before the previous. */
226329f5e925SRichard Henderson                 tcg_debug_assert(i > (input_p ? def->nb_oargs : 0));
226429f5e925SRichard Henderson                 o = i - 1;
226529f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].pair);
226629f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].ct);
226729f5e925SRichard Henderson                 def->args_ct[i] = (TCGArgConstraint){
226829f5e925SRichard Henderson                     .pair = 1,
226929f5e925SRichard Henderson                     .pair_index = o,
227029f5e925SRichard Henderson                     .regs = def->args_ct[o].regs >> 1,
227129f5e925SRichard Henderson                 };
227229f5e925SRichard Henderson                 def->args_ct[o].pair = 2;
227329f5e925SRichard Henderson                 def->args_ct[o].pair_index = i;
227429f5e925SRichard Henderson                 tcg_debug_assert(ct_str[1] == '\0');
227529f5e925SRichard Henderson                 continue;
22768940ea0dSPhilippe Mathieu-Daudé             }
22778940ea0dSPhilippe Mathieu-Daudé 
22788940ea0dSPhilippe Mathieu-Daudé             do {
22798940ea0dSPhilippe Mathieu-Daudé                 switch (*ct_str) {
2280c896fe29Sbellard                 case 'i':
2281c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2282c896fe29Sbellard                     break;
2283358b4923SRichard Henderson 
2284358b4923SRichard Henderson                 /* Include all of the target-specific constraints. */
2285358b4923SRichard Henderson 
2286358b4923SRichard Henderson #undef CONST
2287358b4923SRichard Henderson #define CONST(CASE, MASK) \
22888940ea0dSPhilippe Mathieu-Daudé     case CASE: def->args_ct[i].ct |= MASK; break;
2289358b4923SRichard Henderson #define REGS(CASE, MASK) \
22908940ea0dSPhilippe Mathieu-Daudé     case CASE: def->args_ct[i].regs |= MASK; break;
2291358b4923SRichard Henderson 
2292358b4923SRichard Henderson #include "tcg-target-con-str.h"
2293358b4923SRichard Henderson 
2294358b4923SRichard Henderson #undef REGS
2295358b4923SRichard Henderson #undef CONST
2296c896fe29Sbellard                 default:
22978940ea0dSPhilippe Mathieu-Daudé                 case '0' ... '9':
22988940ea0dSPhilippe Mathieu-Daudé                 case '&':
229929f5e925SRichard Henderson                 case 'p':
230029f5e925SRichard Henderson                 case 'm':
2301358b4923SRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2302358b4923SRichard Henderson                     g_assert_not_reached();
2303358b4923SRichard Henderson                 }
23048940ea0dSPhilippe Mathieu-Daudé             } while (*++ct_str != '\0');
2305c896fe29Sbellard         }
2306c896fe29Sbellard 
2307c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2308eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2309c68aaa18SStefan Weil 
231029f5e925SRichard Henderson         /*
231129f5e925SRichard Henderson          * Fix up output pairs that are aliased with inputs.
231229f5e925SRichard Henderson          * When we created the alias, we copied pair from the output.
231329f5e925SRichard Henderson          * There are three cases:
231429f5e925SRichard Henderson          *    (1a) Pairs of inputs alias pairs of outputs.
231529f5e925SRichard Henderson          *    (1b) One input aliases the first of a pair of outputs.
231629f5e925SRichard Henderson          *    (2)  One input aliases the second of a pair of outputs.
231729f5e925SRichard Henderson          *
231829f5e925SRichard Henderson          * Case 1a is handled by making sure that the pair_index'es are
231929f5e925SRichard Henderson          * properly updated so that they appear the same as a pair of inputs.
232029f5e925SRichard Henderson          *
232129f5e925SRichard Henderson          * Case 1b is handled by setting the pair_index of the input to
232229f5e925SRichard Henderson          * itself, simply so it doesn't point to an unrelated argument.
232329f5e925SRichard Henderson          * Since we don't encounter the "second" during the input allocation
232429f5e925SRichard Henderson          * phase, nothing happens with the second half of the input pair.
232529f5e925SRichard Henderson          *
232629f5e925SRichard Henderson          * Case 2 is handled by setting the second input to pair=3, the
232729f5e925SRichard Henderson          * first output to pair=3, and the pair_index'es to match.
232829f5e925SRichard Henderson          */
232929f5e925SRichard Henderson         if (saw_alias_pair) {
233029f5e925SRichard Henderson             for (i = def->nb_oargs; i < nb_args; i++) {
233129f5e925SRichard Henderson                 /*
233229f5e925SRichard Henderson                  * Since [0-9pm] must be alone in the constraint string,
233329f5e925SRichard Henderson                  * the only way they can both be set is if the pair comes
233429f5e925SRichard Henderson                  * from the output alias.
233529f5e925SRichard Henderson                  */
233629f5e925SRichard Henderson                 if (!def->args_ct[i].ialias) {
233729f5e925SRichard Henderson                     continue;
233829f5e925SRichard Henderson                 }
233929f5e925SRichard Henderson                 switch (def->args_ct[i].pair) {
234029f5e925SRichard Henderson                 case 0:
234129f5e925SRichard Henderson                     break;
234229f5e925SRichard Henderson                 case 1:
234329f5e925SRichard Henderson                     o = def->args_ct[i].alias_index;
234429f5e925SRichard Henderson                     o2 = def->args_ct[o].pair_index;
234529f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o].pair == 1);
234629f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o2].pair == 2);
234729f5e925SRichard Henderson                     if (def->args_ct[o2].oalias) {
234829f5e925SRichard Henderson                         /* Case 1a */
234929f5e925SRichard Henderson                         i2 = def->args_ct[o2].alias_index;
235029f5e925SRichard Henderson                         tcg_debug_assert(def->args_ct[i2].pair == 2);
235129f5e925SRichard Henderson                         def->args_ct[i2].pair_index = i;
235229f5e925SRichard Henderson                         def->args_ct[i].pair_index = i2;
235329f5e925SRichard Henderson                     } else {
235429f5e925SRichard Henderson                         /* Case 1b */
235529f5e925SRichard Henderson                         def->args_ct[i].pair_index = i;
235629f5e925SRichard Henderson                     }
235729f5e925SRichard Henderson                     break;
235829f5e925SRichard Henderson                 case 2:
235929f5e925SRichard Henderson                     o = def->args_ct[i].alias_index;
236029f5e925SRichard Henderson                     o2 = def->args_ct[o].pair_index;
236129f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o].pair == 2);
236229f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o2].pair == 1);
236329f5e925SRichard Henderson                     if (def->args_ct[o2].oalias) {
236429f5e925SRichard Henderson                         /* Case 1a */
236529f5e925SRichard Henderson                         i2 = def->args_ct[o2].alias_index;
236629f5e925SRichard Henderson                         tcg_debug_assert(def->args_ct[i2].pair == 1);
236729f5e925SRichard Henderson                         def->args_ct[i2].pair_index = i;
236829f5e925SRichard Henderson                         def->args_ct[i].pair_index = i2;
236929f5e925SRichard Henderson                     } else {
237029f5e925SRichard Henderson                         /* Case 2 */
237129f5e925SRichard Henderson                         def->args_ct[i].pair = 3;
237229f5e925SRichard Henderson                         def->args_ct[o2].pair = 3;
237329f5e925SRichard Henderson                         def->args_ct[i].pair_index = o2;
237429f5e925SRichard Henderson                         def->args_ct[o2].pair_index = i;
237529f5e925SRichard Henderson                     }
237629f5e925SRichard Henderson                     break;
237729f5e925SRichard Henderson                 default:
237829f5e925SRichard Henderson                     g_assert_not_reached();
237929f5e925SRichard Henderson                 }
238029f5e925SRichard Henderson             }
238129f5e925SRichard Henderson         }
238229f5e925SRichard Henderson 
2383c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
2384c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
2385c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
2386c896fe29Sbellard     }
2387c896fe29Sbellard }
2388c896fe29Sbellard 
23890c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
23900c627cdcSRichard Henderson {
2391d88a117eSRichard Henderson     TCGLabel *label;
2392d88a117eSRichard Henderson 
2393d88a117eSRichard Henderson     switch (op->opc) {
2394d88a117eSRichard Henderson     case INDEX_op_br:
2395d88a117eSRichard Henderson         label = arg_label(op->args[0]);
2396d88a117eSRichard Henderson         label->refs--;
2397d88a117eSRichard Henderson         break;
2398d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
2399d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
2400d88a117eSRichard Henderson         label = arg_label(op->args[3]);
2401d88a117eSRichard Henderson         label->refs--;
2402d88a117eSRichard Henderson         break;
2403d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
2404d88a117eSRichard Henderson         label = arg_label(op->args[5]);
2405d88a117eSRichard Henderson         label->refs--;
2406d88a117eSRichard Henderson         break;
2407d88a117eSRichard Henderson     default:
2408d88a117eSRichard Henderson         break;
2409d88a117eSRichard Henderson     }
2410d88a117eSRichard Henderson 
241115fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
241215fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
2413abebf925SRichard Henderson     s->nb_ops--;
24140c627cdcSRichard Henderson 
24150c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
2416d73415a3SStefan Hajnoczi     qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
24170c627cdcSRichard Henderson #endif
24180c627cdcSRichard Henderson }
24190c627cdcSRichard Henderson 
2420a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op)
2421a80cdd31SRichard Henderson {
2422a80cdd31SRichard Henderson     TCGContext *s = tcg_ctx;
2423a80cdd31SRichard Henderson 
2424a80cdd31SRichard Henderson     while (true) {
2425a80cdd31SRichard Henderson         TCGOp *last = tcg_last_op();
2426a80cdd31SRichard Henderson         if (last == op) {
2427a80cdd31SRichard Henderson             return;
2428a80cdd31SRichard Henderson         }
2429a80cdd31SRichard Henderson         tcg_op_remove(s, last);
2430a80cdd31SRichard Henderson     }
2431a80cdd31SRichard Henderson }
2432a80cdd31SRichard Henderson 
2433d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs)
243415fa08f8SRichard Henderson {
243515fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
2436cb10bc63SRichard Henderson     TCGOp *op = NULL;
243715fa08f8SRichard Henderson 
2438cb10bc63SRichard Henderson     if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) {
2439cb10bc63SRichard Henderson         QTAILQ_FOREACH(op, &s->free_ops, link) {
2440cb10bc63SRichard Henderson             if (nargs <= op->nargs) {
244115fa08f8SRichard Henderson                 QTAILQ_REMOVE(&s->free_ops, op, link);
2442cb10bc63SRichard Henderson                 nargs = op->nargs;
2443cb10bc63SRichard Henderson                 goto found;
244415fa08f8SRichard Henderson             }
2445cb10bc63SRichard Henderson         }
2446cb10bc63SRichard Henderson     }
2447cb10bc63SRichard Henderson 
2448cb10bc63SRichard Henderson     /* Most opcodes have 3 or 4 operands: reduce fragmentation. */
2449cb10bc63SRichard Henderson     nargs = MAX(4, nargs);
2450cb10bc63SRichard Henderson     op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs);
2451cb10bc63SRichard Henderson 
2452cb10bc63SRichard Henderson  found:
245315fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
245415fa08f8SRichard Henderson     op->opc = opc;
2455cb10bc63SRichard Henderson     op->nargs = nargs;
245615fa08f8SRichard Henderson 
2457cb10bc63SRichard Henderson     /* Check for bitfield overflow. */
2458cb10bc63SRichard Henderson     tcg_debug_assert(op->nargs == nargs);
2459cb10bc63SRichard Henderson 
2460cb10bc63SRichard Henderson     s->nb_ops++;
246115fa08f8SRichard Henderson     return op;
246215fa08f8SRichard Henderson }
246315fa08f8SRichard Henderson 
2464d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs)
246515fa08f8SRichard Henderson {
2466d4478943SPhilippe Mathieu-Daudé     TCGOp *op = tcg_op_alloc(opc, nargs);
246715fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
246815fa08f8SRichard Henderson     return op;
246915fa08f8SRichard Henderson }
247015fa08f8SRichard Henderson 
2471d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op,
2472d4478943SPhilippe Mathieu-Daudé                             TCGOpcode opc, unsigned nargs)
24735a18407fSRichard Henderson {
2474d4478943SPhilippe Mathieu-Daudé     TCGOp *new_op = tcg_op_alloc(opc, nargs);
247515fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
24765a18407fSRichard Henderson     return new_op;
24775a18407fSRichard Henderson }
24785a18407fSRichard Henderson 
2479d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op,
2480d4478943SPhilippe Mathieu-Daudé                            TCGOpcode opc, unsigned nargs)
24815a18407fSRichard Henderson {
2482d4478943SPhilippe Mathieu-Daudé     TCGOp *new_op = tcg_op_alloc(opc, nargs);
248315fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
24845a18407fSRichard Henderson     return new_op;
24855a18407fSRichard Henderson }
24865a18407fSRichard Henderson 
2487b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
2488b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s)
2489b4fc67c7SRichard Henderson {
2490b4fc67c7SRichard Henderson     TCGOp *op, *op_next;
2491b4fc67c7SRichard Henderson     bool dead = false;
2492b4fc67c7SRichard Henderson 
2493b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
2494b4fc67c7SRichard Henderson         bool remove = dead;
2495b4fc67c7SRichard Henderson         TCGLabel *label;
2496b4fc67c7SRichard Henderson 
2497b4fc67c7SRichard Henderson         switch (op->opc) {
2498b4fc67c7SRichard Henderson         case INDEX_op_set_label:
2499b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
2500b4fc67c7SRichard Henderson             if (label->refs == 0) {
2501b4fc67c7SRichard Henderson                 /*
2502b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
2503b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
2504b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
2505b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
2506b4fc67c7SRichard Henderson                  * little to be gained by iterating.
2507b4fc67c7SRichard Henderson                  */
2508b4fc67c7SRichard Henderson                 remove = true;
2509b4fc67c7SRichard Henderson             } else {
2510b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
2511b4fc67c7SRichard Henderson                 dead = false;
2512b4fc67c7SRichard Henderson                 remove = false;
2513b4fc67c7SRichard Henderson 
2514b4fc67c7SRichard Henderson                 /*
2515b4fc67c7SRichard Henderson                  * Optimization can fold conditional branches to unconditional.
2516b4fc67c7SRichard Henderson                  * If we find a label with one reference which is preceded by
2517b4fc67c7SRichard Henderson                  * an unconditional branch to it, remove both.  This needed to
2518b4fc67c7SRichard Henderson                  * wait until the dead code in between them was removed.
2519b4fc67c7SRichard Henderson                  */
2520b4fc67c7SRichard Henderson                 if (label->refs == 1) {
2521eae3eb3eSPaolo Bonzini                     TCGOp *op_prev = QTAILQ_PREV(op, link);
2522b4fc67c7SRichard Henderson                     if (op_prev->opc == INDEX_op_br &&
2523b4fc67c7SRichard Henderson                         label == arg_label(op_prev->args[0])) {
2524b4fc67c7SRichard Henderson                         tcg_op_remove(s, op_prev);
2525b4fc67c7SRichard Henderson                         remove = true;
2526b4fc67c7SRichard Henderson                     }
2527b4fc67c7SRichard Henderson                 }
2528b4fc67c7SRichard Henderson             }
2529b4fc67c7SRichard Henderson             break;
2530b4fc67c7SRichard Henderson 
2531b4fc67c7SRichard Henderson         case INDEX_op_br:
2532b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
2533b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
2534b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
2535b4fc67c7SRichard Henderson             dead = true;
2536b4fc67c7SRichard Henderson             break;
2537b4fc67c7SRichard Henderson 
2538b4fc67c7SRichard Henderson         case INDEX_op_call:
2539b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
254090163900SRichard Henderson             if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) {
2541b4fc67c7SRichard Henderson                 dead = true;
2542b4fc67c7SRichard Henderson             }
2543b4fc67c7SRichard Henderson             break;
2544b4fc67c7SRichard Henderson 
2545b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
2546b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
2547b4fc67c7SRichard Henderson             remove = false;
2548b4fc67c7SRichard Henderson             break;
2549b4fc67c7SRichard Henderson 
2550b4fc67c7SRichard Henderson         default:
2551b4fc67c7SRichard Henderson             break;
2552b4fc67c7SRichard Henderson         }
2553b4fc67c7SRichard Henderson 
2554b4fc67c7SRichard Henderson         if (remove) {
2555b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
2556b4fc67c7SRichard Henderson         }
2557b4fc67c7SRichard Henderson     }
2558b4fc67c7SRichard Henderson }
2559b4fc67c7SRichard Henderson 
2560c70fbf0aSRichard Henderson #define TS_DEAD  1
2561c70fbf0aSRichard Henderson #define TS_MEM   2
2562c70fbf0aSRichard Henderson 
25635a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
25645a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
25655a18407fSRichard Henderson 
256625f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
256725f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
256825f49c5fSRichard Henderson {
256925f49c5fSRichard Henderson     return ts->state_ptr;
257025f49c5fSRichard Henderson }
257125f49c5fSRichard Henderson 
257225f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
257325f49c5fSRichard Henderson  * maximal regset for its type.
257425f49c5fSRichard Henderson  */
257525f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
257625f49c5fSRichard Henderson {
257725f49c5fSRichard Henderson     *la_temp_pref(ts)
257825f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
257925f49c5fSRichard Henderson }
258025f49c5fSRichard Henderson 
25819c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
25829c43b68dSAurelien Jarno    should be in memory. */
25832616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
2584c896fe29Sbellard {
2585b83eabeaSRichard Henderson     int i;
2586b83eabeaSRichard Henderson 
2587b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2588b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
258925f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2590b83eabeaSRichard Henderson     }
2591b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2592b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
259325f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2594b83eabeaSRichard Henderson     }
2595c896fe29Sbellard }
2596c896fe29Sbellard 
25979c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
25989c43b68dSAurelien Jarno    and local temps should be in memory. */
25992616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
2600641d5fbeSbellard {
2601b83eabeaSRichard Henderson     int i;
2602641d5fbeSbellard 
2603ee17db83SRichard Henderson     for (i = 0; i < nt; ++i) {
2604ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2605ee17db83SRichard Henderson         int state;
2606ee17db83SRichard Henderson 
2607ee17db83SRichard Henderson         switch (ts->kind) {
2608ee17db83SRichard Henderson         case TEMP_FIXED:
2609ee17db83SRichard Henderson         case TEMP_GLOBAL:
2610ee17db83SRichard Henderson         case TEMP_LOCAL:
2611ee17db83SRichard Henderson             state = TS_DEAD | TS_MEM;
2612ee17db83SRichard Henderson             break;
2613ee17db83SRichard Henderson         case TEMP_NORMAL:
2614c7482438SRichard Henderson         case TEMP_EBB:
2615c0522136SRichard Henderson         case TEMP_CONST:
2616ee17db83SRichard Henderson             state = TS_DEAD;
2617ee17db83SRichard Henderson             break;
2618ee17db83SRichard Henderson         default:
2619ee17db83SRichard Henderson             g_assert_not_reached();
2620c70fbf0aSRichard Henderson         }
2621ee17db83SRichard Henderson         ts->state = state;
2622ee17db83SRichard Henderson         la_reset_pref(ts);
2623641d5fbeSbellard     }
2624641d5fbeSbellard }
2625641d5fbeSbellard 
2626f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
2627f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
2628f65a061cSRichard Henderson {
2629f65a061cSRichard Henderson     int i;
2630f65a061cSRichard Henderson 
2631f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
263225f49c5fSRichard Henderson         int state = s->temps[i].state;
263325f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
263425f49c5fSRichard Henderson         if (state == TS_DEAD) {
263525f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
263625f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
263725f49c5fSRichard Henderson         }
2638f65a061cSRichard Henderson     }
2639f65a061cSRichard Henderson }
2640f65a061cSRichard Henderson 
2641b4cb76e6SRichard Henderson /*
2642c7482438SRichard Henderson  * liveness analysis: conditional branch: all temps are dead unless
2643c7482438SRichard Henderson  * explicitly live-across-conditional-branch, globals and local temps
2644c7482438SRichard Henderson  * should be synced.
2645b4cb76e6SRichard Henderson  */
2646b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
2647b4cb76e6SRichard Henderson {
2648b4cb76e6SRichard Henderson     la_global_sync(s, ng);
2649b4cb76e6SRichard Henderson 
2650b4cb76e6SRichard Henderson     for (int i = ng; i < nt; ++i) {
2651c0522136SRichard Henderson         TCGTemp *ts = &s->temps[i];
2652c0522136SRichard Henderson         int state;
2653c0522136SRichard Henderson 
2654c0522136SRichard Henderson         switch (ts->kind) {
2655c0522136SRichard Henderson         case TEMP_LOCAL:
2656c0522136SRichard Henderson             state = ts->state;
2657c0522136SRichard Henderson             ts->state = state | TS_MEM;
2658b4cb76e6SRichard Henderson             if (state != TS_DEAD) {
2659b4cb76e6SRichard Henderson                 continue;
2660b4cb76e6SRichard Henderson             }
2661c0522136SRichard Henderson             break;
2662c0522136SRichard Henderson         case TEMP_NORMAL:
2663b4cb76e6SRichard Henderson             s->temps[i].state = TS_DEAD;
2664c0522136SRichard Henderson             break;
2665c7482438SRichard Henderson         case TEMP_EBB:
2666c0522136SRichard Henderson         case TEMP_CONST:
2667c0522136SRichard Henderson             continue;
2668c0522136SRichard Henderson         default:
2669c0522136SRichard Henderson             g_assert_not_reached();
2670b4cb76e6SRichard Henderson         }
2671b4cb76e6SRichard Henderson         la_reset_pref(&s->temps[i]);
2672b4cb76e6SRichard Henderson     }
2673b4cb76e6SRichard Henderson }
2674b4cb76e6SRichard Henderson 
2675f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
2676f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
2677f65a061cSRichard Henderson {
2678f65a061cSRichard Henderson     int i;
2679f65a061cSRichard Henderson 
2680f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
2681f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
268225f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
268325f49c5fSRichard Henderson     }
268425f49c5fSRichard Henderson }
268525f49c5fSRichard Henderson 
268625f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
268725f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
268825f49c5fSRichard Henderson {
268925f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
269025f49c5fSRichard Henderson     int i;
269125f49c5fSRichard Henderson 
269225f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
269325f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
269425f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
269525f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
269625f49c5fSRichard Henderson             TCGRegSet set = *pset;
269725f49c5fSRichard Henderson 
269825f49c5fSRichard Henderson             set &= mask;
269925f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
270025f49c5fSRichard Henderson             if (set == 0) {
270125f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
270225f49c5fSRichard Henderson             }
270325f49c5fSRichard Henderson             *pset = set;
270425f49c5fSRichard Henderson         }
2705f65a061cSRichard Henderson     }
2706f65a061cSRichard Henderson }
2707f65a061cSRichard Henderson 
2708a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
2709c896fe29Sbellard    given input arguments is dead. Instructions updating dead
2710c896fe29Sbellard    temporaries are removed. */
2711b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s)
2712c896fe29Sbellard {
2713c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
27142616c808SRichard Henderson     int nb_temps = s->nb_temps;
271515fa08f8SRichard Henderson     TCGOp *op, *op_prev;
271625f49c5fSRichard Henderson     TCGRegSet *prefs;
271725f49c5fSRichard Henderson     int i;
271825f49c5fSRichard Henderson 
271925f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
272025f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
272125f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
272225f49c5fSRichard Henderson     }
2723c896fe29Sbellard 
2724ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
27252616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
2726c896fe29Sbellard 
2727eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
272825f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
2729c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
2730c45cb8bbSRichard Henderson         bool have_opc_new2;
2731a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
273225f49c5fSRichard Henderson         TCGTemp *ts;
2733c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2734c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2735c45cb8bbSRichard Henderson 
2736c45cb8bbSRichard Henderson         switch (opc) {
2737c896fe29Sbellard         case INDEX_op_call:
2738c6e113f5Sbellard             {
273939004a71SRichard Henderson                 const TCGHelperInfo *info = tcg_call_info(op);
274039004a71SRichard Henderson                 int call_flags = tcg_call_flags(op);
2741c6e113f5Sbellard 
2742cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
2743cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
2744c6e113f5Sbellard 
2745c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
274678505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
2747c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
274825f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
274925f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
2750c6e113f5Sbellard                             goto do_not_remove_call;
2751c6e113f5Sbellard                         }
27529c43b68dSAurelien Jarno                     }
2753c45cb8bbSRichard Henderson                     goto do_remove;
2754152c35aaSRichard Henderson                 }
2755c6e113f5Sbellard             do_not_remove_call:
2756c896fe29Sbellard 
275725f49c5fSRichard Henderson                 /* Output args are dead.  */
2758c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
275925f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
276025f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
2761a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
27626b64b624SAurelien Jarno                     }
276325f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
2764a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
27659c43b68dSAurelien Jarno                     }
276625f49c5fSRichard Henderson                     ts->state = TS_DEAD;
276725f49c5fSRichard Henderson                     la_reset_pref(ts);
2768c896fe29Sbellard                 }
2769c896fe29Sbellard 
277031fd884bSRichard Henderson                 /* Not used -- it will be tcg_target_call_oarg_reg().  */
277131fd884bSRichard Henderson                 memset(op->output_pref, 0, sizeof(op->output_pref));
277231fd884bSRichard Henderson 
277378505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
277478505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
2775f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
2776c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
2777f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
2778b9c18f56Saurel32                 }
2779c896fe29Sbellard 
278025f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
2781866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
278225f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
278339004a71SRichard Henderson                     if (ts->state & TS_DEAD) {
2784a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
2785c896fe29Sbellard                     }
2786c896fe29Sbellard                 }
278725f49c5fSRichard Henderson 
278825f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
278925f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
279025f49c5fSRichard Henderson 
279139004a71SRichard Henderson                 /*
279239004a71SRichard Henderson                  * Input arguments are live for preceding opcodes.
279339004a71SRichard Henderson                  *
279439004a71SRichard Henderson                  * For those arguments that die, and will be allocated in
279539004a71SRichard Henderson                  * registers, clear the register set for that arg, to be
279639004a71SRichard Henderson                  * filled in below.  For args that will be on the stack,
279739004a71SRichard Henderson                  * reset to any available reg.  Process arguments in reverse
279839004a71SRichard Henderson                  * order so that if a temp is used more than once, the stack
279939004a71SRichard Henderson                  * reset to max happens before the register reset to 0.
280025f49c5fSRichard Henderson                  */
280139004a71SRichard Henderson                 for (i = nb_iargs - 1; i >= 0; i--) {
280239004a71SRichard Henderson                     const TCGCallArgumentLoc *loc = &info->in[i];
280339004a71SRichard Henderson                     ts = arg_temp(op->args[nb_oargs + i]);
280439004a71SRichard Henderson 
280539004a71SRichard Henderson                     if (ts->state & TS_DEAD) {
280639004a71SRichard Henderson                         switch (loc->kind) {
280739004a71SRichard Henderson                         case TCG_CALL_ARG_NORMAL:
280839004a71SRichard Henderson                         case TCG_CALL_ARG_EXTEND_U:
280939004a71SRichard Henderson                         case TCG_CALL_ARG_EXTEND_S:
281039004a71SRichard Henderson                             if (REG_P(loc)) {
281139004a71SRichard Henderson                                 *la_temp_pref(ts) = 0;
281239004a71SRichard Henderson                                 break;
281339004a71SRichard Henderson                             }
281439004a71SRichard Henderson                             /* fall through */
281539004a71SRichard Henderson                         default:
281639004a71SRichard Henderson                             *la_temp_pref(ts) =
281739004a71SRichard Henderson                                 tcg_target_available_regs[ts->type];
281839004a71SRichard Henderson                             break;
281939004a71SRichard Henderson                         }
282025f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
282125f49c5fSRichard Henderson                     }
282225f49c5fSRichard Henderson                 }
282325f49c5fSRichard Henderson 
282439004a71SRichard Henderson                 /*
282539004a71SRichard Henderson                  * For each input argument, add its input register to prefs.
282639004a71SRichard Henderson                  * If a temp is used once, this produces a single set bit;
282739004a71SRichard Henderson                  * if a temp is used multiple times, this produces a set.
282839004a71SRichard Henderson                  */
282939004a71SRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
283039004a71SRichard Henderson                     const TCGCallArgumentLoc *loc = &info->in[i];
283139004a71SRichard Henderson                     ts = arg_temp(op->args[nb_oargs + i]);
283239004a71SRichard Henderson 
283339004a71SRichard Henderson                     switch (loc->kind) {
283439004a71SRichard Henderson                     case TCG_CALL_ARG_NORMAL:
283539004a71SRichard Henderson                     case TCG_CALL_ARG_EXTEND_U:
283639004a71SRichard Henderson                     case TCG_CALL_ARG_EXTEND_S:
283739004a71SRichard Henderson                         if (REG_P(loc)) {
283825f49c5fSRichard Henderson                             tcg_regset_set_reg(*la_temp_pref(ts),
283939004a71SRichard Henderson                                 tcg_target_call_iarg_regs[loc->arg_slot]);
284039004a71SRichard Henderson                         }
284139004a71SRichard Henderson                         break;
284239004a71SRichard Henderson                     default:
284339004a71SRichard Henderson                         break;
2844c70fbf0aSRichard Henderson                     }
2845c19f47bfSAurelien Jarno                 }
2846c6e113f5Sbellard             }
2847c896fe29Sbellard             break;
2848765b842aSRichard Henderson         case INDEX_op_insn_start:
2849c896fe29Sbellard             break;
28505ff9d6a4Sbellard         case INDEX_op_discard:
28515ff9d6a4Sbellard             /* mark the temporary as dead */
285225f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
285325f49c5fSRichard Henderson             ts->state = TS_DEAD;
285425f49c5fSRichard Henderson             la_reset_pref(ts);
28555ff9d6a4Sbellard             break;
28561305c451SRichard Henderson 
28571305c451SRichard Henderson         case INDEX_op_add2_i32:
2858c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
2859f1fae40cSRichard Henderson             goto do_addsub2;
28601305c451SRichard Henderson         case INDEX_op_sub2_i32:
2861c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
2862f1fae40cSRichard Henderson             goto do_addsub2;
2863f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
2864c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
2865f1fae40cSRichard Henderson             goto do_addsub2;
2866f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
2867c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
2868f1fae40cSRichard Henderson         do_addsub2:
28691305c451SRichard Henderson             nb_iargs = 4;
28701305c451SRichard Henderson             nb_oargs = 2;
28711305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
28721305c451SRichard Henderson                the low part.  The result can be optimized to a simple
28731305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
28741305c451SRichard Henderson                cpu mode is set to 32 bit.  */
2875b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2876b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
28771305c451SRichard Henderson                     goto do_remove;
28781305c451SRichard Henderson                 }
2879c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
2880c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
2881c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2882efee3746SRichard Henderson                 op->args[1] = op->args[2];
2883efee3746SRichard Henderson                 op->args[2] = op->args[4];
28841305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
28851305c451SRichard Henderson                 nb_iargs = 2;
28861305c451SRichard Henderson                 nb_oargs = 1;
28871305c451SRichard Henderson             }
28881305c451SRichard Henderson             goto do_not_remove;
28891305c451SRichard Henderson 
28901414968aSRichard Henderson         case INDEX_op_mulu2_i32:
2891c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2892c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
2893c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
289403271524SRichard Henderson             goto do_mul2;
2895f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
2896c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2897c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
2898c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
2899f1fae40cSRichard Henderson             goto do_mul2;
2900f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
2901c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2902c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
2903c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
290403271524SRichard Henderson             goto do_mul2;
2905f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
2906c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2907c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
2908c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
290903271524SRichard Henderson             goto do_mul2;
2910f1fae40cSRichard Henderson         do_mul2:
29111414968aSRichard Henderson             nb_iargs = 2;
29121414968aSRichard Henderson             nb_oargs = 2;
2913b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2914b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
291503271524SRichard Henderson                     /* Both parts of the operation are dead.  */
29161414968aSRichard Henderson                     goto do_remove;
29171414968aSRichard Henderson                 }
291803271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
2919c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2920efee3746SRichard Henderson                 op->args[1] = op->args[2];
2921efee3746SRichard Henderson                 op->args[2] = op->args[3];
2922b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
292303271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
2924c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
2925efee3746SRichard Henderson                 op->args[0] = op->args[1];
2926efee3746SRichard Henderson                 op->args[1] = op->args[2];
2927efee3746SRichard Henderson                 op->args[2] = op->args[3];
292803271524SRichard Henderson             } else {
292903271524SRichard Henderson                 goto do_not_remove;
293003271524SRichard Henderson             }
293103271524SRichard Henderson             /* Mark the single-word operation live.  */
29321414968aSRichard Henderson             nb_oargs = 1;
29331414968aSRichard Henderson             goto do_not_remove;
29341414968aSRichard Henderson 
2935c896fe29Sbellard         default:
29361305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
2937c896fe29Sbellard             nb_iargs = def->nb_iargs;
2938c896fe29Sbellard             nb_oargs = def->nb_oargs;
2939c896fe29Sbellard 
2940c896fe29Sbellard             /* Test if the operation can be removed because all
29415ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
29425ff9d6a4Sbellard                implies side effects */
29435ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
2944c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
2945b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
2946c896fe29Sbellard                         goto do_not_remove;
2947c896fe29Sbellard                     }
29489c43b68dSAurelien Jarno                 }
2949152c35aaSRichard Henderson                 goto do_remove;
2950152c35aaSRichard Henderson             }
2951152c35aaSRichard Henderson             goto do_not_remove;
2952152c35aaSRichard Henderson 
29531305c451SRichard Henderson         do_remove:
29540c627cdcSRichard Henderson             tcg_op_remove(s, op);
2955152c35aaSRichard Henderson             break;
2956152c35aaSRichard Henderson 
2957c896fe29Sbellard         do_not_remove:
2958c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
295925f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
296025f49c5fSRichard Henderson 
296125f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
296231fd884bSRichard Henderson                 if (i < ARRAY_SIZE(op->output_pref)) {
296325f49c5fSRichard Henderson                     op->output_pref[i] = *la_temp_pref(ts);
296431fd884bSRichard Henderson                 }
296525f49c5fSRichard Henderson 
296625f49c5fSRichard Henderson                 /* Output args are dead.  */
296725f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2968a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
29696b64b624SAurelien Jarno                 }
297025f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
2971a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
29729c43b68dSAurelien Jarno                 }
297325f49c5fSRichard Henderson                 ts->state = TS_DEAD;
297425f49c5fSRichard Henderson                 la_reset_pref(ts);
2975c896fe29Sbellard             }
2976c896fe29Sbellard 
297725f49c5fSRichard Henderson             /* If end of basic block, update.  */
2978ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
2979ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
2980b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_COND_BRANCH) {
2981b4cb76e6SRichard Henderson                 la_bb_sync(s, nb_globals, nb_temps);
2982ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
29832616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
29843d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
2985f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
298625f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
298725f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
298825f49c5fSRichard Henderson                 }
2989c896fe29Sbellard             }
2990c896fe29Sbellard 
299125f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
2992866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
299325f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
299425f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2995a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
2996c896fe29Sbellard                 }
2997c19f47bfSAurelien Jarno             }
299825f49c5fSRichard Henderson 
299925f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
3000c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
300125f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
300225f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
300325f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
300425f49c5fSRichard Henderson                        all regs for the type.  */
300525f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
300625f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
300725f49c5fSRichard Henderson                 }
300825f49c5fSRichard Henderson             }
300925f49c5fSRichard Henderson 
301025f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
301125f49c5fSRichard Henderson             switch (opc) {
301225f49c5fSRichard Henderson             case INDEX_op_mov_i32:
301325f49c5fSRichard Henderson             case INDEX_op_mov_i64:
301425f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
301525f49c5fSRichard Henderson                    have proper constraints.  That said, special case
301625f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
301725f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
301825f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
301925f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
302025f49c5fSRichard Henderson                 }
302125f49c5fSRichard Henderson                 break;
302225f49c5fSRichard Henderson 
302325f49c5fSRichard Henderson             default:
302425f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
302525f49c5fSRichard Henderson                     const TCGArgConstraint *ct = &def->args_ct[i];
302625f49c5fSRichard Henderson                     TCGRegSet set, *pset;
302725f49c5fSRichard Henderson 
302825f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
302925f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
303025f49c5fSRichard Henderson                     set = *pset;
303125f49c5fSRichard Henderson 
30329be0d080SRichard Henderson                     set &= ct->regs;
3033bc2b17e6SRichard Henderson                     if (ct->ialias) {
303431fd884bSRichard Henderson                         set &= output_pref(op, ct->alias_index);
303525f49c5fSRichard Henderson                     }
303625f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
303725f49c5fSRichard Henderson                     if (set == 0) {
30389be0d080SRichard Henderson                         set = ct->regs;
303925f49c5fSRichard Henderson                     }
304025f49c5fSRichard Henderson                     *pset = set;
304125f49c5fSRichard Henderson                 }
304225f49c5fSRichard Henderson                 break;
3043c896fe29Sbellard             }
3044c896fe29Sbellard             break;
3045c896fe29Sbellard         }
3046bee158cbSRichard Henderson         op->life = arg_life;
3047c896fe29Sbellard     }
30481ff0a2c5SEvgeny Voevodin }
3049c896fe29Sbellard 
30505a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
3051b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s)
30525a18407fSRichard Henderson {
30535a18407fSRichard Henderson     int nb_globals = s->nb_globals;
305415fa08f8SRichard Henderson     int nb_temps, i;
30555a18407fSRichard Henderson     bool changes = false;
305615fa08f8SRichard Henderson     TCGOp *op, *op_next;
30575a18407fSRichard Henderson 
30585a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
30595a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
30605a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
30615a18407fSRichard Henderson         if (its->indirect_reg) {
30625a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
30635a18407fSRichard Henderson             dts->type = its->type;
30645a18407fSRichard Henderson             dts->base_type = its->base_type;
3065c7482438SRichard Henderson             dts->kind = TEMP_EBB;
3066b83eabeaSRichard Henderson             its->state_ptr = dts;
3067b83eabeaSRichard Henderson         } else {
3068b83eabeaSRichard Henderson             its->state_ptr = NULL;
30695a18407fSRichard Henderson         }
3070b83eabeaSRichard Henderson         /* All globals begin dead.  */
3071b83eabeaSRichard Henderson         its->state = TS_DEAD;
30725a18407fSRichard Henderson     }
3073b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
3074b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
3075b83eabeaSRichard Henderson         its->state_ptr = NULL;
3076b83eabeaSRichard Henderson         its->state = TS_DEAD;
3077b83eabeaSRichard Henderson     }
30785a18407fSRichard Henderson 
307915fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
30805a18407fSRichard Henderson         TCGOpcode opc = op->opc;
30815a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
30825a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
30835a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
3084b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
30855a18407fSRichard Henderson 
30865a18407fSRichard Henderson         if (opc == INDEX_op_call) {
3087cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
3088cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
308990163900SRichard Henderson             call_flags = tcg_call_flags(op);
30905a18407fSRichard Henderson         } else {
30915a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
30925a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
30935a18407fSRichard Henderson 
30945a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
3095b4cb76e6SRichard Henderson             if (def->flags & TCG_OPF_COND_BRANCH) {
3096b4cb76e6SRichard Henderson                 /* Like reading globals: sync_globals */
3097b4cb76e6SRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
3098b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
30995a18407fSRichard Henderson                 /* Like writing globals: save_globals */
31005a18407fSRichard Henderson                 call_flags = 0;
31015a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
31025a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
31035a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
31045a18407fSRichard Henderson             } else {
31055a18407fSRichard Henderson                 /* No effect on globals.  */
31065a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
31075a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
31085a18407fSRichard Henderson             }
31095a18407fSRichard Henderson         }
31105a18407fSRichard Henderson 
31115a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
31125a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3113b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3114b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
3115b83eabeaSRichard Henderson             if (dir_ts && arg_ts->state == TS_DEAD) {
3116b83eabeaSRichard Henderson                 TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
31175a18407fSRichard Henderson                                   ? INDEX_op_ld_i32
31185a18407fSRichard Henderson                                   : INDEX_op_ld_i64);
3119d4478943SPhilippe Mathieu-Daudé                 TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3);
31205a18407fSRichard Henderson 
3121b83eabeaSRichard Henderson                 lop->args[0] = temp_arg(dir_ts);
3122b83eabeaSRichard Henderson                 lop->args[1] = temp_arg(arg_ts->mem_base);
3123b83eabeaSRichard Henderson                 lop->args[2] = arg_ts->mem_offset;
31245a18407fSRichard Henderson 
31255a18407fSRichard Henderson                 /* Loaded, but synced with memory.  */
3126b83eabeaSRichard Henderson                 arg_ts->state = TS_MEM;
31275a18407fSRichard Henderson             }
31285a18407fSRichard Henderson         }
31295a18407fSRichard Henderson 
31305a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
31315a18407fSRichard Henderson            No action is required except keeping temp_state up to date
31325a18407fSRichard Henderson            so that we reload when needed.  */
31335a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3134b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3135b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
3136b83eabeaSRichard Henderson             if (dir_ts) {
3137b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
31385a18407fSRichard Henderson                 changes = true;
31395a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3140b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
31415a18407fSRichard Henderson                 }
31425a18407fSRichard Henderson             }
31435a18407fSRichard Henderson         }
31445a18407fSRichard Henderson 
31455a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
31465a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
31475a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
31485a18407fSRichard Henderson             /* Nothing to do */
31495a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
31505a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
31515a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
31525a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
3153b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3154b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3155b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
31565a18407fSRichard Henderson             }
31575a18407fSRichard Henderson         } else {
31585a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
31595a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
31605a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
3161b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3162b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3163b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
31645a18407fSRichard Henderson             }
31655a18407fSRichard Henderson         }
31665a18407fSRichard Henderson 
31675a18407fSRichard Henderson         /* Outputs become available.  */
316861f15c48SRichard Henderson         if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) {
316961f15c48SRichard Henderson             arg_ts = arg_temp(op->args[0]);
317061f15c48SRichard Henderson             dir_ts = arg_ts->state_ptr;
317161f15c48SRichard Henderson             if (dir_ts) {
317261f15c48SRichard Henderson                 op->args[0] = temp_arg(dir_ts);
317361f15c48SRichard Henderson                 changes = true;
317461f15c48SRichard Henderson 
317561f15c48SRichard Henderson                 /* The output is now live and modified.  */
317661f15c48SRichard Henderson                 arg_ts->state = 0;
317761f15c48SRichard Henderson 
317861f15c48SRichard Henderson                 if (NEED_SYNC_ARG(0)) {
317961f15c48SRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
318061f15c48SRichard Henderson                                       ? INDEX_op_st_i32
318161f15c48SRichard Henderson                                       : INDEX_op_st_i64);
3182d4478943SPhilippe Mathieu-Daudé                     TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
318361f15c48SRichard Henderson                     TCGTemp *out_ts = dir_ts;
318461f15c48SRichard Henderson 
318561f15c48SRichard Henderson                     if (IS_DEAD_ARG(0)) {
318661f15c48SRichard Henderson                         out_ts = arg_temp(op->args[1]);
318761f15c48SRichard Henderson                         arg_ts->state = TS_DEAD;
318861f15c48SRichard Henderson                         tcg_op_remove(s, op);
318961f15c48SRichard Henderson                     } else {
319061f15c48SRichard Henderson                         arg_ts->state = TS_MEM;
319161f15c48SRichard Henderson                     }
319261f15c48SRichard Henderson 
319361f15c48SRichard Henderson                     sop->args[0] = temp_arg(out_ts);
319461f15c48SRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
319561f15c48SRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
319661f15c48SRichard Henderson                 } else {
319761f15c48SRichard Henderson                     tcg_debug_assert(!IS_DEAD_ARG(0));
319861f15c48SRichard Henderson                 }
319961f15c48SRichard Henderson             }
320061f15c48SRichard Henderson         } else {
32015a18407fSRichard Henderson             for (i = 0; i < nb_oargs; i++) {
3202b83eabeaSRichard Henderson                 arg_ts = arg_temp(op->args[i]);
3203b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3204b83eabeaSRichard Henderson                 if (!dir_ts) {
32055a18407fSRichard Henderson                     continue;
32065a18407fSRichard Henderson                 }
3207b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
32085a18407fSRichard Henderson                 changes = true;
32095a18407fSRichard Henderson 
32105a18407fSRichard Henderson                 /* The output is now live and modified.  */
3211b83eabeaSRichard Henderson                 arg_ts->state = 0;
32125a18407fSRichard Henderson 
32135a18407fSRichard Henderson                 /* Sync outputs upon their last write.  */
32145a18407fSRichard Henderson                 if (NEED_SYNC_ARG(i)) {
3215b83eabeaSRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
32165a18407fSRichard Henderson                                       ? INDEX_op_st_i32
32175a18407fSRichard Henderson                                       : INDEX_op_st_i64);
3218d4478943SPhilippe Mathieu-Daudé                     TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
32195a18407fSRichard Henderson 
3220b83eabeaSRichard Henderson                     sop->args[0] = temp_arg(dir_ts);
3221b83eabeaSRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
3222b83eabeaSRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
32235a18407fSRichard Henderson 
3224b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
32255a18407fSRichard Henderson                 }
32265a18407fSRichard Henderson                 /* Drop outputs that are dead.  */
32275a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3228b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
32295a18407fSRichard Henderson                 }
32305a18407fSRichard Henderson             }
32315a18407fSRichard Henderson         }
323261f15c48SRichard Henderson     }
32335a18407fSRichard Henderson 
32345a18407fSRichard Henderson     return changes;
32355a18407fSRichard Henderson }
32365a18407fSRichard Henderson 
32372272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
3238c896fe29Sbellard {
323931c96417SRichard Henderson     int size = tcg_type_size(ts->type);
324031c96417SRichard Henderson     int align;
324131c96417SRichard Henderson     intptr_t off;
3242c1c09194SRichard Henderson 
3243c1c09194SRichard Henderson     switch (ts->type) {
3244c1c09194SRichard Henderson     case TCG_TYPE_I32:
324531c96417SRichard Henderson         align = 4;
3246c1c09194SRichard Henderson         break;
3247c1c09194SRichard Henderson     case TCG_TYPE_I64:
3248c1c09194SRichard Henderson     case TCG_TYPE_V64:
324931c96417SRichard Henderson         align = 8;
3250c1c09194SRichard Henderson         break;
3251c1c09194SRichard Henderson     case TCG_TYPE_V128:
3252c1c09194SRichard Henderson     case TCG_TYPE_V256:
3253c1c09194SRichard Henderson         /* Note that we do not require aligned storage for V256. */
325431c96417SRichard Henderson         align = 16;
3255c1c09194SRichard Henderson         break;
3256c1c09194SRichard Henderson     default:
3257c1c09194SRichard Henderson         g_assert_not_reached();
3258b591dc59SBlue Swirl     }
3259c1c09194SRichard Henderson 
3260b9537d59SRichard Henderson     /*
3261b9537d59SRichard Henderson      * Assume the stack is sufficiently aligned.
3262b9537d59SRichard Henderson      * This affects e.g. ARM NEON, where we have 8 byte stack alignment
3263b9537d59SRichard Henderson      * and do not require 16 byte vector alignment.  This seems slightly
3264b9537d59SRichard Henderson      * easier than fully parameterizing the above switch statement.
3265b9537d59SRichard Henderson      */
3266b9537d59SRichard Henderson     align = MIN(TCG_TARGET_STACK_ALIGN, align);
3267c1c09194SRichard Henderson     off = ROUND_UP(s->current_frame_offset, align);
3268732d5897SRichard Henderson 
3269732d5897SRichard Henderson     /* If we've exhausted the stack frame, restart with a smaller TB. */
3270732d5897SRichard Henderson     if (off + size > s->frame_end) {
3271732d5897SRichard Henderson         tcg_raise_tb_overflow(s);
3272732d5897SRichard Henderson     }
3273c1c09194SRichard Henderson     s->current_frame_offset = off + size;
3274c1c09194SRichard Henderson 
3275c1c09194SRichard Henderson     ts->mem_offset = off;
32769defd1bdSRichard Henderson #if defined(__sparc__)
32779defd1bdSRichard Henderson     ts->mem_offset += TCG_TARGET_STACK_BIAS;
32789defd1bdSRichard Henderson #endif
3279b3a62939SRichard Henderson     ts->mem_base = s->frame_temp;
3280c896fe29Sbellard     ts->mem_allocated = 1;
3281c896fe29Sbellard }
3282c896fe29Sbellard 
3283098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */
3284098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg)
3285098859f1SRichard Henderson {
3286098859f1SRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
3287098859f1SRichard Henderson         TCGReg old = ts->reg;
3288098859f1SRichard Henderson         tcg_debug_assert(s->reg_to_temp[old] == ts);
3289098859f1SRichard Henderson         if (old == reg) {
3290098859f1SRichard Henderson             return;
3291098859f1SRichard Henderson         }
3292098859f1SRichard Henderson         s->reg_to_temp[old] = NULL;
3293098859f1SRichard Henderson     }
3294098859f1SRichard Henderson     tcg_debug_assert(s->reg_to_temp[reg] == NULL);
3295098859f1SRichard Henderson     s->reg_to_temp[reg] = ts;
3296098859f1SRichard Henderson     ts->val_type = TEMP_VAL_REG;
3297098859f1SRichard Henderson     ts->reg = reg;
3298098859f1SRichard Henderson }
3299098859f1SRichard Henderson 
3300098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */
3301098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type)
3302098859f1SRichard Henderson {
3303098859f1SRichard Henderson     tcg_debug_assert(type != TEMP_VAL_REG);
3304098859f1SRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
3305098859f1SRichard Henderson         TCGReg reg = ts->reg;
3306098859f1SRichard Henderson         tcg_debug_assert(s->reg_to_temp[reg] == ts);
3307098859f1SRichard Henderson         s->reg_to_temp[reg] = NULL;
3308098859f1SRichard Henderson     }
3309098859f1SRichard Henderson     ts->val_type = type;
3310098859f1SRichard Henderson }
3311098859f1SRichard Henderson 
3312b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
3313b3915dbbSRichard Henderson 
331459d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
331559d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
331659d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
3317c896fe29Sbellard {
3318c0522136SRichard Henderson     TCGTempVal new_type;
3319c0522136SRichard Henderson 
3320c0522136SRichard Henderson     switch (ts->kind) {
3321c0522136SRichard Henderson     case TEMP_FIXED:
332259d7c14eSRichard Henderson         return;
3323c0522136SRichard Henderson     case TEMP_GLOBAL:
3324c0522136SRichard Henderson     case TEMP_LOCAL:
3325c0522136SRichard Henderson         new_type = TEMP_VAL_MEM;
3326c0522136SRichard Henderson         break;
3327c0522136SRichard Henderson     case TEMP_NORMAL:
3328c7482438SRichard Henderson     case TEMP_EBB:
3329c0522136SRichard Henderson         new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD;
3330c0522136SRichard Henderson         break;
3331c0522136SRichard Henderson     case TEMP_CONST:
3332c0522136SRichard Henderson         new_type = TEMP_VAL_CONST;
3333c0522136SRichard Henderson         break;
3334c0522136SRichard Henderson     default:
3335c0522136SRichard Henderson         g_assert_not_reached();
333659d7c14eSRichard Henderson     }
3337098859f1SRichard Henderson     set_temp_val_nonreg(s, ts, new_type);
333859d7c14eSRichard Henderson }
3339c896fe29Sbellard 
334059d7c14eSRichard Henderson /* Mark a temporary as dead.  */
334159d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
334259d7c14eSRichard Henderson {
334359d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
334459d7c14eSRichard Henderson }
334559d7c14eSRichard Henderson 
334659d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
334759d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
334859d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
334959d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
335098b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
335198b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
335259d7c14eSRichard Henderson {
3353c0522136SRichard Henderson     if (!temp_readonly(ts) && !ts->mem_coherent) {
33547f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
33552272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
335659d7c14eSRichard Henderson         }
335759d7c14eSRichard Henderson         switch (ts->val_type) {
335859d7c14eSRichard Henderson         case TEMP_VAL_CONST:
335959d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
336059d7c14eSRichard Henderson                require it later in a register, so attempt to store the
336159d7c14eSRichard Henderson                constant to memory directly.  */
336259d7c14eSRichard Henderson             if (free_or_dead
336359d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
336459d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
336559d7c14eSRichard Henderson                 break;
336659d7c14eSRichard Henderson             }
336759d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
336898b4e186SRichard Henderson                       allocated_regs, preferred_regs);
336959d7c14eSRichard Henderson             /* fallthrough */
337059d7c14eSRichard Henderson 
337159d7c14eSRichard Henderson         case TEMP_VAL_REG:
337259d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
337359d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
337459d7c14eSRichard Henderson             break;
337559d7c14eSRichard Henderson 
337659d7c14eSRichard Henderson         case TEMP_VAL_MEM:
337759d7c14eSRichard Henderson             break;
337859d7c14eSRichard Henderson 
337959d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
338059d7c14eSRichard Henderson         default:
338159d7c14eSRichard Henderson             tcg_abort();
3382c896fe29Sbellard         }
33837f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
33847f6ceedfSAurelien Jarno     }
338559d7c14eSRichard Henderson     if (free_or_dead) {
338659d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
338759d7c14eSRichard Henderson     }
338859d7c14eSRichard Henderson }
33897f6ceedfSAurelien Jarno 
33907f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
3391b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
33927f6ceedfSAurelien Jarno {
3393f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
3394f8b2f202SRichard Henderson     if (ts != NULL) {
339598b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
3396c896fe29Sbellard     }
3397c896fe29Sbellard }
3398c896fe29Sbellard 
3399b016486eSRichard Henderson /**
3400b016486eSRichard Henderson  * tcg_reg_alloc:
3401b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
3402b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
3403b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
3404b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
3405b016486eSRichard Henderson  *
3406b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
3407b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
3408b016486eSRichard Henderson  */
3409b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
3410b016486eSRichard Henderson                             TCGRegSet allocated_regs,
3411b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
3412c896fe29Sbellard {
3413b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
3414b016486eSRichard Henderson     TCGRegSet reg_ct[2];
341591478cefSRichard Henderson     const int *order;
3416c896fe29Sbellard 
3417b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
3418b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
3419b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
3420b016486eSRichard Henderson 
3421b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
3422b016486eSRichard Henderson        or if the preference made no difference.  */
3423b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
3424b016486eSRichard Henderson 
342591478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
3426c896fe29Sbellard 
3427b016486eSRichard Henderson     /* Try free registers, preferences first.  */
3428b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3429b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3430b016486eSRichard Henderson 
3431b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3432b016486eSRichard Henderson             /* One register in the set.  */
3433b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3434b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
3435c896fe29Sbellard                 return reg;
3436c896fe29Sbellard             }
3437b016486eSRichard Henderson         } else {
343891478cefSRichard Henderson             for (i = 0; i < n; i++) {
3439b016486eSRichard Henderson                 TCGReg reg = order[i];
3440b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
3441b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
3442b016486eSRichard Henderson                     return reg;
3443b016486eSRichard Henderson                 }
3444b016486eSRichard Henderson             }
3445b016486eSRichard Henderson         }
3446b016486eSRichard Henderson     }
3447b016486eSRichard Henderson 
3448b016486eSRichard Henderson     /* We must spill something.  */
3449b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3450b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3451b016486eSRichard Henderson 
3452b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3453b016486eSRichard Henderson             /* One register in the set.  */
3454b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3455b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
3456c896fe29Sbellard             return reg;
3457b016486eSRichard Henderson         } else {
3458b016486eSRichard Henderson             for (i = 0; i < n; i++) {
3459b016486eSRichard Henderson                 TCGReg reg = order[i];
3460b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
3461b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
3462b016486eSRichard Henderson                     return reg;
3463b016486eSRichard Henderson                 }
3464b016486eSRichard Henderson             }
3465c896fe29Sbellard         }
3466c896fe29Sbellard     }
3467c896fe29Sbellard 
3468c896fe29Sbellard     tcg_abort();
3469c896fe29Sbellard }
3470c896fe29Sbellard 
347129f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs,
347229f5e925SRichard Henderson                                  TCGRegSet allocated_regs,
347329f5e925SRichard Henderson                                  TCGRegSet preferred_regs, bool rev)
347429f5e925SRichard Henderson {
347529f5e925SRichard Henderson     int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
347629f5e925SRichard Henderson     TCGRegSet reg_ct[2];
347729f5e925SRichard Henderson     const int *order;
347829f5e925SRichard Henderson 
347929f5e925SRichard Henderson     /* Ensure that if I is not in allocated_regs, I+1 is not either. */
348029f5e925SRichard Henderson     reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1));
348129f5e925SRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
348229f5e925SRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
348329f5e925SRichard Henderson 
348429f5e925SRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
348529f5e925SRichard Henderson 
348629f5e925SRichard Henderson     /*
348729f5e925SRichard Henderson      * Skip the preferred_regs option if it cannot be satisfied,
348829f5e925SRichard Henderson      * or if the preference made no difference.
348929f5e925SRichard Henderson      */
349029f5e925SRichard Henderson     k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
349129f5e925SRichard Henderson 
349229f5e925SRichard Henderson     /*
349329f5e925SRichard Henderson      * Minimize the number of flushes by looking for 2 free registers first,
349429f5e925SRichard Henderson      * then a single flush, then two flushes.
349529f5e925SRichard Henderson      */
349629f5e925SRichard Henderson     for (fmin = 2; fmin >= 0; fmin--) {
349729f5e925SRichard Henderson         for (j = k; j < 2; j++) {
349829f5e925SRichard Henderson             TCGRegSet set = reg_ct[j];
349929f5e925SRichard Henderson 
350029f5e925SRichard Henderson             for (i = 0; i < n; i++) {
350129f5e925SRichard Henderson                 TCGReg reg = order[i];
350229f5e925SRichard Henderson 
350329f5e925SRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
350429f5e925SRichard Henderson                     int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1];
350529f5e925SRichard Henderson                     if (f >= fmin) {
350629f5e925SRichard Henderson                         tcg_reg_free(s, reg, allocated_regs);
350729f5e925SRichard Henderson                         tcg_reg_free(s, reg + 1, allocated_regs);
350829f5e925SRichard Henderson                         return reg;
350929f5e925SRichard Henderson                     }
351029f5e925SRichard Henderson                 }
351129f5e925SRichard Henderson             }
351229f5e925SRichard Henderson         }
351329f5e925SRichard Henderson     }
351429f5e925SRichard Henderson     tcg_abort();
351529f5e925SRichard Henderson }
351629f5e925SRichard Henderson 
351740ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
351840ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
351940ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
3520b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
352140ae5c62SRichard Henderson {
352240ae5c62SRichard Henderson     TCGReg reg;
352340ae5c62SRichard Henderson 
352440ae5c62SRichard Henderson     switch (ts->val_type) {
352540ae5c62SRichard Henderson     case TEMP_VAL_REG:
352640ae5c62SRichard Henderson         return;
352740ae5c62SRichard Henderson     case TEMP_VAL_CONST:
3528b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3529b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
35300a6a8bc8SRichard Henderson         if (ts->type <= TCG_TYPE_I64) {
353140ae5c62SRichard Henderson             tcg_out_movi(s, ts->type, reg, ts->val);
35320a6a8bc8SRichard Henderson         } else {
35334e186175SRichard Henderson             uint64_t val = ts->val;
35344e186175SRichard Henderson             MemOp vece = MO_64;
35354e186175SRichard Henderson 
35364e186175SRichard Henderson             /*
35374e186175SRichard Henderson              * Find the minimal vector element that matches the constant.
35384e186175SRichard Henderson              * The targets will, in general, have to do this search anyway,
35394e186175SRichard Henderson              * do this generically.
35404e186175SRichard Henderson              */
35414e186175SRichard Henderson             if (val == dup_const(MO_8, val)) {
35424e186175SRichard Henderson                 vece = MO_8;
35434e186175SRichard Henderson             } else if (val == dup_const(MO_16, val)) {
35444e186175SRichard Henderson                 vece = MO_16;
35450b4286ddSRichard Henderson             } else if (val == dup_const(MO_32, val)) {
35464e186175SRichard Henderson                 vece = MO_32;
35474e186175SRichard Henderson             }
35484e186175SRichard Henderson 
35494e186175SRichard Henderson             tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val);
35500a6a8bc8SRichard Henderson         }
355140ae5c62SRichard Henderson         ts->mem_coherent = 0;
355240ae5c62SRichard Henderson         break;
355340ae5c62SRichard Henderson     case TEMP_VAL_MEM:
3554b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3555b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
355640ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
355740ae5c62SRichard Henderson         ts->mem_coherent = 1;
355840ae5c62SRichard Henderson         break;
355940ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
356040ae5c62SRichard Henderson     default:
356140ae5c62SRichard Henderson         tcg_abort();
356240ae5c62SRichard Henderson     }
3563098859f1SRichard Henderson     set_temp_val_reg(s, ts, reg);
356440ae5c62SRichard Henderson }
356540ae5c62SRichard Henderson 
356659d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
3567e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
356859d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
35691ad80729SAurelien Jarno {
35702c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
3571eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
3572e01fa97dSRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts));
35731ad80729SAurelien Jarno }
35741ad80729SAurelien Jarno 
35759814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
3576641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
3577641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
3578641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
3579641d5fbeSbellard {
3580ac3b8891SRichard Henderson     int i, n;
3581641d5fbeSbellard 
3582ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
3583b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
3584641d5fbeSbellard     }
3585e5097dc8Sbellard }
3586e5097dc8Sbellard 
35873d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
35883d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
35893d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
35903d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
35913d5c5f87SAurelien Jarno {
3592ac3b8891SRichard Henderson     int i, n;
35933d5c5f87SAurelien Jarno 
3594ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
359512b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
359612b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
3597ee17db83SRichard Henderson                          || ts->kind == TEMP_FIXED
359812b9b11aSRichard Henderson                          || ts->mem_coherent);
35993d5c5f87SAurelien Jarno     }
36003d5c5f87SAurelien Jarno }
36013d5c5f87SAurelien Jarno 
3602e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
3603e8996ee0Sbellard    all globals are stored at their canonical location. */
3604e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
3605e5097dc8Sbellard {
3606e5097dc8Sbellard     int i;
3607e5097dc8Sbellard 
3608c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
3609b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
3610c0522136SRichard Henderson 
3611c0522136SRichard Henderson         switch (ts->kind) {
3612c0522136SRichard Henderson         case TEMP_LOCAL:
3613b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
3614c0522136SRichard Henderson             break;
3615c0522136SRichard Henderson         case TEMP_NORMAL:
3616c7482438SRichard Henderson         case TEMP_EBB:
36172c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
3618eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
3619eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3620c0522136SRichard Henderson             break;
3621c0522136SRichard Henderson         case TEMP_CONST:
3622c0522136SRichard Henderson             /* Similarly, we should have freed any allocated register. */
3623c0522136SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_CONST);
3624c0522136SRichard Henderson             break;
3625c0522136SRichard Henderson         default:
3626c0522136SRichard Henderson             g_assert_not_reached();
3627c896fe29Sbellard         }
3628641d5fbeSbellard     }
3629e8996ee0Sbellard 
3630e8996ee0Sbellard     save_globals(s, allocated_regs);
3631c896fe29Sbellard }
3632c896fe29Sbellard 
3633bab1671fSRichard Henderson /*
3634c7482438SRichard Henderson  * At a conditional branch, we assume all temporaries are dead unless
3635c7482438SRichard Henderson  * explicitly live-across-conditional-branch; all globals and local
3636c7482438SRichard Henderson  * temps are synced to their location.
3637b4cb76e6SRichard Henderson  */
3638b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
3639b4cb76e6SRichard Henderson {
3640b4cb76e6SRichard Henderson     sync_globals(s, allocated_regs);
3641b4cb76e6SRichard Henderson 
3642b4cb76e6SRichard Henderson     for (int i = s->nb_globals; i < s->nb_temps; i++) {
3643b4cb76e6SRichard Henderson         TCGTemp *ts = &s->temps[i];
3644b4cb76e6SRichard Henderson         /*
3645b4cb76e6SRichard Henderson          * The liveness analysis already ensures that temps are dead.
3646b4cb76e6SRichard Henderson          * Keep tcg_debug_asserts for safety.
3647b4cb76e6SRichard Henderson          */
3648c0522136SRichard Henderson         switch (ts->kind) {
3649c0522136SRichard Henderson         case TEMP_LOCAL:
3650b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
3651c0522136SRichard Henderson             break;
3652c0522136SRichard Henderson         case TEMP_NORMAL:
3653b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3654c0522136SRichard Henderson             break;
3655c7482438SRichard Henderson         case TEMP_EBB:
3656c0522136SRichard Henderson         case TEMP_CONST:
3657c0522136SRichard Henderson             break;
3658c0522136SRichard Henderson         default:
3659c0522136SRichard Henderson             g_assert_not_reached();
3660b4cb76e6SRichard Henderson         }
3661b4cb76e6SRichard Henderson     }
3662b4cb76e6SRichard Henderson }
3663b4cb76e6SRichard Henderson 
3664b4cb76e6SRichard Henderson /*
3665c58f4c97SRichard Henderson  * Specialized code generation for INDEX_op_mov_* with a constant.
3666bab1671fSRichard Henderson  */
36670fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
3668ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
3669ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
3670e8996ee0Sbellard {
3671d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3672e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
367359d7c14eSRichard Henderson 
367459d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
3675098859f1SRichard Henderson     set_temp_val_nonreg(s, ots, TEMP_VAL_CONST);
3676e8996ee0Sbellard     ots->val = val;
367759d7c14eSRichard Henderson     ots->mem_coherent = 0;
3678ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
3679ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
368059d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
3681f8bf00f1SRichard Henderson         temp_dead(s, ots);
36824c4e1ab2SAurelien Jarno     }
3683e8996ee0Sbellard }
3684e8996ee0Sbellard 
3685bab1671fSRichard Henderson /*
3686bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
3687bab1671fSRichard Henderson  */
3688dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
3689c896fe29Sbellard {
3690dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
369169e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
3692c896fe29Sbellard     TCGTemp *ts, *ots;
3693450445d5SRichard Henderson     TCGType otype, itype;
3694098859f1SRichard Henderson     TCGReg oreg, ireg;
3695c896fe29Sbellard 
3696d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
369731fd884bSRichard Henderson     preferred_regs = output_pref(op, 0);
369843439139SRichard Henderson     ots = arg_temp(op->args[0]);
369943439139SRichard Henderson     ts = arg_temp(op->args[1]);
3700450445d5SRichard Henderson 
3701d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3702e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
3703d63e3b6eSRichard Henderson 
3704450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
3705450445d5SRichard Henderson     otype = ots->type;
3706450445d5SRichard Henderson     itype = ts->type;
3707c896fe29Sbellard 
37080fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
37090fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
37100fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
37110fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
37120fe4fca4SPaolo Bonzini             temp_dead(s, ts);
37130fe4fca4SPaolo Bonzini         }
371469e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
37150fe4fca4SPaolo Bonzini         return;
37160fe4fca4SPaolo Bonzini     }
37170fe4fca4SPaolo Bonzini 
37180fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
37190fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
37200fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
37210fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
37220fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
372369e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
372469e3706dSRichard Henderson                   allocated_regs, preferred_regs);
3725c29c1d7eSAurelien Jarno     }
37260fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
3727098859f1SRichard Henderson     ireg = ts->reg;
3728098859f1SRichard Henderson 
3729d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
3730c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
3731c29c1d7eSAurelien Jarno            liveness analysis disabled). */
3732eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
3733c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
37342272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
3735c29c1d7eSAurelien Jarno         }
3736098859f1SRichard Henderson         tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset);
3737c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
3738f8bf00f1SRichard Henderson             temp_dead(s, ts);
3739c29c1d7eSAurelien Jarno         }
3740f8bf00f1SRichard Henderson         temp_dead(s, ots);
3741098859f1SRichard Henderson         return;
3742098859f1SRichard Henderson     }
3743098859f1SRichard Henderson 
3744ee17db83SRichard Henderson     if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) {
3745098859f1SRichard Henderson         /*
3746098859f1SRichard Henderson          * The mov can be suppressed.  Kill input first, so that it
3747098859f1SRichard Henderson          * is unlinked from reg_to_temp, then set the output to the
3748098859f1SRichard Henderson          * reg that we saved from the input.
3749098859f1SRichard Henderson          */
3750f8bf00f1SRichard Henderson         temp_dead(s, ts);
3751098859f1SRichard Henderson         oreg = ireg;
3752c29c1d7eSAurelien Jarno     } else {
3753098859f1SRichard Henderson         if (ots->val_type == TEMP_VAL_REG) {
3754098859f1SRichard Henderson             oreg = ots->reg;
3755098859f1SRichard Henderson         } else {
3756098859f1SRichard Henderson             /* Make sure to not spill the input register during allocation. */
3757098859f1SRichard Henderson             oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
3758098859f1SRichard Henderson                                  allocated_regs | ((TCGRegSet)1 << ireg),
3759098859f1SRichard Henderson                                  preferred_regs, ots->indirect_base);
3760c29c1d7eSAurelien Jarno         }
3761098859f1SRichard Henderson         if (!tcg_out_mov(s, otype, oreg, ireg)) {
3762240c08d0SRichard Henderson             /*
3763240c08d0SRichard Henderson              * Cross register class move not supported.
3764240c08d0SRichard Henderson              * Store the source register into the destination slot
3765240c08d0SRichard Henderson              * and leave the destination temp as TEMP_VAL_MEM.
3766240c08d0SRichard Henderson              */
3767e01fa97dSRichard Henderson             assert(!temp_readonly(ots));
3768240c08d0SRichard Henderson             if (!ts->mem_allocated) {
3769240c08d0SRichard Henderson                 temp_allocate_frame(s, ots);
3770240c08d0SRichard Henderson             }
3771098859f1SRichard Henderson             tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset);
3772098859f1SRichard Henderson             set_temp_val_nonreg(s, ts, TEMP_VAL_MEM);
3773240c08d0SRichard Henderson             ots->mem_coherent = 1;
3774240c08d0SRichard Henderson             return;
377578113e83SRichard Henderson         }
3776c29c1d7eSAurelien Jarno     }
3777098859f1SRichard Henderson     set_temp_val_reg(s, ots, oreg);
3778c896fe29Sbellard     ots->mem_coherent = 0;
3779098859f1SRichard Henderson 
3780ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
378198b4e186SRichard Henderson         temp_sync(s, ots, allocated_regs, 0, 0);
3782c29c1d7eSAurelien Jarno     }
3783ec7a869dSAurelien Jarno }
3784c896fe29Sbellard 
3785bab1671fSRichard Henderson /*
3786bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
3787bab1671fSRichard Henderson  */
3788bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
3789bab1671fSRichard Henderson {
3790bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
3791bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
3792bab1671fSRichard Henderson     TCGTemp *its, *ots;
3793bab1671fSRichard Henderson     TCGType itype, vtype;
3794bab1671fSRichard Henderson     unsigned vece;
379531c96417SRichard Henderson     int lowpart_ofs;
3796bab1671fSRichard Henderson     bool ok;
3797bab1671fSRichard Henderson 
3798bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
3799bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
3800bab1671fSRichard Henderson 
3801bab1671fSRichard Henderson     /* ENV should not be modified.  */
3802e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
3803bab1671fSRichard Henderson 
3804bab1671fSRichard Henderson     itype = its->type;
3805bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
3806bab1671fSRichard Henderson     vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
3807bab1671fSRichard Henderson 
3808bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
3809bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
3810bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
3811bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
3812bab1671fSRichard Henderson             temp_dead(s, its);
3813bab1671fSRichard Henderson         }
381431fd884bSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0));
3815bab1671fSRichard Henderson         return;
3816bab1671fSRichard Henderson     }
3817bab1671fSRichard Henderson 
38189be0d080SRichard Henderson     dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
38199be0d080SRichard Henderson     dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs;
3820bab1671fSRichard Henderson 
3821bab1671fSRichard Henderson     /* Allocate the output register now.  */
3822bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
3823bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
3824098859f1SRichard Henderson         TCGReg oreg;
3825bab1671fSRichard Henderson 
3826bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
3827bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
3828bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
3829bab1671fSRichard Henderson         }
3830098859f1SRichard Henderson         oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
383131fd884bSRichard Henderson                              output_pref(op, 0), ots->indirect_base);
3832098859f1SRichard Henderson         set_temp_val_reg(s, ots, oreg);
3833bab1671fSRichard Henderson     }
3834bab1671fSRichard Henderson 
3835bab1671fSRichard Henderson     switch (its->val_type) {
3836bab1671fSRichard Henderson     case TEMP_VAL_REG:
3837bab1671fSRichard Henderson         /*
3838bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
3839bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
3840bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
3841bab1671fSRichard Henderson          */
3842bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
3843bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
3844bab1671fSRichard Henderson                 goto done;
3845bab1671fSRichard Henderson             }
3846bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
3847bab1671fSRichard Henderson         }
3848bab1671fSRichard Henderson         if (!its->mem_coherent) {
3849bab1671fSRichard Henderson             /*
3850bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
3851bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
3852bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
3853bab1671fSRichard Henderson              */
3854bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
3855bab1671fSRichard Henderson                 break;
3856bab1671fSRichard Henderson             }
3857bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
3858bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
3859bab1671fSRichard Henderson         }
3860bab1671fSRichard Henderson         /* fall through */
3861bab1671fSRichard Henderson 
3862bab1671fSRichard Henderson     case TEMP_VAL_MEM:
386331c96417SRichard Henderson         lowpart_ofs = 0;
386431c96417SRichard Henderson         if (HOST_BIG_ENDIAN) {
386531c96417SRichard Henderson             lowpart_ofs = tcg_type_size(itype) - (1 << vece);
386631c96417SRichard Henderson         }
3867d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
386831c96417SRichard Henderson                              its->mem_offset + lowpart_ofs)) {
3869d6ecb4a9SRichard Henderson             goto done;
3870d6ecb4a9SRichard Henderson         }
3871098859f1SRichard Henderson         /* Load the input into the destination vector register. */
3872bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
3873bab1671fSRichard Henderson         break;
3874bab1671fSRichard Henderson 
3875bab1671fSRichard Henderson     default:
3876bab1671fSRichard Henderson         g_assert_not_reached();
3877bab1671fSRichard Henderson     }
3878bab1671fSRichard Henderson 
3879bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
3880bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
3881bab1671fSRichard Henderson     tcg_debug_assert(ok);
3882bab1671fSRichard Henderson 
3883bab1671fSRichard Henderson  done:
388436f5539cSRichard Henderson     ots->mem_coherent = 0;
3885bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
3886bab1671fSRichard Henderson         temp_dead(s, its);
3887bab1671fSRichard Henderson     }
3888bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
3889bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
3890bab1671fSRichard Henderson     }
3891bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
3892bab1671fSRichard Henderson         temp_dead(s, ots);
3893bab1671fSRichard Henderson     }
3894bab1671fSRichard Henderson }
3895bab1671fSRichard Henderson 
3896dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
3897c896fe29Sbellard {
3898dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3899dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
390082790a87SRichard Henderson     TCGRegSet i_allocated_regs;
390182790a87SRichard Henderson     TCGRegSet o_allocated_regs;
3902b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
3903b6638662SRichard Henderson     TCGReg reg;
3904c896fe29Sbellard     TCGArg arg;
3905c896fe29Sbellard     const TCGArgConstraint *arg_ct;
3906c896fe29Sbellard     TCGTemp *ts;
3907c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
3908c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
3909c896fe29Sbellard 
3910c896fe29Sbellard     nb_oargs = def->nb_oargs;
3911c896fe29Sbellard     nb_iargs = def->nb_iargs;
3912c896fe29Sbellard 
3913c896fe29Sbellard     /* copy constants */
3914c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
3915dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
3916c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
3917c896fe29Sbellard 
3918d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
3919d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
392082790a87SRichard Henderson 
3921c896fe29Sbellard     /* satisfy input constraints */
3922c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
392329f5e925SRichard Henderson         TCGRegSet i_preferred_regs, i_required_regs;
392429f5e925SRichard Henderson         bool allocate_new_reg, copyto_new_reg;
392529f5e925SRichard Henderson         TCGTemp *ts2;
392629f5e925SRichard Henderson         int i1, i2;
3927d62816f2SRichard Henderson 
392866792f90SRichard Henderson         i = def->args_ct[nb_oargs + k].sort_index;
3929dd186292SRichard Henderson         arg = op->args[i];
3930c896fe29Sbellard         arg_ct = &def->args_ct[i];
393143439139SRichard Henderson         ts = arg_temp(arg);
393240ae5c62SRichard Henderson 
393340ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
3934a4fbbd77SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct->ct)) {
3935c896fe29Sbellard             /* constant is OK for instruction */
3936c896fe29Sbellard             const_args[i] = 1;
3937c896fe29Sbellard             new_args[i] = ts->val;
3938d62816f2SRichard Henderson             continue;
3939c896fe29Sbellard         }
394040ae5c62SRichard Henderson 
39411c1824dcSRichard Henderson         reg = ts->reg;
39421c1824dcSRichard Henderson         i_preferred_regs = 0;
394329f5e925SRichard Henderson         i_required_regs = arg_ct->regs;
39441c1824dcSRichard Henderson         allocate_new_reg = false;
394529f5e925SRichard Henderson         copyto_new_reg = false;
39461c1824dcSRichard Henderson 
394729f5e925SRichard Henderson         switch (arg_ct->pair) {
394829f5e925SRichard Henderson         case 0: /* not paired */
3949bc2b17e6SRichard Henderson             if (arg_ct->ialias) {
395031fd884bSRichard Henderson                 i_preferred_regs = output_pref(op, arg_ct->alias_index);
3951c0522136SRichard Henderson 
3952c0522136SRichard Henderson                 /*
3953c0522136SRichard Henderson                  * If the input is readonly, then it cannot also be an
3954c0522136SRichard Henderson                  * output and aliased to itself.  If the input is not
3955c0522136SRichard Henderson                  * dead after the instruction, we must allocate a new
3956c0522136SRichard Henderson                  * register and move it.
3957c0522136SRichard Henderson                  */
3958c0522136SRichard Henderson                 if (temp_readonly(ts) || !IS_DEAD_ARG(i)) {
39591c1824dcSRichard Henderson                     allocate_new_reg = true;
39601c1824dcSRichard Henderson                 } else if (ts->val_type == TEMP_VAL_REG) {
3961c0522136SRichard Henderson                     /*
39621c1824dcSRichard Henderson                      * Check if the current register has already been
39631c1824dcSRichard Henderson                      * allocated for another input.
3964c0522136SRichard Henderson                      */
396529f5e925SRichard Henderson                     allocate_new_reg =
396629f5e925SRichard Henderson                         tcg_regset_test_reg(i_allocated_regs, reg);
39677e1df267SAurelien Jarno                 }
39687e1df267SAurelien Jarno             }
39691c1824dcSRichard Henderson             if (!allocate_new_reg) {
397029f5e925SRichard Henderson                 temp_load(s, ts, i_required_regs, i_allocated_regs,
397129f5e925SRichard Henderson                           i_preferred_regs);
3972c896fe29Sbellard                 reg = ts->reg;
397329f5e925SRichard Henderson                 allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg);
39741c1824dcSRichard Henderson             }
39751c1824dcSRichard Henderson             if (allocate_new_reg) {
3976c0522136SRichard Henderson                 /*
3977c0522136SRichard Henderson                  * Allocate a new register matching the constraint
3978c0522136SRichard Henderson                  * and move the temporary register into it.
3979c0522136SRichard Henderson                  */
3980d62816f2SRichard Henderson                 temp_load(s, ts, tcg_target_available_regs[ts->type],
3981d62816f2SRichard Henderson                           i_allocated_regs, 0);
398229f5e925SRichard Henderson                 reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs,
39831c1824dcSRichard Henderson                                     i_preferred_regs, ts->indirect_base);
398429f5e925SRichard Henderson                 copyto_new_reg = true;
398529f5e925SRichard Henderson             }
398629f5e925SRichard Henderson             break;
398729f5e925SRichard Henderson 
398829f5e925SRichard Henderson         case 1:
398929f5e925SRichard Henderson             /* First of an input pair; if i1 == i2, the second is an output. */
399029f5e925SRichard Henderson             i1 = i;
399129f5e925SRichard Henderson             i2 = arg_ct->pair_index;
399229f5e925SRichard Henderson             ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL;
399329f5e925SRichard Henderson 
399429f5e925SRichard Henderson             /*
399529f5e925SRichard Henderson              * It is easier to default to allocating a new pair
399629f5e925SRichard Henderson              * and to identify a few cases where it's not required.
399729f5e925SRichard Henderson              */
399829f5e925SRichard Henderson             if (arg_ct->ialias) {
399931fd884bSRichard Henderson                 i_preferred_regs = output_pref(op, arg_ct->alias_index);
400029f5e925SRichard Henderson                 if (IS_DEAD_ARG(i1) &&
400129f5e925SRichard Henderson                     IS_DEAD_ARG(i2) &&
400229f5e925SRichard Henderson                     !temp_readonly(ts) &&
400329f5e925SRichard Henderson                     ts->val_type == TEMP_VAL_REG &&
400429f5e925SRichard Henderson                     ts->reg < TCG_TARGET_NB_REGS - 1 &&
400529f5e925SRichard Henderson                     tcg_regset_test_reg(i_required_regs, reg) &&
400629f5e925SRichard Henderson                     !tcg_regset_test_reg(i_allocated_regs, reg) &&
400729f5e925SRichard Henderson                     !tcg_regset_test_reg(i_allocated_regs, reg + 1) &&
400829f5e925SRichard Henderson                     (ts2
400929f5e925SRichard Henderson                      ? ts2->val_type == TEMP_VAL_REG &&
401029f5e925SRichard Henderson                        ts2->reg == reg + 1 &&
401129f5e925SRichard Henderson                        !temp_readonly(ts2)
401229f5e925SRichard Henderson                      : s->reg_to_temp[reg + 1] == NULL)) {
401329f5e925SRichard Henderson                     break;
401429f5e925SRichard Henderson                 }
401529f5e925SRichard Henderson             } else {
401629f5e925SRichard Henderson                 /* Without aliasing, the pair must also be an input. */
401729f5e925SRichard Henderson                 tcg_debug_assert(ts2);
401829f5e925SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG &&
401929f5e925SRichard Henderson                     ts2->val_type == TEMP_VAL_REG &&
402029f5e925SRichard Henderson                     ts2->reg == reg + 1 &&
402129f5e925SRichard Henderson                     tcg_regset_test_reg(i_required_regs, reg)) {
402229f5e925SRichard Henderson                     break;
402329f5e925SRichard Henderson                 }
402429f5e925SRichard Henderson             }
402529f5e925SRichard Henderson             reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs,
402629f5e925SRichard Henderson                                      0, ts->indirect_base);
402729f5e925SRichard Henderson             goto do_pair;
402829f5e925SRichard Henderson 
402929f5e925SRichard Henderson         case 2: /* pair second */
403029f5e925SRichard Henderson             reg = new_args[arg_ct->pair_index] + 1;
403129f5e925SRichard Henderson             goto do_pair;
403229f5e925SRichard Henderson 
403329f5e925SRichard Henderson         case 3: /* ialias with second output, no first input */
403429f5e925SRichard Henderson             tcg_debug_assert(arg_ct->ialias);
403531fd884bSRichard Henderson             i_preferred_regs = output_pref(op, arg_ct->alias_index);
403629f5e925SRichard Henderson 
403729f5e925SRichard Henderson             if (IS_DEAD_ARG(i) &&
403829f5e925SRichard Henderson                 !temp_readonly(ts) &&
403929f5e925SRichard Henderson                 ts->val_type == TEMP_VAL_REG &&
404029f5e925SRichard Henderson                 reg > 0 &&
404129f5e925SRichard Henderson                 s->reg_to_temp[reg - 1] == NULL &&
404229f5e925SRichard Henderson                 tcg_regset_test_reg(i_required_regs, reg) &&
404329f5e925SRichard Henderson                 !tcg_regset_test_reg(i_allocated_regs, reg) &&
404429f5e925SRichard Henderson                 !tcg_regset_test_reg(i_allocated_regs, reg - 1)) {
404529f5e925SRichard Henderson                 tcg_regset_set_reg(i_allocated_regs, reg - 1);
404629f5e925SRichard Henderson                 break;
404729f5e925SRichard Henderson             }
404829f5e925SRichard Henderson             reg = tcg_reg_alloc_pair(s, i_required_regs >> 1,
404929f5e925SRichard Henderson                                      i_allocated_regs, 0,
405029f5e925SRichard Henderson                                      ts->indirect_base);
405129f5e925SRichard Henderson             tcg_regset_set_reg(i_allocated_regs, reg);
405229f5e925SRichard Henderson             reg += 1;
405329f5e925SRichard Henderson             goto do_pair;
405429f5e925SRichard Henderson 
405529f5e925SRichard Henderson         do_pair:
405629f5e925SRichard Henderson             /*
405729f5e925SRichard Henderson              * If an aliased input is not dead after the instruction,
405829f5e925SRichard Henderson              * we must allocate a new register and move it.
405929f5e925SRichard Henderson              */
406029f5e925SRichard Henderson             if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) {
406129f5e925SRichard Henderson                 TCGRegSet t_allocated_regs = i_allocated_regs;
406229f5e925SRichard Henderson 
406329f5e925SRichard Henderson                 /*
406429f5e925SRichard Henderson                  * Because of the alias, and the continued life, make sure
406529f5e925SRichard Henderson                  * that the temp is somewhere *other* than the reg pair,
406629f5e925SRichard Henderson                  * and we get a copy in reg.
406729f5e925SRichard Henderson                  */
406829f5e925SRichard Henderson                 tcg_regset_set_reg(t_allocated_regs, reg);
406929f5e925SRichard Henderson                 tcg_regset_set_reg(t_allocated_regs, reg + 1);
407029f5e925SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) {
407129f5e925SRichard Henderson                     /* If ts was already in reg, copy it somewhere else. */
407229f5e925SRichard Henderson                     TCGReg nr;
407329f5e925SRichard Henderson                     bool ok;
407429f5e925SRichard Henderson 
407529f5e925SRichard Henderson                     tcg_debug_assert(ts->kind != TEMP_FIXED);
407629f5e925SRichard Henderson                     nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
407729f5e925SRichard Henderson                                        t_allocated_regs, 0, ts->indirect_base);
407829f5e925SRichard Henderson                     ok = tcg_out_mov(s, ts->type, nr, reg);
407929f5e925SRichard Henderson                     tcg_debug_assert(ok);
408029f5e925SRichard Henderson 
408129f5e925SRichard Henderson                     set_temp_val_reg(s, ts, nr);
408229f5e925SRichard Henderson                 } else {
408329f5e925SRichard Henderson                     temp_load(s, ts, tcg_target_available_regs[ts->type],
408429f5e925SRichard Henderson                               t_allocated_regs, 0);
408529f5e925SRichard Henderson                     copyto_new_reg = true;
408629f5e925SRichard Henderson                 }
408729f5e925SRichard Henderson             } else {
408829f5e925SRichard Henderson                 /* Preferably allocate to reg, otherwise copy. */
408929f5e925SRichard Henderson                 i_required_regs = (TCGRegSet)1 << reg;
409029f5e925SRichard Henderson                 temp_load(s, ts, i_required_regs, i_allocated_regs,
409129f5e925SRichard Henderson                           i_preferred_regs);
409229f5e925SRichard Henderson                 copyto_new_reg = ts->reg != reg;
409329f5e925SRichard Henderson             }
409429f5e925SRichard Henderson             break;
409529f5e925SRichard Henderson 
409629f5e925SRichard Henderson         default:
409729f5e925SRichard Henderson             g_assert_not_reached();
409829f5e925SRichard Henderson         }
409929f5e925SRichard Henderson 
410029f5e925SRichard Henderson         if (copyto_new_reg) {
410178113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4102240c08d0SRichard Henderson                 /*
4103240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
4104240c08d0SRichard Henderson                  * temp back to its slot and load from there.
4105240c08d0SRichard Henderson                  */
4106240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
4107240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
4108240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
410978113e83SRichard Henderson             }
4110c896fe29Sbellard         }
4111c896fe29Sbellard         new_args[i] = reg;
4112c896fe29Sbellard         const_args[i] = 0;
411382790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
4114c896fe29Sbellard     }
4115c896fe29Sbellard 
4116c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
4117866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
4118866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
411943439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4120c896fe29Sbellard         }
4121c896fe29Sbellard     }
4122c896fe29Sbellard 
4123b4cb76e6SRichard Henderson     if (def->flags & TCG_OPF_COND_BRANCH) {
4124b4cb76e6SRichard Henderson         tcg_reg_alloc_cbranch(s, i_allocated_regs);
4125b4cb76e6SRichard Henderson     } else if (def->flags & TCG_OPF_BB_END) {
412682790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
4127a52ad07eSAurelien Jarno     } else {
4128c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
4129b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
4130c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4131c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
413282790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
4133c896fe29Sbellard                 }
4134c896fe29Sbellard             }
41353d5c5f87SAurelien Jarno         }
41363d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
41373d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
41383d5c5f87SAurelien Jarno                an exception. */
413982790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
4140c896fe29Sbellard         }
4141c896fe29Sbellard 
4142c896fe29Sbellard         /* satisfy the output constraints */
4143c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
414466792f90SRichard Henderson             i = def->args_ct[k].sort_index;
4145dd186292SRichard Henderson             arg = op->args[i];
4146c896fe29Sbellard             arg_ct = &def->args_ct[i];
414743439139SRichard Henderson             ts = arg_temp(arg);
4148d63e3b6eSRichard Henderson 
4149d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
4150e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
4151d63e3b6eSRichard Henderson 
415229f5e925SRichard Henderson             switch (arg_ct->pair) {
415329f5e925SRichard Henderson             case 0: /* not paired */
4154bc2b17e6SRichard Henderson                 if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
41555ff9d6a4Sbellard                     reg = new_args[arg_ct->alias_index];
4156bc2b17e6SRichard Henderson                 } else if (arg_ct->newreg) {
41579be0d080SRichard Henderson                     reg = tcg_reg_alloc(s, arg_ct->regs,
415882790a87SRichard Henderson                                         i_allocated_regs | o_allocated_regs,
415931fd884bSRichard Henderson                                         output_pref(op, k), ts->indirect_base);
4160c896fe29Sbellard                 } else {
41619be0d080SRichard Henderson                     reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
416231fd884bSRichard Henderson                                         output_pref(op, k), ts->indirect_base);
4163c896fe29Sbellard                 }
416429f5e925SRichard Henderson                 break;
416529f5e925SRichard Henderson 
416629f5e925SRichard Henderson             case 1: /* first of pair */
416729f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
416829f5e925SRichard Henderson                 if (arg_ct->oalias) {
416929f5e925SRichard Henderson                     reg = new_args[arg_ct->alias_index];
417029f5e925SRichard Henderson                     break;
417129f5e925SRichard Henderson                 }
417229f5e925SRichard Henderson                 reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs,
417331fd884bSRichard Henderson                                          output_pref(op, k), ts->indirect_base);
417429f5e925SRichard Henderson                 break;
417529f5e925SRichard Henderson 
417629f5e925SRichard Henderson             case 2: /* second of pair */
417729f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
417829f5e925SRichard Henderson                 if (arg_ct->oalias) {
417929f5e925SRichard Henderson                     reg = new_args[arg_ct->alias_index];
418029f5e925SRichard Henderson                 } else {
418129f5e925SRichard Henderson                     reg = new_args[arg_ct->pair_index] + 1;
418229f5e925SRichard Henderson                 }
418329f5e925SRichard Henderson                 break;
418429f5e925SRichard Henderson 
418529f5e925SRichard Henderson             case 3: /* first of pair, aliasing with a second input */
418629f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
418729f5e925SRichard Henderson                 reg = new_args[arg_ct->pair_index] - 1;
418829f5e925SRichard Henderson                 break;
418929f5e925SRichard Henderson 
419029f5e925SRichard Henderson             default:
419129f5e925SRichard Henderson                 g_assert_not_reached();
419229f5e925SRichard Henderson             }
419382790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
4194098859f1SRichard Henderson             set_temp_val_reg(s, ts, reg);
4195c896fe29Sbellard             ts->mem_coherent = 0;
4196c896fe29Sbellard             new_args[i] = reg;
4197c896fe29Sbellard         }
4198e8996ee0Sbellard     }
4199c896fe29Sbellard 
4200c896fe29Sbellard     /* emit instruction */
4201d2fd745fSRichard Henderson     if (def->flags & TCG_OPF_VECTOR) {
4202d2fd745fSRichard Henderson         tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
4203d2fd745fSRichard Henderson                        new_args, const_args);
4204d2fd745fSRichard Henderson     } else {
4205dd186292SRichard Henderson         tcg_out_op(s, op->opc, new_args, const_args);
4206d2fd745fSRichard Henderson     }
4207c896fe29Sbellard 
4208c896fe29Sbellard     /* move the outputs in the correct register if needed */
4209c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
421043439139SRichard Henderson         ts = arg_temp(op->args[i]);
4211d63e3b6eSRichard Henderson 
4212d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
4213e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
4214d63e3b6eSRichard Henderson 
4215ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
421698b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
421759d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4218f8bf00f1SRichard Henderson             temp_dead(s, ts);
4219ec7a869dSAurelien Jarno         }
4220c896fe29Sbellard     }
4221c896fe29Sbellard }
4222c896fe29Sbellard 
4223efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op)
4224efe86b21SRichard Henderson {
4225efe86b21SRichard Henderson     const TCGLifeData arg_life = op->life;
4226efe86b21SRichard Henderson     TCGTemp *ots, *itsl, *itsh;
4227efe86b21SRichard Henderson     TCGType vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
4228efe86b21SRichard Henderson 
4229efe86b21SRichard Henderson     /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */
4230efe86b21SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 32);
4231efe86b21SRichard Henderson     tcg_debug_assert(TCGOP_VECE(op) == MO_64);
4232efe86b21SRichard Henderson 
4233efe86b21SRichard Henderson     ots = arg_temp(op->args[0]);
4234efe86b21SRichard Henderson     itsl = arg_temp(op->args[1]);
4235efe86b21SRichard Henderson     itsh = arg_temp(op->args[2]);
4236efe86b21SRichard Henderson 
4237efe86b21SRichard Henderson     /* ENV should not be modified.  */
4238efe86b21SRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4239efe86b21SRichard Henderson 
4240efe86b21SRichard Henderson     /* Allocate the output register now.  */
4241efe86b21SRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
4242efe86b21SRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
4243efe86b21SRichard Henderson         TCGRegSet dup_out_regs =
4244efe86b21SRichard Henderson             tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
4245098859f1SRichard Henderson         TCGReg oreg;
4246efe86b21SRichard Henderson 
4247efe86b21SRichard Henderson         /* Make sure to not spill the input registers. */
4248efe86b21SRichard Henderson         if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) {
4249efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsl->reg);
4250efe86b21SRichard Henderson         }
4251efe86b21SRichard Henderson         if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) {
4252efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsh->reg);
4253efe86b21SRichard Henderson         }
4254efe86b21SRichard Henderson 
4255098859f1SRichard Henderson         oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
425631fd884bSRichard Henderson                              output_pref(op, 0), ots->indirect_base);
4257098859f1SRichard Henderson         set_temp_val_reg(s, ots, oreg);
4258efe86b21SRichard Henderson     }
4259efe86b21SRichard Henderson 
4260efe86b21SRichard Henderson     /* Promote dup2 of immediates to dupi_vec. */
4261efe86b21SRichard Henderson     if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) {
4262efe86b21SRichard Henderson         uint64_t val = deposit64(itsl->val, 32, 32, itsh->val);
4263efe86b21SRichard Henderson         MemOp vece = MO_64;
4264efe86b21SRichard Henderson 
4265efe86b21SRichard Henderson         if (val == dup_const(MO_8, val)) {
4266efe86b21SRichard Henderson             vece = MO_8;
4267efe86b21SRichard Henderson         } else if (val == dup_const(MO_16, val)) {
4268efe86b21SRichard Henderson             vece = MO_16;
4269efe86b21SRichard Henderson         } else if (val == dup_const(MO_32, val)) {
4270efe86b21SRichard Henderson             vece = MO_32;
4271efe86b21SRichard Henderson         }
4272efe86b21SRichard Henderson 
4273efe86b21SRichard Henderson         tcg_out_dupi_vec(s, vtype, vece, ots->reg, val);
4274efe86b21SRichard Henderson         goto done;
4275efe86b21SRichard Henderson     }
4276efe86b21SRichard Henderson 
4277efe86b21SRichard Henderson     /* If the two inputs form one 64-bit value, try dupm_vec. */
4278aef85402SRichard Henderson     if (itsl->temp_subindex == HOST_BIG_ENDIAN &&
4279aef85402SRichard Henderson         itsh->temp_subindex == !HOST_BIG_ENDIAN &&
4280aef85402SRichard Henderson         itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) {
4281aef85402SRichard Henderson         TCGTemp *its = itsl - HOST_BIG_ENDIAN;
4282aef85402SRichard Henderson 
4283aef85402SRichard Henderson         temp_sync(s, its + 0, s->reserved_regs, 0, 0);
4284aef85402SRichard Henderson         temp_sync(s, its + 1, s->reserved_regs, 0, 0);
4285aef85402SRichard Henderson 
4286efe86b21SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg,
4287efe86b21SRichard Henderson                              its->mem_base->reg, its->mem_offset)) {
4288efe86b21SRichard Henderson             goto done;
4289efe86b21SRichard Henderson         }
4290efe86b21SRichard Henderson     }
4291efe86b21SRichard Henderson 
4292efe86b21SRichard Henderson     /* Fall back to generic expansion. */
4293efe86b21SRichard Henderson     return false;
4294efe86b21SRichard Henderson 
4295efe86b21SRichard Henderson  done:
429636f5539cSRichard Henderson     ots->mem_coherent = 0;
4297efe86b21SRichard Henderson     if (IS_DEAD_ARG(1)) {
4298efe86b21SRichard Henderson         temp_dead(s, itsl);
4299efe86b21SRichard Henderson     }
4300efe86b21SRichard Henderson     if (IS_DEAD_ARG(2)) {
4301efe86b21SRichard Henderson         temp_dead(s, itsh);
4302efe86b21SRichard Henderson     }
4303efe86b21SRichard Henderson     if (NEED_SYNC_ARG(0)) {
4304efe86b21SRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0));
4305efe86b21SRichard Henderson     } else if (IS_DEAD_ARG(0)) {
4306efe86b21SRichard Henderson         temp_dead(s, ots);
4307efe86b21SRichard Henderson     }
4308efe86b21SRichard Henderson     return true;
4309efe86b21SRichard Henderson }
4310efe86b21SRichard Henderson 
431139004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts,
431239004a71SRichard Henderson                          TCGRegSet allocated_regs)
4313c896fe29Sbellard {
4314c896fe29Sbellard     if (ts->val_type == TEMP_VAL_REG) {
4315c896fe29Sbellard         if (ts->reg != reg) {
43164250da10SRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
431778113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4318240c08d0SRichard Henderson                 /*
4319240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
4320240c08d0SRichard Henderson                  * temp back to its slot and load from there.
4321240c08d0SRichard Henderson                  */
4322240c08d0SRichard Henderson                 temp_sync(s, ts, allocated_regs, 0, 0);
4323240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
4324240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
432578113e83SRichard Henderson             }
4326c896fe29Sbellard         }
4327c896fe29Sbellard     } else {
4328ccb1bb66SRichard Henderson         TCGRegSet arg_set = 0;
432940ae5c62SRichard Henderson 
43304250da10SRichard Henderson         tcg_reg_free(s, reg, allocated_regs);
433140ae5c62SRichard Henderson         tcg_regset_set_reg(arg_set, reg);
4332b722452aSRichard Henderson         temp_load(s, ts, arg_set, allocated_regs, 0);
4333c896fe29Sbellard     }
433439004a71SRichard Henderson }
433540ae5c62SRichard Henderson 
433639004a71SRichard Henderson static void load_arg_stk(TCGContext *s, int stk_slot, TCGTemp *ts,
433739004a71SRichard Henderson                          TCGRegSet allocated_regs)
433839004a71SRichard Henderson {
433939004a71SRichard Henderson     /*
434039004a71SRichard Henderson      * When the destination is on the stack, load up the temp and store.
434139004a71SRichard Henderson      * If there are many call-saved registers, the temp might live to
434239004a71SRichard Henderson      * see another use; otherwise it'll be discarded.
434339004a71SRichard Henderson      */
434439004a71SRichard Henderson     temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0);
434539004a71SRichard Henderson     tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK,
434639004a71SRichard Henderson                TCG_TARGET_CALL_STACK_OFFSET +
434739004a71SRichard Henderson                stk_slot * sizeof(tcg_target_long));
434839004a71SRichard Henderson }
434939004a71SRichard Henderson 
435039004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l,
435139004a71SRichard Henderson                             TCGTemp *ts, TCGRegSet *allocated_regs)
435239004a71SRichard Henderson {
435339004a71SRichard Henderson     if (REG_P(l)) {
435439004a71SRichard Henderson         TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot];
435539004a71SRichard Henderson         load_arg_reg(s, reg, ts, *allocated_regs);
435639004a71SRichard Henderson         tcg_regset_set_reg(*allocated_regs, reg);
435739004a71SRichard Henderson     } else {
435839004a71SRichard Henderson         load_arg_stk(s, l->arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs),
435939004a71SRichard Henderson                      ts, *allocated_regs);
4360c896fe29Sbellard     }
436139cf05d3Sbellard }
4362c896fe29Sbellard 
436339004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
436439004a71SRichard Henderson {
436539004a71SRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
436639004a71SRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
436739004a71SRichard Henderson     const TCGLifeData arg_life = op->life;
436839004a71SRichard Henderson     const TCGHelperInfo *info = tcg_call_info(op);
436939004a71SRichard Henderson     TCGRegSet allocated_regs = s->reserved_regs;
437039004a71SRichard Henderson     int i;
437139004a71SRichard Henderson 
437239004a71SRichard Henderson     /*
437339004a71SRichard Henderson      * Move inputs into place in reverse order,
437439004a71SRichard Henderson      * so that we place stacked arguments first.
437539004a71SRichard Henderson      */
437639004a71SRichard Henderson     for (i = nb_iargs - 1; i >= 0; --i) {
437739004a71SRichard Henderson         const TCGCallArgumentLoc *loc = &info->in[i];
437839004a71SRichard Henderson         TCGTemp *ts = arg_temp(op->args[nb_oargs + i]);
437939004a71SRichard Henderson 
438039004a71SRichard Henderson         switch (loc->kind) {
438139004a71SRichard Henderson         case TCG_CALL_ARG_NORMAL:
438239004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
438339004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
438439004a71SRichard Henderson             load_arg_normal(s, loc, ts, &allocated_regs);
438539004a71SRichard Henderson             break;
438639004a71SRichard Henderson         default:
438739004a71SRichard Henderson             g_assert_not_reached();
438839004a71SRichard Henderson         }
438939004a71SRichard Henderson     }
439039004a71SRichard Henderson 
439139004a71SRichard Henderson     /* Mark dead temporaries and free the associated registers.  */
4392866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4393866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
439443439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4395c896fe29Sbellard         }
4396c896fe29Sbellard     }
4397c896fe29Sbellard 
439839004a71SRichard Henderson     /* Clobber call registers.  */
4399c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4400c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
4401b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
4402c896fe29Sbellard         }
4403c896fe29Sbellard     }
4404c896fe29Sbellard 
440539004a71SRichard Henderson     /*
440639004a71SRichard Henderson      * Save globals if they might be written by the helper,
440739004a71SRichard Henderson      * sync them if they might be read.
440839004a71SRichard Henderson      */
440939004a71SRichard Henderson     if (info->flags & TCG_CALL_NO_READ_GLOBALS) {
441078505279SAurelien Jarno         /* Nothing to do */
441139004a71SRichard Henderson     } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) {
441278505279SAurelien Jarno         sync_globals(s, allocated_regs);
441378505279SAurelien Jarno     } else {
4414e8996ee0Sbellard         save_globals(s, allocated_regs);
4415b9c18f56Saurel32     }
4416c896fe29Sbellard 
4417cee44b03SRichard Henderson     tcg_out_call(s, tcg_call_func(op), info);
4418c896fe29Sbellard 
441939004a71SRichard Henderson     /* Assign output registers and emit moves if needed.  */
442039004a71SRichard Henderson     switch (info->out_kind) {
442139004a71SRichard Henderson     case TCG_CALL_RET_NORMAL:
4422c896fe29Sbellard         for (i = 0; i < nb_oargs; i++) {
442339004a71SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
442439004a71SRichard Henderson             TCGReg reg = tcg_target_call_oarg_regs[i];
4425d63e3b6eSRichard Henderson 
4426d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
4427e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
4428d63e3b6eSRichard Henderson 
4429098859f1SRichard Henderson             set_temp_val_reg(s, ts, reg);
4430c896fe29Sbellard             ts->mem_coherent = 0;
443139004a71SRichard Henderson         }
443239004a71SRichard Henderson         break;
443339004a71SRichard Henderson     default:
443439004a71SRichard Henderson         g_assert_not_reached();
443539004a71SRichard Henderson     }
443639004a71SRichard Henderson 
443739004a71SRichard Henderson     /* Flush or discard output registers as needed. */
443839004a71SRichard Henderson     for (i = 0; i < nb_oargs; i++) {
443939004a71SRichard Henderson         TCGTemp *ts = arg_temp(op->args[i]);
4440ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
444139004a71SRichard Henderson             temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i));
444259d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4443f8bf00f1SRichard Henderson             temp_dead(s, ts);
4444c896fe29Sbellard         }
4445c896fe29Sbellard     }
44468c11ad25SAurelien Jarno }
4447c896fe29Sbellard 
4448c896fe29Sbellard #ifdef CONFIG_PROFILER
4449c896fe29Sbellard 
4450c3fac113SEmilio G. Cota /* avoid copy/paste errors */
4451c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field)                       \
4452c3fac113SEmilio G. Cota     do {                                                \
4453d73415a3SStefan Hajnoczi         (to)->field += qatomic_read(&((from)->field));  \
4454c3fac113SEmilio G. Cota     } while (0)
4455c896fe29Sbellard 
4456c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field)                                       \
4457c3fac113SEmilio G. Cota     do {                                                                \
4458d73415a3SStefan Hajnoczi         typeof((from)->field) val__ = qatomic_read(&((from)->field));   \
4459c3fac113SEmilio G. Cota         if (val__ > (to)->field) {                                      \
4460c3fac113SEmilio G. Cota             (to)->field = val__;                                        \
4461c3fac113SEmilio G. Cota         }                                                               \
4462c3fac113SEmilio G. Cota     } while (0)
4463c3fac113SEmilio G. Cota 
4464c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */
4465c3fac113SEmilio G. Cota static inline
4466c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
4467c896fe29Sbellard {
44680e2d61cfSRichard Henderson     unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
4469c3fac113SEmilio G. Cota     unsigned int i;
4470c3fac113SEmilio G. Cota 
44713468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4472d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
44733468b59eSEmilio G. Cota         const TCGProfile *orig = &s->prof;
4474c3fac113SEmilio G. Cota 
4475c3fac113SEmilio G. Cota         if (counters) {
447672fd2efbSEmilio G. Cota             PROF_ADD(prof, orig, cpu_exec_time);
4477c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count1);
4478c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count);
4479c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, op_count);
4480c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, op_count_max);
4481c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, temp_count);
4482c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, temp_count_max);
4483c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, del_op_count);
4484c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_in_len);
4485c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_out_len);
4486c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, search_out_len);
4487c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, interm_time);
4488c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_time);
4489c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, la_time);
4490c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, opt_time);
4491c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_count);
4492c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_time);
4493c3fac113SEmilio G. Cota         }
4494c3fac113SEmilio G. Cota         if (table) {
4495c896fe29Sbellard             int i;
4496d70724ceSzhanghailiang 
449715fc7daaSRichard Henderson             for (i = 0; i < NB_OPS; i++) {
4498c3fac113SEmilio G. Cota                 PROF_ADD(prof, orig, table_op_count[i]);
4499c3fac113SEmilio G. Cota             }
4500c3fac113SEmilio G. Cota         }
4501c3fac113SEmilio G. Cota     }
4502c3fac113SEmilio G. Cota }
4503c3fac113SEmilio G. Cota 
4504c3fac113SEmilio G. Cota #undef PROF_ADD
4505c3fac113SEmilio G. Cota #undef PROF_MAX
4506c3fac113SEmilio G. Cota 
4507c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof)
4508c3fac113SEmilio G. Cota {
4509c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, true, false);
4510c3fac113SEmilio G. Cota }
4511c3fac113SEmilio G. Cota 
4512c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof)
4513c3fac113SEmilio G. Cota {
4514c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, false, true);
4515c3fac113SEmilio G. Cota }
4516c3fac113SEmilio G. Cota 
4517b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf)
4518c3fac113SEmilio G. Cota {
4519c3fac113SEmilio G. Cota     TCGProfile prof = {};
4520c3fac113SEmilio G. Cota     int i;
4521c3fac113SEmilio G. Cota 
4522c3fac113SEmilio G. Cota     tcg_profile_snapshot_table(&prof);
4523c3fac113SEmilio G. Cota     for (i = 0; i < NB_OPS; i++) {
4524b6a7f3e0SDaniel P. Berrangé         g_string_append_printf(buf, "%s %" PRId64 "\n", tcg_op_defs[i].name,
4525c3fac113SEmilio G. Cota                                prof.table_op_count[i]);
4526c896fe29Sbellard     }
4527c896fe29Sbellard }
452872fd2efbSEmilio G. Cota 
452972fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
453072fd2efbSEmilio G. Cota {
45310e2d61cfSRichard Henderson     unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
453272fd2efbSEmilio G. Cota     unsigned int i;
453372fd2efbSEmilio G. Cota     int64_t ret = 0;
453472fd2efbSEmilio G. Cota 
453572fd2efbSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4536d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
453772fd2efbSEmilio G. Cota         const TCGProfile *prof = &s->prof;
453872fd2efbSEmilio G. Cota 
4539d73415a3SStefan Hajnoczi         ret += qatomic_read(&prof->cpu_exec_time);
454072fd2efbSEmilio G. Cota     }
454172fd2efbSEmilio G. Cota     return ret;
454272fd2efbSEmilio G. Cota }
4543246ae24dSMax Filippov #else
4544b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf)
4545246ae24dSMax Filippov {
4546b6a7f3e0SDaniel P. Berrangé     g_string_append_printf(buf, "[TCG profiler not compiled]\n");
4547246ae24dSMax Filippov }
454872fd2efbSEmilio G. Cota 
454972fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
455072fd2efbSEmilio G. Cota {
455172fd2efbSEmilio G. Cota     error_report("%s: TCG profiler not compiled", __func__);
455272fd2efbSEmilio G. Cota     exit(EXIT_FAILURE);
455372fd2efbSEmilio G. Cota }
4554c896fe29Sbellard #endif
4555c896fe29Sbellard 
4556c896fe29Sbellard 
4557fbf59aadSRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start)
4558c896fe29Sbellard {
4559c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER
4560c3fac113SEmilio G. Cota     TCGProfile *prof = &s->prof;
4561c3fac113SEmilio G. Cota #endif
456215fa08f8SRichard Henderson     int i, num_insns;
456315fa08f8SRichard Henderson     TCGOp *op;
4564c896fe29Sbellard 
456504fe6400SRichard Henderson #ifdef CONFIG_PROFILER
456604fe6400SRichard Henderson     {
4567c1f543b7SEmilio G. Cota         int n = 0;
456804fe6400SRichard Henderson 
456915fa08f8SRichard Henderson         QTAILQ_FOREACH(op, &s->ops, link) {
457015fa08f8SRichard Henderson             n++;
457115fa08f8SRichard Henderson         }
4572d73415a3SStefan Hajnoczi         qatomic_set(&prof->op_count, prof->op_count + n);
4573c3fac113SEmilio G. Cota         if (n > prof->op_count_max) {
4574d73415a3SStefan Hajnoczi             qatomic_set(&prof->op_count_max, n);
457504fe6400SRichard Henderson         }
457604fe6400SRichard Henderson 
457704fe6400SRichard Henderson         n = s->nb_temps;
4578d73415a3SStefan Hajnoczi         qatomic_set(&prof->temp_count, prof->temp_count + n);
4579c3fac113SEmilio G. Cota         if (n > prof->temp_count_max) {
4580d73415a3SStefan Hajnoczi             qatomic_set(&prof->temp_count_max, n);
458104fe6400SRichard Henderson         }
458204fe6400SRichard Henderson     }
458304fe6400SRichard Henderson #endif
458404fe6400SRichard Henderson 
4585c896fe29Sbellard #ifdef DEBUG_DISAS
4586d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
4587fbf59aadSRichard Henderson                  && qemu_log_in_addr_range(pc_start))) {
4588c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
458978b54858SRichard Henderson         if (logfile) {
459078b54858SRichard Henderson             fprintf(logfile, "OP:\n");
4591b7a83ff8SRichard Henderson             tcg_dump_ops(s, logfile, false);
459278b54858SRichard Henderson             fprintf(logfile, "\n");
4593fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
4594c896fe29Sbellard         }
459578b54858SRichard Henderson     }
4596c896fe29Sbellard #endif
4597c896fe29Sbellard 
4598bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
4599bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
4600bef16ab4SRichard Henderson     {
4601bef16ab4SRichard Henderson         TCGLabel *l;
4602bef16ab4SRichard Henderson         bool error = false;
4603bef16ab4SRichard Henderson 
4604bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
4605bef16ab4SRichard Henderson             if (unlikely(!l->present) && l->refs) {
4606bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
4607bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
4608bef16ab4SRichard Henderson                 error = true;
4609bef16ab4SRichard Henderson             }
4610bef16ab4SRichard Henderson         }
4611bef16ab4SRichard Henderson         assert(!error);
4612bef16ab4SRichard Henderson     }
4613bef16ab4SRichard Henderson #endif
4614bef16ab4SRichard Henderson 
4615c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
4616d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
4617c5cc28ffSAurelien Jarno #endif
4618c5cc28ffSAurelien Jarno 
46198f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
4620c45cb8bbSRichard Henderson     tcg_optimize(s);
46218f2e8c07SKirill Batuzov #endif
46228f2e8c07SKirill Batuzov 
4623a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4624d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
4625d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time - profile_getclock());
4626a23a9ec6Sbellard #endif
4627c5cc28ffSAurelien Jarno 
4628b4fc67c7SRichard Henderson     reachable_code_pass(s);
4629b83eabeaSRichard Henderson     liveness_pass_1(s);
46305a18407fSRichard Henderson 
46315a18407fSRichard Henderson     if (s->nb_indirects > 0) {
46325a18407fSRichard Henderson #ifdef DEBUG_DISAS
46335a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
4634fbf59aadSRichard Henderson                      && qemu_log_in_addr_range(pc_start))) {
4635c60f599bSRichard Henderson             FILE *logfile = qemu_log_trylock();
463678b54858SRichard Henderson             if (logfile) {
463778b54858SRichard Henderson                 fprintf(logfile, "OP before indirect lowering:\n");
4638b7a83ff8SRichard Henderson                 tcg_dump_ops(s, logfile, false);
463978b54858SRichard Henderson                 fprintf(logfile, "\n");
4640fc59d2d8SRobert Foley                 qemu_log_unlock(logfile);
46415a18407fSRichard Henderson             }
464278b54858SRichard Henderson         }
46435a18407fSRichard Henderson #endif
46445a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
4645b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
46465a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
4647b83eabeaSRichard Henderson             liveness_pass_1(s);
46485a18407fSRichard Henderson         }
46495a18407fSRichard Henderson     }
4650c5cc28ffSAurelien Jarno 
4651a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4652d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time + profile_getclock());
4653a23a9ec6Sbellard #endif
4654c896fe29Sbellard 
4655c896fe29Sbellard #ifdef DEBUG_DISAS
4656d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
4657fbf59aadSRichard Henderson                  && qemu_log_in_addr_range(pc_start))) {
4658c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
465978b54858SRichard Henderson         if (logfile) {
466078b54858SRichard Henderson             fprintf(logfile, "OP after optimization and liveness analysis:\n");
4661b7a83ff8SRichard Henderson             tcg_dump_ops(s, logfile, true);
466278b54858SRichard Henderson             fprintf(logfile, "\n");
4663fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
4664c896fe29Sbellard         }
466578b54858SRichard Henderson     }
4666c896fe29Sbellard #endif
4667c896fe29Sbellard 
466835abb009SRichard Henderson     /* Initialize goto_tb jump offsets. */
46693a50f424SRichard Henderson     tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID;
46703a50f424SRichard Henderson     tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID;
4671*9da6079bSRichard Henderson     tb->jmp_insn_offset[0] = TB_JMP_OFFSET_INVALID;
4672*9da6079bSRichard Henderson     tb->jmp_insn_offset[1] = TB_JMP_OFFSET_INVALID;
467335abb009SRichard Henderson 
4674c896fe29Sbellard     tcg_reg_alloc_start(s);
4675c896fe29Sbellard 
4676db0c51a3SRichard Henderson     /*
4677db0c51a3SRichard Henderson      * Reset the buffer pointers when restarting after overflow.
4678db0c51a3SRichard Henderson      * TODO: Move this into translate-all.c with the rest of the
4679db0c51a3SRichard Henderson      * buffer management.  Having only this done here is confusing.
4680db0c51a3SRichard Henderson      */
4681db0c51a3SRichard Henderson     s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr);
4682db0c51a3SRichard Henderson     s->code_ptr = s->code_buf;
4683c896fe29Sbellard 
4684659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
46856001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
4686659ef5cbSRichard Henderson #endif
468757a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
468857a26946SRichard Henderson     s->pool_labels = NULL;
468957a26946SRichard Henderson #endif
46909ecefc84SRichard Henderson 
4691fca8a500SRichard Henderson     num_insns = -1;
469215fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
4693c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
4694b3db8758Sblueswir1 
4695c896fe29Sbellard #ifdef CONFIG_PROFILER
4696d73415a3SStefan Hajnoczi         qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
4697c896fe29Sbellard #endif
4698c45cb8bbSRichard Henderson 
4699c896fe29Sbellard         switch (opc) {
4700c896fe29Sbellard         case INDEX_op_mov_i32:
4701c896fe29Sbellard         case INDEX_op_mov_i64:
4702d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
4703dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
4704c896fe29Sbellard             break;
4705bab1671fSRichard Henderson         case INDEX_op_dup_vec:
4706bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
4707bab1671fSRichard Henderson             break;
4708765b842aSRichard Henderson         case INDEX_op_insn_start:
4709fca8a500SRichard Henderson             if (num_insns >= 0) {
47109f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
47119f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
47129f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
47139f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
4714fca8a500SRichard Henderson             }
4715fca8a500SRichard Henderson             num_insns++;
4716bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
4717bad729e2SRichard Henderson                 target_ulong a;
4718bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
4719efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
4720bad729e2SRichard Henderson #else
4721efee3746SRichard Henderson                 a = op->args[i];
4722bad729e2SRichard Henderson #endif
4723fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
4724bad729e2SRichard Henderson             }
4725c896fe29Sbellard             break;
47265ff9d6a4Sbellard         case INDEX_op_discard:
472743439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
47285ff9d6a4Sbellard             break;
4729c896fe29Sbellard         case INDEX_op_set_label:
4730e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
473192ab8e7dSRichard Henderson             tcg_out_label(s, arg_label(op->args[0]));
4732c896fe29Sbellard             break;
4733c896fe29Sbellard         case INDEX_op_call:
4734dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
4735c45cb8bbSRichard Henderson             break;
4736b55a8d9dSRichard Henderson         case INDEX_op_exit_tb:
4737b55a8d9dSRichard Henderson             tcg_out_exit_tb(s, op->args[0]);
4738b55a8d9dSRichard Henderson             break;
4739cf7d6b8eSRichard Henderson         case INDEX_op_goto_tb:
4740cf7d6b8eSRichard Henderson             tcg_out_goto_tb(s, op->args[0]);
4741cf7d6b8eSRichard Henderson             break;
4742efe86b21SRichard Henderson         case INDEX_op_dup2_vec:
4743efe86b21SRichard Henderson             if (tcg_reg_alloc_dup2(s, op)) {
4744efe86b21SRichard Henderson                 break;
4745efe86b21SRichard Henderson             }
4746efe86b21SRichard Henderson             /* fall through */
4747c896fe29Sbellard         default:
474825c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
4749be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
4750c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
4751c896fe29Sbellard                faster to have specialized register allocator functions for
4752c896fe29Sbellard                some common argument patterns */
4753dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
4754c896fe29Sbellard             break;
4755c896fe29Sbellard         }
4756b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
4757b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
4758b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
4759b125f9dcSRichard Henderson            generating code without having to check during generation.  */
4760644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
4761b125f9dcSRichard Henderson             return -1;
4762b125f9dcSRichard Henderson         }
47636e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
47646e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
47656e6c4efeSRichard Henderson             return -2;
47666e6c4efeSRichard Henderson         }
4767c896fe29Sbellard     }
4768fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
4769fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
4770c45cb8bbSRichard Henderson 
4771b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
4772659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
4773aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
4774aeee05f5SRichard Henderson     if (i < 0) {
4775aeee05f5SRichard Henderson         return i;
477623dceda6SRichard Henderson     }
4777659ef5cbSRichard Henderson #endif
477857a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
47791768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
47801768987bSRichard Henderson     if (i < 0) {
47811768987bSRichard Henderson         return i;
478257a26946SRichard Henderson     }
478357a26946SRichard Henderson #endif
47847ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
47857ecd02a0SRichard Henderson         return -2;
47867ecd02a0SRichard Henderson     }
4787c896fe29Sbellard 
4788df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
4789c896fe29Sbellard     /* flush instruction cache */
4790db0c51a3SRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
4791db0c51a3SRichard Henderson                         (uintptr_t)s->code_buf,
47921da8de39SRichard Henderson                         tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
4793df5d2b16SRichard Henderson #endif
47942aeabc08SStefan Weil 
47951813e175SRichard Henderson     return tcg_current_code_size(s);
4796c896fe29Sbellard }
4797c896fe29Sbellard 
4798a23a9ec6Sbellard #ifdef CONFIG_PROFILER
47993a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf)
4800a23a9ec6Sbellard {
4801c3fac113SEmilio G. Cota     TCGProfile prof = {};
4802c3fac113SEmilio G. Cota     const TCGProfile *s;
4803c3fac113SEmilio G. Cota     int64_t tb_count;
4804c3fac113SEmilio G. Cota     int64_t tb_div_count;
4805c3fac113SEmilio G. Cota     int64_t tot;
4806c3fac113SEmilio G. Cota 
4807c3fac113SEmilio G. Cota     tcg_profile_snapshot_counters(&prof);
4808c3fac113SEmilio G. Cota     s = &prof;
4809c3fac113SEmilio G. Cota     tb_count = s->tb_count;
4810c3fac113SEmilio G. Cota     tb_div_count = tb_count ? tb_count : 1;
4811c3fac113SEmilio G. Cota     tot = s->interm_time + s->code_time;
4812a23a9ec6Sbellard 
48133a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "JIT cycles          %" PRId64
48143a841ab5SDaniel P. Berrangé                            " (%0.3f s at 2.4 GHz)\n",
4815a23a9ec6Sbellard                            tot, tot / 2.4e9);
48163a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "translated TBs      %" PRId64
48173a841ab5SDaniel P. Berrangé                            " (aborted=%" PRId64 " %0.1f%%)\n",
4818fca8a500SRichard Henderson                            tb_count, s->tb_count1 - tb_count,
4819fca8a500SRichard Henderson                            (double)(s->tb_count1 - s->tb_count)
4820fca8a500SRichard Henderson                            / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
48213a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg ops/TB          %0.1f max=%d\n",
4822fca8a500SRichard Henderson                            (double)s->op_count / tb_div_count, s->op_count_max);
48233a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "deleted ops/TB      %0.2f\n",
4824fca8a500SRichard Henderson                            (double)s->del_op_count / tb_div_count);
48253a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg temps/TB        %0.2f max=%d\n",
48263a841ab5SDaniel P. Berrangé                            (double)s->temp_count / tb_div_count,
48273a841ab5SDaniel P. Berrangé                            s->temp_count_max);
48283a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg host code/TB    %0.1f\n",
4829fca8a500SRichard Henderson                            (double)s->code_out_len / tb_div_count);
48303a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg search data/TB  %0.1f\n",
4831fca8a500SRichard Henderson                            (double)s->search_out_len / tb_div_count);
4832a23a9ec6Sbellard 
48333a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/op           %0.1f\n",
4834a23a9ec6Sbellard                            s->op_count ? (double)tot / s->op_count : 0);
48353a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/in byte      %0.1f\n",
4836a23a9ec6Sbellard                            s->code_in_len ? (double)tot / s->code_in_len : 0);
48373a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/out byte     %0.1f\n",
4838a23a9ec6Sbellard                            s->code_out_len ? (double)tot / s->code_out_len : 0);
48393a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/search byte     %0.1f\n",
48403a841ab5SDaniel P. Berrangé                            s->search_out_len ?
48413a841ab5SDaniel P. Berrangé                            (double)tot / s->search_out_len : 0);
4842fca8a500SRichard Henderson     if (tot == 0) {
4843a23a9ec6Sbellard         tot = 1;
4844fca8a500SRichard Henderson     }
48453a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "  gen_interm time   %0.1f%%\n",
4846a23a9ec6Sbellard                            (double)s->interm_time / tot * 100.0);
48473a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "  gen_code time     %0.1f%%\n",
4848a23a9ec6Sbellard                            (double)s->code_time / tot * 100.0);
48493a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "optim./code time    %0.1f%%\n",
48503a841ab5SDaniel P. Berrangé                            (double)s->opt_time / (s->code_time ?
48513a841ab5SDaniel P. Berrangé                                                   s->code_time : 1)
4852c5cc28ffSAurelien Jarno                            * 100.0);
48533a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "liveness/code time  %0.1f%%\n",
48543a841ab5SDaniel P. Berrangé                            (double)s->la_time / (s->code_time ?
48553a841ab5SDaniel P. Berrangé                                                  s->code_time : 1) * 100.0);
48563a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cpu_restore count   %" PRId64 "\n",
4857a23a9ec6Sbellard                            s->restore_count);
48583a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "  avg cycles        %0.1f\n",
48593a841ab5SDaniel P. Berrangé                            s->restore_count ?
48603a841ab5SDaniel P. Berrangé                            (double)s->restore_time / s->restore_count : 0);
4861a23a9ec6Sbellard }
4862a23a9ec6Sbellard #else
48633a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf)
4864a23a9ec6Sbellard {
48653a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "[TCG profiler not compiled]\n");
4866a23a9ec6Sbellard }
4867a23a9ec6Sbellard #endif
4868813da627SRichard Henderson 
4869813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
48705872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
48715872bbf2SRichard Henderson 
48725872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
48735872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
48745872bbf2SRichard Henderson 
48755872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
48765872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
48775872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
48785872bbf2SRichard Henderson 
48795872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
48805872bbf2SRichard Henderson */
4881813da627SRichard Henderson 
4882813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
4883813da627SRichard Henderson typedef enum {
4884813da627SRichard Henderson     JIT_NOACTION = 0,
4885813da627SRichard Henderson     JIT_REGISTER_FN,
4886813da627SRichard Henderson     JIT_UNREGISTER_FN
4887813da627SRichard Henderson } jit_actions_t;
4888813da627SRichard Henderson 
4889813da627SRichard Henderson struct jit_code_entry {
4890813da627SRichard Henderson     struct jit_code_entry *next_entry;
4891813da627SRichard Henderson     struct jit_code_entry *prev_entry;
4892813da627SRichard Henderson     const void *symfile_addr;
4893813da627SRichard Henderson     uint64_t symfile_size;
4894813da627SRichard Henderson };
4895813da627SRichard Henderson 
4896813da627SRichard Henderson struct jit_descriptor {
4897813da627SRichard Henderson     uint32_t version;
4898813da627SRichard Henderson     uint32_t action_flag;
4899813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
4900813da627SRichard Henderson     struct jit_code_entry *first_entry;
4901813da627SRichard Henderson };
4902813da627SRichard Henderson 
4903813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
4904813da627SRichard Henderson void __jit_debug_register_code(void)
4905813da627SRichard Henderson {
4906813da627SRichard Henderson     asm("");
4907813da627SRichard Henderson }
4908813da627SRichard Henderson 
4909813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
4910813da627SRichard Henderson    the version before we can set it.  */
4911813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
4912813da627SRichard Henderson 
4913813da627SRichard Henderson /* End GDB interface.  */
4914813da627SRichard Henderson 
4915813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
4916813da627SRichard Henderson {
4917813da627SRichard Henderson     const char *p = strtab + 1;
4918813da627SRichard Henderson 
4919813da627SRichard Henderson     while (1) {
4920813da627SRichard Henderson         if (strcmp(p, str) == 0) {
4921813da627SRichard Henderson             return p - strtab;
4922813da627SRichard Henderson         }
4923813da627SRichard Henderson         p += strlen(p) + 1;
4924813da627SRichard Henderson     }
4925813da627SRichard Henderson }
4926813da627SRichard Henderson 
4927755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size,
49282c90784aSRichard Henderson                                  const void *debug_frame,
49292c90784aSRichard Henderson                                  size_t debug_frame_size)
4930813da627SRichard Henderson {
49315872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
49325872bbf2SRichard Henderson         uint32_t  len;
49335872bbf2SRichard Henderson         uint16_t  version;
49345872bbf2SRichard Henderson         uint32_t  abbrev;
49355872bbf2SRichard Henderson         uint8_t   ptr_size;
49365872bbf2SRichard Henderson         uint8_t   cu_die;
49375872bbf2SRichard Henderson         uint16_t  cu_lang;
49385872bbf2SRichard Henderson         uintptr_t cu_low_pc;
49395872bbf2SRichard Henderson         uintptr_t cu_high_pc;
49405872bbf2SRichard Henderson         uint8_t   fn_die;
49415872bbf2SRichard Henderson         char      fn_name[16];
49425872bbf2SRichard Henderson         uintptr_t fn_low_pc;
49435872bbf2SRichard Henderson         uintptr_t fn_high_pc;
49445872bbf2SRichard Henderson         uint8_t   cu_eoc;
49455872bbf2SRichard Henderson     };
4946813da627SRichard Henderson 
4947813da627SRichard Henderson     struct ElfImage {
4948813da627SRichard Henderson         ElfW(Ehdr) ehdr;
4949813da627SRichard Henderson         ElfW(Phdr) phdr;
49505872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
49515872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
49525872bbf2SRichard Henderson         struct DebugInfo di;
49535872bbf2SRichard Henderson         uint8_t    da[24];
49545872bbf2SRichard Henderson         char       str[80];
49555872bbf2SRichard Henderson     };
49565872bbf2SRichard Henderson 
49575872bbf2SRichard Henderson     struct ElfImage *img;
49585872bbf2SRichard Henderson 
49595872bbf2SRichard Henderson     static const struct ElfImage img_template = {
49605872bbf2SRichard Henderson         .ehdr = {
49615872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
49625872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
49635872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
49645872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
49655872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
49665872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
49675872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
49685872bbf2SRichard Henderson             .e_type = ET_EXEC,
49695872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
49705872bbf2SRichard Henderson             .e_version = EV_CURRENT,
49715872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
49725872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
49735872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
49745872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
49755872bbf2SRichard Henderson             .e_phnum = 1,
49765872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
49775872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
49785872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
4979abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
4980abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
4981abbb3eaeSRichard Henderson #endif
4982abbb3eaeSRichard Henderson #ifdef ELF_OSABI
4983abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
4984abbb3eaeSRichard Henderson #endif
49855872bbf2SRichard Henderson         },
49865872bbf2SRichard Henderson         .phdr = {
49875872bbf2SRichard Henderson             .p_type = PT_LOAD,
49885872bbf2SRichard Henderson             .p_flags = PF_X,
49895872bbf2SRichard Henderson         },
49905872bbf2SRichard Henderson         .shdr = {
49915872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
49925872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
49935872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
49945872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
49955872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
49965872bbf2SRichard Henderson             [1] = { /* .text */
49975872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
49985872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
49995872bbf2SRichard Henderson             },
50005872bbf2SRichard Henderson             [2] = { /* .debug_info */
50015872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
50025872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
50035872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
50045872bbf2SRichard Henderson             },
50055872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
50065872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
50075872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
50085872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
50095872bbf2SRichard Henderson             },
50105872bbf2SRichard Henderson             [4] = { /* .debug_frame */
50115872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
50125872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
50135872bbf2SRichard Henderson             },
50145872bbf2SRichard Henderson             [5] = { /* .symtab */
50155872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
50165872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
50175872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
50185872bbf2SRichard Henderson                 .sh_info = 1,
50195872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
50205872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
50215872bbf2SRichard Henderson             },
50225872bbf2SRichard Henderson             [6] = { /* .strtab */
50235872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
50245872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
50255872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
50265872bbf2SRichard Henderson             }
50275872bbf2SRichard Henderson         },
50285872bbf2SRichard Henderson         .sym = {
50295872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
50305872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
50315872bbf2SRichard Henderson                 .st_shndx = 1,
50325872bbf2SRichard Henderson             }
50335872bbf2SRichard Henderson         },
50345872bbf2SRichard Henderson         .di = {
50355872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
50365872bbf2SRichard Henderson             .version = 2,
50375872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
50385872bbf2SRichard Henderson             .cu_die = 1,
50395872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
50405872bbf2SRichard Henderson             .fn_die = 2,
50415872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
50425872bbf2SRichard Henderson         },
50435872bbf2SRichard Henderson         .da = {
50445872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
50455872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
50465872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
50475872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
50485872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
50495872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
50505872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
50515872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
50525872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
50535872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
50545872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
50555872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
50565872bbf2SRichard Henderson             0           /* no more abbrev */
50575872bbf2SRichard Henderson         },
50585872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
50595872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
5060813da627SRichard Henderson     };
5061813da627SRichard Henderson 
5062813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
5063813da627SRichard Henderson     static struct jit_code_entry one_entry;
5064813da627SRichard Henderson 
50655872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
5066813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
50672c90784aSRichard Henderson     DebugFrameHeader *dfh;
5068813da627SRichard Henderson 
50695872bbf2SRichard Henderson     img = g_malloc(img_size);
50705872bbf2SRichard Henderson     *img = img_template;
5071813da627SRichard Henderson 
50725872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
50735872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
50745872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
5075813da627SRichard Henderson 
50765872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
50775872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
50785872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
5079813da627SRichard Henderson 
50805872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
50815872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
50825872bbf2SRichard Henderson 
50835872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
50845872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
50855872bbf2SRichard Henderson 
50865872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
50875872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
50885872bbf2SRichard Henderson 
50895872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
50905872bbf2SRichard Henderson     img->sym[1].st_value = buf;
50915872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
50925872bbf2SRichard Henderson 
50935872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
509445aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
50955872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
509645aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
5097813da627SRichard Henderson 
50982c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
50992c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
51002c90784aSRichard Henderson     dfh->fde.func_start = buf;
51012c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
51022c90784aSRichard Henderson 
5103813da627SRichard Henderson #ifdef DEBUG_JIT
5104813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
5105813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
5106813da627SRichard Henderson     {
5107eb6b2edfSBin Meng         g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir());
5108eb6b2edfSBin Meng         FILE *f = fopen(jit, "w+b");
5109813da627SRichard Henderson         if (f) {
51105872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
5111813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
5112813da627SRichard Henderson             }
5113813da627SRichard Henderson             fclose(f);
5114813da627SRichard Henderson         }
5115813da627SRichard Henderson     }
5116813da627SRichard Henderson #endif
5117813da627SRichard Henderson 
5118813da627SRichard Henderson     one_entry.symfile_addr = img;
5119813da627SRichard Henderson     one_entry.symfile_size = img_size;
5120813da627SRichard Henderson 
5121813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
5122813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
5123813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
5124813da627SRichard Henderson     __jit_debug_register_code();
5125813da627SRichard Henderson }
5126813da627SRichard Henderson #else
51275872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
51285872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
5129813da627SRichard Henderson 
5130755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
51312c90784aSRichard Henderson                                  const void *debug_frame,
51322c90784aSRichard Henderson                                  size_t debug_frame_size)
5133813da627SRichard Henderson {
5134813da627SRichard Henderson }
5135813da627SRichard Henderson 
5136755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size)
5137813da627SRichard Henderson {
5138813da627SRichard Henderson }
5139813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
5140db432672SRichard Henderson 
5141db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
5142db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
5143db432672SRichard Henderson {
5144db432672SRichard Henderson     g_assert_not_reached();
5145db432672SRichard Henderson }
5146db432672SRichard Henderson #endif
5147