xref: /qemu/tcg/tcg.c (revision 379afdff47556f01e75ce2caffd7ae9efa4f1214)
1c896fe29Sbellard /*
2c896fe29Sbellard  * Tiny Code Generator for QEMU
3c896fe29Sbellard  *
4c896fe29Sbellard  * Copyright (c) 2008 Fabrice Bellard
5c896fe29Sbellard  *
6c896fe29Sbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
7c896fe29Sbellard  * of this software and associated documentation files (the "Software"), to deal
8c896fe29Sbellard  * in the Software without restriction, including without limitation the rights
9c896fe29Sbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10c896fe29Sbellard  * copies of the Software, and to permit persons to whom the Software is
11c896fe29Sbellard  * furnished to do so, subject to the following conditions:
12c896fe29Sbellard  *
13c896fe29Sbellard  * The above copyright notice and this permission notice shall be included in
14c896fe29Sbellard  * all copies or substantial portions of the Software.
15c896fe29Sbellard  *
16c896fe29Sbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17c896fe29Sbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18c896fe29Sbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19c896fe29Sbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20c896fe29Sbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21c896fe29Sbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22c896fe29Sbellard  * THE SOFTWARE.
23c896fe29Sbellard  */
24c896fe29Sbellard 
25c896fe29Sbellard /* define it to use liveness analysis (better code) */
268f2e8c07SKirill Batuzov #define USE_TCG_OPTIMIZATIONS
27c896fe29Sbellard 
28757e725bSPeter Maydell #include "qemu/osdep.h"
29cca82982Saurel32 
30813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB.  */
31813da627SRichard Henderson #undef DEBUG_JIT
32813da627SRichard Henderson 
3372fd2efbSEmilio G. Cota #include "qemu/error-report.h"
34f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
351de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
36d4c51a0aSMarkus Armbruster #include "qemu/qemu-print.h"
37084cfca1SRichard Henderson #include "qemu/cacheflush.h"
38ad768e6fSPeter Maydell #include "qemu/cacheinfo.h"
39533206f0SRichard W.M. Jones #include "qemu/timer.h"
40c896fe29Sbellard 
41c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU
42c896fe29Sbellard    CPU definitions. Currently they are used for qemu_ld/st
43c896fe29Sbellard    instructions */
44c896fe29Sbellard #define NO_CPU_IO_DEFS
45c896fe29Sbellard 
4663c91552SPaolo Bonzini #include "exec/exec-all.h"
47dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
48813da627SRichard Henderson 
49edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX
50813da627SRichard Henderson # define ELF_CLASS  ELFCLASS32
51edee2579SRichard Henderson #else
52edee2579SRichard Henderson # define ELF_CLASS  ELFCLASS64
53813da627SRichard Henderson #endif
54e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
55813da627SRichard Henderson # define ELF_DATA   ELFDATA2MSB
56813da627SRichard Henderson #else
57813da627SRichard Henderson # define ELF_DATA   ELFDATA2LSB
58813da627SRichard Henderson #endif
59813da627SRichard Henderson 
60c896fe29Sbellard #include "elf.h"
61508127e2SPaolo Bonzini #include "exec/log.h"
62d2ba8026SRichard Henderson #include "tcg/tcg-ldst.h"
6347f7313dSRichard Henderson #include "tcg/tcg-temp-internal.h"
645ff7258cSRichard Henderson #include "tcg-internal.h"
655584e2dbSIlya Leoshkevich #include "accel/tcg/perf.h"
66c896fe29Sbellard 
67139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and
68ce151109SPeter Maydell    used here. */
69e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s);
70e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
716ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
722ba7fae2SRichard Henderson                         intptr_t value, intptr_t addend);
73c896fe29Sbellard 
74497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts.  */
75497a22ebSRichard Henderson typedef struct {
76497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
77497a22ebSRichard Henderson     uint32_t id;
78497a22ebSRichard Henderson     uint8_t version;
79497a22ebSRichard Henderson     char augmentation[1];
80497a22ebSRichard Henderson     uint8_t code_align;
81497a22ebSRichard Henderson     uint8_t data_align;
82497a22ebSRichard Henderson     uint8_t return_column;
83497a22ebSRichard Henderson } DebugFrameCIE;
84497a22ebSRichard Henderson 
85497a22ebSRichard Henderson typedef struct QEMU_PACKED {
86497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
87497a22ebSRichard Henderson     uint32_t cie_offset;
88edee2579SRichard Henderson     uintptr_t func_start;
89edee2579SRichard Henderson     uintptr_t func_len;
90497a22ebSRichard Henderson } DebugFrameFDEHeader;
91497a22ebSRichard Henderson 
922c90784aSRichard Henderson typedef struct QEMU_PACKED {
932c90784aSRichard Henderson     DebugFrameCIE cie;
942c90784aSRichard Henderson     DebugFrameFDEHeader fde;
952c90784aSRichard Henderson } DebugFrameHeader;
962c90784aSRichard Henderson 
97755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
982c90784aSRichard Henderson                                  const void *debug_frame,
992c90784aSRichard Henderson                                  size_t debug_frame_size)
100813da627SRichard Henderson     __attribute__((unused));
101813da627SRichard Henderson 
102139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */
1032a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
104a05b5b9bSRichard Henderson                        intptr_t arg2);
10578113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
106c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1072a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
108678155b2SRichard Henderson static void tcg_out_ext8s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
109753e42eaSRichard Henderson static void tcg_out_ext16s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
110d0e66c89SRichard Henderson static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg);
111*379afdffSRichard Henderson static void tcg_out_ext16u(TCGContext *s, TCGReg ret, TCGReg arg);
112313bdea8SRichard Henderson static void tcg_out_addi_ptr(TCGContext *s, TCGReg, TCGReg, tcg_target_long);
113b55a8d9dSRichard Henderson static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg);
114cf7d6b8eSRichard Henderson static void tcg_out_goto_tb(TCGContext *s, int which);
1155e8892dbSMiroslav Rezanina static void tcg_out_op(TCGContext *s, TCGOpcode opc,
1165e8892dbSMiroslav Rezanina                        const TCGArg args[TCG_MAX_OP_ARGS],
1175e8892dbSMiroslav Rezanina                        const int const_args[TCG_MAX_OP_ARGS]);
118d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec
119e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
120e7632cfaSRichard Henderson                             TCGReg dst, TCGReg src);
121d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
122d6ecb4a9SRichard Henderson                              TCGReg dst, TCGReg base, intptr_t offset);
1234e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1244e186175SRichard Henderson                              TCGReg dst, int64_t arg);
1255e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1265e8892dbSMiroslav Rezanina                            unsigned vecl, unsigned vece,
1275e8892dbSMiroslav Rezanina                            const TCGArg args[TCG_MAX_OP_ARGS],
1285e8892dbSMiroslav Rezanina                            const int const_args[TCG_MAX_OP_ARGS]);
129d2fd745fSRichard Henderson #else
130e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
131e7632cfaSRichard Henderson                                    TCGReg dst, TCGReg src)
132e7632cfaSRichard Henderson {
133e7632cfaSRichard Henderson     g_assert_not_reached();
134e7632cfaSRichard Henderson }
135d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
136d6ecb4a9SRichard Henderson                                     TCGReg dst, TCGReg base, intptr_t offset)
137d6ecb4a9SRichard Henderson {
138d6ecb4a9SRichard Henderson     g_assert_not_reached();
139d6ecb4a9SRichard Henderson }
1404e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1414e186175SRichard Henderson                                     TCGReg dst, int64_t arg)
142e7632cfaSRichard Henderson {
143e7632cfaSRichard Henderson     g_assert_not_reached();
144e7632cfaSRichard Henderson }
1455e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1465e8892dbSMiroslav Rezanina                                   unsigned vecl, unsigned vece,
1475e8892dbSMiroslav Rezanina                                   const TCGArg args[TCG_MAX_OP_ARGS],
1485e8892dbSMiroslav Rezanina                                   const int const_args[TCG_MAX_OP_ARGS])
149d2fd745fSRichard Henderson {
150d2fd745fSRichard Henderson     g_assert_not_reached();
151d2fd745fSRichard Henderson }
152d2fd745fSRichard Henderson #endif
1532a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
154a05b5b9bSRichard Henderson                        intptr_t arg2);
15559d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
15659d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
1577b7d8b2dSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target,
158cee44b03SRichard Henderson                          const TCGHelperInfo *info);
1595e3d0c19SRichard Henderson static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot);
160a4fbbd77SRichard Henderson static bool tcg_target_const_match(int64_t val, TCGType type, int ct);
161659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
162aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s);
163659ef5cbSRichard Henderson #endif
164c896fe29Sbellard 
16542eb6dfcSRichard Henderson TCGContext tcg_init_ctx;
16642eb6dfcSRichard Henderson __thread TCGContext *tcg_ctx;
16742eb6dfcSRichard Henderson 
1685ff7258cSRichard Henderson TCGContext **tcg_ctxs;
1690e2d61cfSRichard Henderson unsigned int tcg_cur_ctxs;
1700e2d61cfSRichard Henderson unsigned int tcg_max_ctxs;
1711c2adb95SRichard Henderson TCGv_env cpu_env = 0;
172c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue;
173db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff;
174df2cce29SEmilio G. Cota 
175b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
176b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec;
177b91ccb31SRichard Henderson #endif
178b91ccb31SRichard Henderson 
179d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
180b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
181c896fe29Sbellard 
1821813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
1834196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
184c896fe29Sbellard {
185c896fe29Sbellard     *s->code_ptr++ = v;
186c896fe29Sbellard }
187c896fe29Sbellard 
1884196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
1894196dca6SPeter Maydell                                                       uint8_t v)
1905c53bb81SPeter Maydell {
1911813e175SRichard Henderson     *p = v;
1925c53bb81SPeter Maydell }
1931813e175SRichard Henderson #endif
1945c53bb81SPeter Maydell 
1951813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
1964196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
197c896fe29Sbellard {
1981813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
1991813e175SRichard Henderson         *s->code_ptr++ = v;
2001813e175SRichard Henderson     } else {
2011813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2024387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2031813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
2041813e175SRichard Henderson     }
205c896fe29Sbellard }
206c896fe29Sbellard 
2074196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2084196dca6SPeter Maydell                                                        uint16_t v)
2095c53bb81SPeter Maydell {
2101813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2111813e175SRichard Henderson         *p = v;
2121813e175SRichard Henderson     } else {
2135c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2145c53bb81SPeter Maydell     }
2151813e175SRichard Henderson }
2161813e175SRichard Henderson #endif
2175c53bb81SPeter Maydell 
2181813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
2194196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
220c896fe29Sbellard {
2211813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2221813e175SRichard Henderson         *s->code_ptr++ = v;
2231813e175SRichard Henderson     } else {
2241813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2254387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2261813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
2271813e175SRichard Henderson     }
228c896fe29Sbellard }
229c896fe29Sbellard 
2304196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
2314196dca6SPeter Maydell                                                        uint32_t v)
2325c53bb81SPeter Maydell {
2331813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2341813e175SRichard Henderson         *p = v;
2351813e175SRichard Henderson     } else {
2365c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2375c53bb81SPeter Maydell     }
2381813e175SRichard Henderson }
2391813e175SRichard Henderson #endif
2405c53bb81SPeter Maydell 
2411813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
2424196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
243ac26eb69SRichard Henderson {
2441813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2451813e175SRichard Henderson         *s->code_ptr++ = v;
2461813e175SRichard Henderson     } else {
2471813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2484387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2491813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
2501813e175SRichard Henderson     }
251ac26eb69SRichard Henderson }
252ac26eb69SRichard Henderson 
2534196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
2544196dca6SPeter Maydell                                                        uint64_t v)
2555c53bb81SPeter Maydell {
2561813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2571813e175SRichard Henderson         *p = v;
2581813e175SRichard Henderson     } else {
2595c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2605c53bb81SPeter Maydell     }
2611813e175SRichard Henderson }
2621813e175SRichard Henderson #endif
2635c53bb81SPeter Maydell 
264c896fe29Sbellard /* label relocation processing */
265c896fe29Sbellard 
2661813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
267bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
268c896fe29Sbellard {
2697ecd02a0SRichard Henderson     TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation));
270c896fe29Sbellard 
271c896fe29Sbellard     r->type = type;
272c896fe29Sbellard     r->ptr = code_ptr;
273c896fe29Sbellard     r->addend = addend;
2747ecd02a0SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
275c896fe29Sbellard }
276c896fe29Sbellard 
27792ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l)
278c896fe29Sbellard {
279eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
280c896fe29Sbellard     l->has_value = 1;
28192ab8e7dSRichard Henderson     l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr);
282c896fe29Sbellard }
283c896fe29Sbellard 
28442a268c2SRichard Henderson TCGLabel *gen_new_label(void)
285c896fe29Sbellard {
286b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
28751e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
288c896fe29Sbellard 
2897ecd02a0SRichard Henderson     memset(l, 0, sizeof(TCGLabel));
2907ecd02a0SRichard Henderson     l->id = s->nb_labels++;
291f85b1fc4SRichard Henderson     QSIMPLEQ_INIT(&l->branches);
2927ecd02a0SRichard Henderson     QSIMPLEQ_INIT(&l->relocs);
2937ecd02a0SRichard Henderson 
294bef16ab4SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
29542a268c2SRichard Henderson 
29642a268c2SRichard Henderson     return l;
297c896fe29Sbellard }
298c896fe29Sbellard 
2997ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s)
3007ecd02a0SRichard Henderson {
3017ecd02a0SRichard Henderson     TCGLabel *l;
3027ecd02a0SRichard Henderson 
3037ecd02a0SRichard Henderson     QSIMPLEQ_FOREACH(l, &s->labels, next) {
3047ecd02a0SRichard Henderson         TCGRelocation *r;
3057ecd02a0SRichard Henderson         uintptr_t value = l->u.value;
3067ecd02a0SRichard Henderson 
3077ecd02a0SRichard Henderson         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
3087ecd02a0SRichard Henderson             if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
3097ecd02a0SRichard Henderson                 return false;
3107ecd02a0SRichard Henderson             }
3117ecd02a0SRichard Henderson         }
3127ecd02a0SRichard Henderson     }
3137ecd02a0SRichard Henderson     return true;
3147ecd02a0SRichard Henderson }
3157ecd02a0SRichard Henderson 
3169f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3179f754620SRichard Henderson {
318f14bed3fSRichard Henderson     /*
319f14bed3fSRichard Henderson      * We will check for overflow at the end of the opcode loop in
320f14bed3fSRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
321f14bed3fSRichard Henderson      */
322b7e4afbdSRichard Henderson     s->gen_tb->jmp_reset_offset[which] = tcg_current_code_size(s);
3239f754620SRichard Henderson }
3249f754620SRichard Henderson 
325b52a2c03SRichard Henderson static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which)
326b52a2c03SRichard Henderson {
327b52a2c03SRichard Henderson     /*
328b52a2c03SRichard Henderson      * We will check for overflow at the end of the opcode loop in
329b52a2c03SRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
330b52a2c03SRichard Henderson      */
3319da6079bSRichard Henderson     s->gen_tb->jmp_insn_offset[which] = tcg_current_code_size(s);
332b52a2c03SRichard Henderson }
333b52a2c03SRichard Henderson 
334becc452aSRichard Henderson static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which)
335becc452aSRichard Henderson {
336becc452aSRichard Henderson     /*
337becc452aSRichard Henderson      * Return the read-execute version of the pointer, for the benefit
338becc452aSRichard Henderson      * of any pc-relative addressing mode.
339becc452aSRichard Henderson      */
3409da6079bSRichard Henderson     return (uintptr_t)tcg_splitwx_to_rx(&s->gen_tb->jmp_target_addr[which]);
341becc452aSRichard Henderson }
342becc452aSRichard Henderson 
343db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */
3448905770bSMarc-André Lureau static G_NORETURN
3458905770bSMarc-André Lureau void tcg_raise_tb_overflow(TCGContext *s)
346db6b7d0cSRichard Henderson {
347db6b7d0cSRichard Henderson     siglongjmp(s->jmp_trans, -2);
348db6b7d0cSRichard Henderson }
349db6b7d0cSRichard Henderson 
3504c22e840SRichard Henderson #define C_PFX1(P, A)                    P##A
3514c22e840SRichard Henderson #define C_PFX2(P, A, B)                 P##A##_##B
3524c22e840SRichard Henderson #define C_PFX3(P, A, B, C)              P##A##_##B##_##C
3534c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D)           P##A##_##B##_##C##_##D
3544c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E)        P##A##_##B##_##C##_##D##_##E
3554c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F)     P##A##_##B##_##C##_##D##_##E##_##F
3564c22e840SRichard Henderson 
3574c22e840SRichard Henderson /* Define an enumeration for the various combinations. */
3584c22e840SRichard Henderson 
3594c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1),
3604c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2),
3614c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3),
3624c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4),
3634c22e840SRichard Henderson 
3644c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1),
3654c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2),
3664c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3),
3674c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4),
3684c22e840SRichard Henderson 
3694c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2),
3704c22e840SRichard Henderson 
3714c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1),
3724c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2),
3734c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3),
3744c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4),
3754c22e840SRichard Henderson 
3764c22e840SRichard Henderson typedef enum {
3774c22e840SRichard Henderson #include "tcg-target-con-set.h"
3784c22e840SRichard Henderson } TCGConstraintSetIndex;
3794c22e840SRichard Henderson 
3804c22e840SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode);
3814c22e840SRichard Henderson 
3824c22e840SRichard Henderson #undef C_O0_I1
3834c22e840SRichard Henderson #undef C_O0_I2
3844c22e840SRichard Henderson #undef C_O0_I3
3854c22e840SRichard Henderson #undef C_O0_I4
3864c22e840SRichard Henderson #undef C_O1_I1
3874c22e840SRichard Henderson #undef C_O1_I2
3884c22e840SRichard Henderson #undef C_O1_I3
3894c22e840SRichard Henderson #undef C_O1_I4
3904c22e840SRichard Henderson #undef C_N1_I2
3914c22e840SRichard Henderson #undef C_O2_I1
3924c22e840SRichard Henderson #undef C_O2_I2
3934c22e840SRichard Henderson #undef C_O2_I3
3944c22e840SRichard Henderson #undef C_O2_I4
3954c22e840SRichard Henderson 
3964c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */
3974c22e840SRichard Henderson 
3984c22e840SRichard Henderson #define C_O0_I1(I1)                     { .args_ct_str = { #I1 } },
3994c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 { .args_ct_str = { #I1, #I2 } },
4004c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             { .args_ct_str = { #I1, #I2, #I3 } },
4014c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         { .args_ct_str = { #I1, #I2, #I3, #I4 } },
4024c22e840SRichard Henderson 
4034c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 { .args_ct_str = { #O1, #I1 } },
4044c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             { .args_ct_str = { #O1, #I1, #I2 } },
4054c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         { .args_ct_str = { #O1, #I1, #I2, #I3 } },
4064c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } },
4074c22e840SRichard Henderson 
4084c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             { .args_ct_str = { "&" #O1, #I1, #I2 } },
4094c22e840SRichard Henderson 
4104c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             { .args_ct_str = { #O1, #O2, #I1 } },
4114c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         { .args_ct_str = { #O1, #O2, #I1, #I2 } },
4124c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } },
4134c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } },
4144c22e840SRichard Henderson 
4154c22e840SRichard Henderson static const TCGTargetOpDef constraint_sets[] = {
4164c22e840SRichard Henderson #include "tcg-target-con-set.h"
4174c22e840SRichard Henderson };
4184c22e840SRichard Henderson 
4194c22e840SRichard Henderson 
4204c22e840SRichard Henderson #undef C_O0_I1
4214c22e840SRichard Henderson #undef C_O0_I2
4224c22e840SRichard Henderson #undef C_O0_I3
4234c22e840SRichard Henderson #undef C_O0_I4
4244c22e840SRichard Henderson #undef C_O1_I1
4254c22e840SRichard Henderson #undef C_O1_I2
4264c22e840SRichard Henderson #undef C_O1_I3
4274c22e840SRichard Henderson #undef C_O1_I4
4284c22e840SRichard Henderson #undef C_N1_I2
4294c22e840SRichard Henderson #undef C_O2_I1
4304c22e840SRichard Henderson #undef C_O2_I2
4314c22e840SRichard Henderson #undef C_O2_I3
4324c22e840SRichard Henderson #undef C_O2_I4
4334c22e840SRichard Henderson 
4344c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */
4354c22e840SRichard Henderson 
4364c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1)
4374c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2)
4384c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3)
4394c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4)
4404c22e840SRichard Henderson 
4414c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1)
4424c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2)
4434c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3)
4444c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4)
4454c22e840SRichard Henderson 
4464c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2)
4474c22e840SRichard Henderson 
4484c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1)
4494c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2)
4504c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3)
4514c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4)
4524c22e840SRichard Henderson 
453139c1837SPaolo Bonzini #include "tcg-target.c.inc"
454c896fe29Sbellard 
45538b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s)
45638b47b19SEmilio G. Cota {
45738b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
45838b47b19SEmilio G. Cota     s->plugin_tb = g_new0(struct qemu_plugin_tb, 1);
45938b47b19SEmilio G. Cota     s->plugin_tb->insns =
46038b47b19SEmilio G. Cota         g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn);
46138b47b19SEmilio G. Cota #endif
46238b47b19SEmilio G. Cota }
46338b47b19SEmilio G. Cota 
464e8feb96fSEmilio G. Cota /*
4653468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
4663468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
4673468b59eSEmilio G. Cota  * before initiating translation.
4683468b59eSEmilio G. Cota  *
4693468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
4703468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
4713468b59eSEmilio G. Cota  *
4723468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
4733468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
4743468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
4753468b59eSEmilio G. Cota  *
4763468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
4773468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
4783468b59eSEmilio G. Cota  */
4793468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
4803468b59eSEmilio G. Cota void tcg_register_thread(void)
4813468b59eSEmilio G. Cota {
4823468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
4833468b59eSEmilio G. Cota }
4843468b59eSEmilio G. Cota #else
4853468b59eSEmilio G. Cota void tcg_register_thread(void)
4863468b59eSEmilio G. Cota {
4873468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
4883468b59eSEmilio G. Cota     unsigned int i, n;
4893468b59eSEmilio G. Cota 
4903468b59eSEmilio G. Cota     *s = tcg_init_ctx;
4913468b59eSEmilio G. Cota 
4923468b59eSEmilio G. Cota     /* Relink mem_base.  */
4933468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
4943468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
4953468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
4963468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
4973468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
4983468b59eSEmilio G. Cota         }
4993468b59eSEmilio G. Cota     }
5003468b59eSEmilio G. Cota 
5013468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
5020e2d61cfSRichard Henderson     n = qatomic_fetch_inc(&tcg_cur_ctxs);
5030e2d61cfSRichard Henderson     g_assert(n < tcg_max_ctxs);
504d73415a3SStefan Hajnoczi     qatomic_set(&tcg_ctxs[n], s);
5053468b59eSEmilio G. Cota 
50638b47b19SEmilio G. Cota     if (n > 0) {
50738b47b19SEmilio G. Cota         alloc_tcg_plugin_context(s);
508bf042e8eSRichard Henderson         tcg_region_initial_alloc(s);
50938b47b19SEmilio G. Cota     }
51038b47b19SEmilio G. Cota 
5113468b59eSEmilio G. Cota     tcg_ctx = s;
5123468b59eSEmilio G. Cota }
5133468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
5143468b59eSEmilio G. Cota 
515c896fe29Sbellard /* pool based memory allocation */
516c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
517c896fe29Sbellard {
518c896fe29Sbellard     TCGPool *p;
519c896fe29Sbellard     int pool_size;
520c896fe29Sbellard 
521c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
522c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
5237267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
524c896fe29Sbellard         p->size = size;
5254055299eSKirill Batuzov         p->next = s->pool_first_large;
5264055299eSKirill Batuzov         s->pool_first_large = p;
5274055299eSKirill Batuzov         return p->data;
528c896fe29Sbellard     } else {
529c896fe29Sbellard         p = s->pool_current;
530c896fe29Sbellard         if (!p) {
531c896fe29Sbellard             p = s->pool_first;
532c896fe29Sbellard             if (!p)
533c896fe29Sbellard                 goto new_pool;
534c896fe29Sbellard         } else {
535c896fe29Sbellard             if (!p->next) {
536c896fe29Sbellard             new_pool:
537c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
5387267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
539c896fe29Sbellard                 p->size = pool_size;
540c896fe29Sbellard                 p->next = NULL;
541a813e36fSRichard Henderson                 if (s->pool_current) {
542c896fe29Sbellard                     s->pool_current->next = p;
543a813e36fSRichard Henderson                 } else {
544c896fe29Sbellard                     s->pool_first = p;
545a813e36fSRichard Henderson                 }
546c896fe29Sbellard             } else {
547c896fe29Sbellard                 p = p->next;
548c896fe29Sbellard             }
549c896fe29Sbellard         }
550c896fe29Sbellard     }
551c896fe29Sbellard     s->pool_current = p;
552c896fe29Sbellard     s->pool_cur = p->data + size;
553c896fe29Sbellard     s->pool_end = p->data + p->size;
554c896fe29Sbellard     return p->data;
555c896fe29Sbellard }
556c896fe29Sbellard 
557c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
558c896fe29Sbellard {
5594055299eSKirill Batuzov     TCGPool *p, *t;
5604055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
5614055299eSKirill Batuzov         t = p->next;
5624055299eSKirill Batuzov         g_free(p);
5634055299eSKirill Batuzov     }
5644055299eSKirill Batuzov     s->pool_first_large = NULL;
565c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
566c896fe29Sbellard     s->pool_current = NULL;
567c896fe29Sbellard }
568c896fe29Sbellard 
5692ef6175aSRichard Henderson #include "exec/helper-proto.h"
5702ef6175aSRichard Henderson 
57139004a71SRichard Henderson static TCGHelperInfo all_helpers[] = {
5722ef6175aSRichard Henderson #include "exec/helper-tcg.h"
573100b5e01SRichard Henderson };
574619205fdSEmilio G. Cota static GHashTable *helper_table;
575100b5e01SRichard Henderson 
57622f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
577c6ef8c7bSPhilippe Mathieu-Daudé static ffi_type *typecode_to_ffi(int argmask)
578c6ef8c7bSPhilippe Mathieu-Daudé {
579e9709e17SRichard Henderson     /*
580e9709e17SRichard Henderson      * libffi does not support __int128_t, so we have forced Int128
581e9709e17SRichard Henderson      * to use the structure definition instead of the builtin type.
582e9709e17SRichard Henderson      */
583e9709e17SRichard Henderson     static ffi_type *ffi_type_i128_elements[3] = {
584e9709e17SRichard Henderson         &ffi_type_uint64,
585e9709e17SRichard Henderson         &ffi_type_uint64,
586e9709e17SRichard Henderson         NULL
587e9709e17SRichard Henderson     };
588e9709e17SRichard Henderson     static ffi_type ffi_type_i128 = {
589e9709e17SRichard Henderson         .size = 16,
590e9709e17SRichard Henderson         .alignment = __alignof__(Int128),
591e9709e17SRichard Henderson         .type = FFI_TYPE_STRUCT,
592e9709e17SRichard Henderson         .elements = ffi_type_i128_elements,
593e9709e17SRichard Henderson     };
594e9709e17SRichard Henderson 
595c6ef8c7bSPhilippe Mathieu-Daudé     switch (argmask) {
596c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_void:
597c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_void;
598c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_i32:
599c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_uint32;
600c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_s32:
601c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_sint32;
602c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_i64:
603c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_uint64;
604c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_s64:
605c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_sint64;
606c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_ptr:
607c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_pointer;
608e9709e17SRichard Henderson     case dh_typecode_i128:
609e9709e17SRichard Henderson         return &ffi_type_i128;
610c6ef8c7bSPhilippe Mathieu-Daudé     }
611c6ef8c7bSPhilippe Mathieu-Daudé     g_assert_not_reached();
612c6ef8c7bSPhilippe Mathieu-Daudé }
6130c22e176SPhilippe Mathieu-Daudé 
6140c22e176SPhilippe Mathieu-Daudé static void init_ffi_layouts(void)
6150c22e176SPhilippe Mathieu-Daudé {
6160c22e176SPhilippe Mathieu-Daudé     /* g_direct_hash/equal for direct comparisons on uint32_t.  */
617f9c4bb80SRichard Henderson     GHashTable *ffi_table = g_hash_table_new(NULL, NULL);
618f9c4bb80SRichard Henderson 
6190c22e176SPhilippe Mathieu-Daudé     for (int i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
620f9c4bb80SRichard Henderson         TCGHelperInfo *info = &all_helpers[i];
621f9c4bb80SRichard Henderson         unsigned typemask = info->typemask;
6220c22e176SPhilippe Mathieu-Daudé         gpointer hash = (gpointer)(uintptr_t)typemask;
6230c22e176SPhilippe Mathieu-Daudé         struct {
6240c22e176SPhilippe Mathieu-Daudé             ffi_cif cif;
6250c22e176SPhilippe Mathieu-Daudé             ffi_type *args[];
6260c22e176SPhilippe Mathieu-Daudé         } *ca;
6270c22e176SPhilippe Mathieu-Daudé         ffi_status status;
6280c22e176SPhilippe Mathieu-Daudé         int nargs;
629f9c4bb80SRichard Henderson         ffi_cif *cif;
6300c22e176SPhilippe Mathieu-Daudé 
631f9c4bb80SRichard Henderson         cif = g_hash_table_lookup(ffi_table, hash);
632f9c4bb80SRichard Henderson         if (cif) {
633f9c4bb80SRichard Henderson             info->cif = cif;
6340c22e176SPhilippe Mathieu-Daudé             continue;
6350c22e176SPhilippe Mathieu-Daudé         }
6360c22e176SPhilippe Mathieu-Daudé 
6370c22e176SPhilippe Mathieu-Daudé         /* Ignoring the return type, find the last non-zero field. */
6380c22e176SPhilippe Mathieu-Daudé         nargs = 32 - clz32(typemask >> 3);
6390c22e176SPhilippe Mathieu-Daudé         nargs = DIV_ROUND_UP(nargs, 3);
640e9709e17SRichard Henderson         assert(nargs <= MAX_CALL_IARGS);
6410c22e176SPhilippe Mathieu-Daudé 
6420c22e176SPhilippe Mathieu-Daudé         ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *));
6430c22e176SPhilippe Mathieu-Daudé         ca->cif.rtype = typecode_to_ffi(typemask & 7);
6440c22e176SPhilippe Mathieu-Daudé         ca->cif.nargs = nargs;
6450c22e176SPhilippe Mathieu-Daudé 
6460c22e176SPhilippe Mathieu-Daudé         if (nargs != 0) {
6470c22e176SPhilippe Mathieu-Daudé             ca->cif.arg_types = ca->args;
6480c22e176SPhilippe Mathieu-Daudé             for (int j = 0; j < nargs; ++j) {
6490c22e176SPhilippe Mathieu-Daudé                 int typecode = extract32(typemask, (j + 1) * 3, 3);
6500c22e176SPhilippe Mathieu-Daudé                 ca->args[j] = typecode_to_ffi(typecode);
6510c22e176SPhilippe Mathieu-Daudé             }
6520c22e176SPhilippe Mathieu-Daudé         }
6530c22e176SPhilippe Mathieu-Daudé 
6540c22e176SPhilippe Mathieu-Daudé         status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs,
6550c22e176SPhilippe Mathieu-Daudé                               ca->cif.rtype, ca->cif.arg_types);
6560c22e176SPhilippe Mathieu-Daudé         assert(status == FFI_OK);
6570c22e176SPhilippe Mathieu-Daudé 
658f9c4bb80SRichard Henderson         cif = &ca->cif;
659f9c4bb80SRichard Henderson         info->cif = cif;
660f9c4bb80SRichard Henderson         g_hash_table_insert(ffi_table, hash, (gpointer)cif);
6610c22e176SPhilippe Mathieu-Daudé     }
662f9c4bb80SRichard Henderson 
663f9c4bb80SRichard Henderson     g_hash_table_destroy(ffi_table);
6640c22e176SPhilippe Mathieu-Daudé }
6650c22e176SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG_INTERPRETER */
66622f15579SRichard Henderson 
66739004a71SRichard Henderson typedef struct TCGCumulativeArgs {
66839004a71SRichard Henderson     int arg_idx;                /* tcg_gen_callN args[] */
66939004a71SRichard Henderson     int info_in_idx;            /* TCGHelperInfo in[] */
67039004a71SRichard Henderson     int arg_slot;               /* regs+stack slot */
67139004a71SRichard Henderson     int ref_slot;               /* stack slots for references */
67239004a71SRichard Henderson } TCGCumulativeArgs;
67339004a71SRichard Henderson 
67439004a71SRichard Henderson static void layout_arg_even(TCGCumulativeArgs *cum)
67539004a71SRichard Henderson {
67639004a71SRichard Henderson     cum->arg_slot += cum->arg_slot & 1;
67739004a71SRichard Henderson }
67839004a71SRichard Henderson 
67939004a71SRichard Henderson static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info,
68039004a71SRichard Henderson                          TCGCallArgumentKind kind)
68139004a71SRichard Henderson {
68239004a71SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
68339004a71SRichard Henderson 
68439004a71SRichard Henderson     *loc = (TCGCallArgumentLoc){
68539004a71SRichard Henderson         .kind = kind,
68639004a71SRichard Henderson         .arg_idx = cum->arg_idx,
68739004a71SRichard Henderson         .arg_slot = cum->arg_slot,
68839004a71SRichard Henderson     };
68939004a71SRichard Henderson     cum->info_in_idx++;
69039004a71SRichard Henderson     cum->arg_slot++;
69139004a71SRichard Henderson }
69239004a71SRichard Henderson 
69339004a71SRichard Henderson static void layout_arg_normal_n(TCGCumulativeArgs *cum,
69439004a71SRichard Henderson                                 TCGHelperInfo *info, int n)
69539004a71SRichard Henderson {
69639004a71SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
69739004a71SRichard Henderson 
69839004a71SRichard Henderson     for (int i = 0; i < n; ++i) {
69939004a71SRichard Henderson         /* Layout all using the same arg_idx, adjusting the subindex. */
70039004a71SRichard Henderson         loc[i] = (TCGCallArgumentLoc){
70139004a71SRichard Henderson             .kind = TCG_CALL_ARG_NORMAL,
70239004a71SRichard Henderson             .arg_idx = cum->arg_idx,
70339004a71SRichard Henderson             .tmp_subindex = i,
70439004a71SRichard Henderson             .arg_slot = cum->arg_slot + i,
70539004a71SRichard Henderson         };
70639004a71SRichard Henderson     }
70739004a71SRichard Henderson     cum->info_in_idx += n;
70839004a71SRichard Henderson     cum->arg_slot += n;
70939004a71SRichard Henderson }
71039004a71SRichard Henderson 
711313bdea8SRichard Henderson static void layout_arg_by_ref(TCGCumulativeArgs *cum, TCGHelperInfo *info)
712313bdea8SRichard Henderson {
713313bdea8SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
714313bdea8SRichard Henderson     int n = 128 / TCG_TARGET_REG_BITS;
715313bdea8SRichard Henderson 
716313bdea8SRichard Henderson     /* The first subindex carries the pointer. */
717313bdea8SRichard Henderson     layout_arg_1(cum, info, TCG_CALL_ARG_BY_REF);
718313bdea8SRichard Henderson 
719313bdea8SRichard Henderson     /*
720313bdea8SRichard Henderson      * The callee is allowed to clobber memory associated with
721313bdea8SRichard Henderson      * structure pass by-reference.  Therefore we must make copies.
722313bdea8SRichard Henderson      * Allocate space from "ref_slot", which will be adjusted to
723313bdea8SRichard Henderson      * follow the parameters on the stack.
724313bdea8SRichard Henderson      */
725313bdea8SRichard Henderson     loc[0].ref_slot = cum->ref_slot;
726313bdea8SRichard Henderson 
727313bdea8SRichard Henderson     /*
728313bdea8SRichard Henderson      * Subsequent words also go into the reference slot, but
729313bdea8SRichard Henderson      * do not accumulate into the regular arguments.
730313bdea8SRichard Henderson      */
731313bdea8SRichard Henderson     for (int i = 1; i < n; ++i) {
732313bdea8SRichard Henderson         loc[i] = (TCGCallArgumentLoc){
733313bdea8SRichard Henderson             .kind = TCG_CALL_ARG_BY_REF_N,
734313bdea8SRichard Henderson             .arg_idx = cum->arg_idx,
735313bdea8SRichard Henderson             .tmp_subindex = i,
736313bdea8SRichard Henderson             .ref_slot = cum->ref_slot + i,
737313bdea8SRichard Henderson         };
738313bdea8SRichard Henderson     }
739313bdea8SRichard Henderson     cum->info_in_idx += n;
740313bdea8SRichard Henderson     cum->ref_slot += n;
741313bdea8SRichard Henderson }
742313bdea8SRichard Henderson 
74339004a71SRichard Henderson static void init_call_layout(TCGHelperInfo *info)
74439004a71SRichard Henderson {
74539004a71SRichard Henderson     int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs);
74639004a71SRichard Henderson     int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long);
74739004a71SRichard Henderson     unsigned typemask = info->typemask;
74839004a71SRichard Henderson     unsigned typecode;
74939004a71SRichard Henderson     TCGCumulativeArgs cum = { };
75039004a71SRichard Henderson 
75139004a71SRichard Henderson     /*
75239004a71SRichard Henderson      * Parse and place any function return value.
75339004a71SRichard Henderson      */
75439004a71SRichard Henderson     typecode = typemask & 7;
75539004a71SRichard Henderson     switch (typecode) {
75639004a71SRichard Henderson     case dh_typecode_void:
75739004a71SRichard Henderson         info->nr_out = 0;
75839004a71SRichard Henderson         break;
75939004a71SRichard Henderson     case dh_typecode_i32:
76039004a71SRichard Henderson     case dh_typecode_s32:
76139004a71SRichard Henderson     case dh_typecode_ptr:
76239004a71SRichard Henderson         info->nr_out = 1;
76339004a71SRichard Henderson         info->out_kind = TCG_CALL_RET_NORMAL;
76439004a71SRichard Henderson         break;
76539004a71SRichard Henderson     case dh_typecode_i64:
76639004a71SRichard Henderson     case dh_typecode_s64:
76739004a71SRichard Henderson         info->nr_out = 64 / TCG_TARGET_REG_BITS;
76839004a71SRichard Henderson         info->out_kind = TCG_CALL_RET_NORMAL;
7695e3d0c19SRichard Henderson         /* Query the last register now to trigger any assert early. */
7705e3d0c19SRichard Henderson         tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1);
771466d3759SRichard Henderson         break;
772466d3759SRichard Henderson     case dh_typecode_i128:
773466d3759SRichard Henderson         info->nr_out = 128 / TCG_TARGET_REG_BITS;
7745427a9a7SRichard Henderson         info->out_kind = TCG_TARGET_CALL_RET_I128;
7755427a9a7SRichard Henderson         switch (TCG_TARGET_CALL_RET_I128) {
776466d3759SRichard Henderson         case TCG_CALL_RET_NORMAL:
7775e3d0c19SRichard Henderson             /* Query the last register now to trigger any assert early. */
7785e3d0c19SRichard Henderson             tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1);
779466d3759SRichard Henderson             break;
780c6556aa0SRichard Henderson         case TCG_CALL_RET_BY_VEC:
781c6556aa0SRichard Henderson             /* Query the single register now to trigger any assert early. */
782c6556aa0SRichard Henderson             tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0);
783c6556aa0SRichard Henderson             break;
784313bdea8SRichard Henderson         case TCG_CALL_RET_BY_REF:
785313bdea8SRichard Henderson             /*
786313bdea8SRichard Henderson              * Allocate the first argument to the output.
787313bdea8SRichard Henderson              * We don't need to store this anywhere, just make it
788313bdea8SRichard Henderson              * unavailable for use in the input loop below.
789313bdea8SRichard Henderson              */
790313bdea8SRichard Henderson             cum.arg_slot = 1;
791313bdea8SRichard Henderson             break;
792466d3759SRichard Henderson         default:
793466d3759SRichard Henderson             qemu_build_not_reached();
794466d3759SRichard Henderson         }
79539004a71SRichard Henderson         break;
79639004a71SRichard Henderson     default:
79739004a71SRichard Henderson         g_assert_not_reached();
79839004a71SRichard Henderson     }
79939004a71SRichard Henderson 
80039004a71SRichard Henderson     /*
80139004a71SRichard Henderson      * Parse and place function arguments.
80239004a71SRichard Henderson      */
80339004a71SRichard Henderson     for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) {
80439004a71SRichard Henderson         TCGCallArgumentKind kind;
80539004a71SRichard Henderson         TCGType type;
80639004a71SRichard Henderson 
80739004a71SRichard Henderson         typecode = typemask & 7;
80839004a71SRichard Henderson         switch (typecode) {
80939004a71SRichard Henderson         case dh_typecode_i32:
81039004a71SRichard Henderson         case dh_typecode_s32:
81139004a71SRichard Henderson             type = TCG_TYPE_I32;
81239004a71SRichard Henderson             break;
81339004a71SRichard Henderson         case dh_typecode_i64:
81439004a71SRichard Henderson         case dh_typecode_s64:
81539004a71SRichard Henderson             type = TCG_TYPE_I64;
81639004a71SRichard Henderson             break;
81739004a71SRichard Henderson         case dh_typecode_ptr:
81839004a71SRichard Henderson             type = TCG_TYPE_PTR;
81939004a71SRichard Henderson             break;
820466d3759SRichard Henderson         case dh_typecode_i128:
821466d3759SRichard Henderson             type = TCG_TYPE_I128;
822466d3759SRichard Henderson             break;
82339004a71SRichard Henderson         default:
82439004a71SRichard Henderson             g_assert_not_reached();
82539004a71SRichard Henderson         }
82639004a71SRichard Henderson 
82739004a71SRichard Henderson         switch (type) {
82839004a71SRichard Henderson         case TCG_TYPE_I32:
82939004a71SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I32) {
83039004a71SRichard Henderson             case TCG_CALL_ARG_EVEN:
83139004a71SRichard Henderson                 layout_arg_even(&cum);
83239004a71SRichard Henderson                 /* fall through */
83339004a71SRichard Henderson             case TCG_CALL_ARG_NORMAL:
83439004a71SRichard Henderson                 layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
83539004a71SRichard Henderson                 break;
83639004a71SRichard Henderson             case TCG_CALL_ARG_EXTEND:
83739004a71SRichard Henderson                 kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1);
83839004a71SRichard Henderson                 layout_arg_1(&cum, info, kind);
83939004a71SRichard Henderson                 break;
84039004a71SRichard Henderson             default:
84139004a71SRichard Henderson                 qemu_build_not_reached();
84239004a71SRichard Henderson             }
84339004a71SRichard Henderson             break;
84439004a71SRichard Henderson 
84539004a71SRichard Henderson         case TCG_TYPE_I64:
84639004a71SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I64) {
84739004a71SRichard Henderson             case TCG_CALL_ARG_EVEN:
84839004a71SRichard Henderson                 layout_arg_even(&cum);
84939004a71SRichard Henderson                 /* fall through */
85039004a71SRichard Henderson             case TCG_CALL_ARG_NORMAL:
85139004a71SRichard Henderson                 if (TCG_TARGET_REG_BITS == 32) {
85239004a71SRichard Henderson                     layout_arg_normal_n(&cum, info, 2);
85339004a71SRichard Henderson                 } else {
85439004a71SRichard Henderson                     layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
85539004a71SRichard Henderson                 }
85639004a71SRichard Henderson                 break;
85739004a71SRichard Henderson             default:
85839004a71SRichard Henderson                 qemu_build_not_reached();
85939004a71SRichard Henderson             }
86039004a71SRichard Henderson             break;
86139004a71SRichard Henderson 
862466d3759SRichard Henderson         case TCG_TYPE_I128:
8635427a9a7SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I128) {
864466d3759SRichard Henderson             case TCG_CALL_ARG_EVEN:
865466d3759SRichard Henderson                 layout_arg_even(&cum);
866466d3759SRichard Henderson                 /* fall through */
867466d3759SRichard Henderson             case TCG_CALL_ARG_NORMAL:
868466d3759SRichard Henderson                 layout_arg_normal_n(&cum, info, 128 / TCG_TARGET_REG_BITS);
869466d3759SRichard Henderson                 break;
870313bdea8SRichard Henderson             case TCG_CALL_ARG_BY_REF:
871313bdea8SRichard Henderson                 layout_arg_by_ref(&cum, info);
872313bdea8SRichard Henderson                 break;
873466d3759SRichard Henderson             default:
874466d3759SRichard Henderson                 qemu_build_not_reached();
875466d3759SRichard Henderson             }
876466d3759SRichard Henderson             break;
877466d3759SRichard Henderson 
87839004a71SRichard Henderson         default:
87939004a71SRichard Henderson             g_assert_not_reached();
88039004a71SRichard Henderson         }
88139004a71SRichard Henderson     }
88239004a71SRichard Henderson     info->nr_in = cum.info_in_idx;
88339004a71SRichard Henderson 
88439004a71SRichard Henderson     /* Validate that we didn't overrun the input array. */
88539004a71SRichard Henderson     assert(cum.info_in_idx <= ARRAY_SIZE(info->in));
88639004a71SRichard Henderson     /* Validate the backend has enough argument space. */
88739004a71SRichard Henderson     assert(cum.arg_slot <= max_reg_slots + max_stk_slots);
888313bdea8SRichard Henderson 
889313bdea8SRichard Henderson     /*
890313bdea8SRichard Henderson      * Relocate the "ref_slot" area to the end of the parameters.
891313bdea8SRichard Henderson      * Minimizing this stack offset helps code size for x86,
892313bdea8SRichard Henderson      * which has a signed 8-bit offset encoding.
893313bdea8SRichard Henderson      */
894313bdea8SRichard Henderson     if (cum.ref_slot != 0) {
895313bdea8SRichard Henderson         int ref_base = 0;
896313bdea8SRichard Henderson 
897313bdea8SRichard Henderson         if (cum.arg_slot > max_reg_slots) {
898313bdea8SRichard Henderson             int align = __alignof(Int128) / sizeof(tcg_target_long);
899313bdea8SRichard Henderson 
900313bdea8SRichard Henderson             ref_base = cum.arg_slot - max_reg_slots;
901313bdea8SRichard Henderson             if (align > 1) {
902313bdea8SRichard Henderson                 ref_base = ROUND_UP(ref_base, align);
903313bdea8SRichard Henderson             }
904313bdea8SRichard Henderson         }
905313bdea8SRichard Henderson         assert(ref_base + cum.ref_slot <= max_stk_slots);
906313bdea8SRichard Henderson 
907313bdea8SRichard Henderson         if (ref_base != 0) {
908313bdea8SRichard Henderson             for (int i = cum.info_in_idx - 1; i >= 0; --i) {
909313bdea8SRichard Henderson                 TCGCallArgumentLoc *loc = &info->in[i];
910313bdea8SRichard Henderson                 switch (loc->kind) {
911313bdea8SRichard Henderson                 case TCG_CALL_ARG_BY_REF:
912313bdea8SRichard Henderson                 case TCG_CALL_ARG_BY_REF_N:
913313bdea8SRichard Henderson                     loc->ref_slot += ref_base;
914313bdea8SRichard Henderson                     break;
915313bdea8SRichard Henderson                 default:
916313bdea8SRichard Henderson                     break;
917313bdea8SRichard Henderson                 }
918313bdea8SRichard Henderson             }
919313bdea8SRichard Henderson         }
920313bdea8SRichard Henderson     }
92139004a71SRichard Henderson }
92239004a71SRichard Henderson 
92391478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
924f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
9251c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
9261c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
92791478cefSRichard Henderson 
92843b972b7SRichard Henderson static void tcg_context_init(unsigned max_cpus)
929c896fe29Sbellard {
930a76aabd3SRichard Henderson     TCGContext *s = &tcg_init_ctx;
931100b5e01SRichard Henderson     int op, total_args, n, i;
932c896fe29Sbellard     TCGOpDef *def;
933c896fe29Sbellard     TCGArgConstraint *args_ct;
9341c2adb95SRichard Henderson     TCGTemp *ts;
935c896fe29Sbellard 
936c896fe29Sbellard     memset(s, 0, sizeof(*s));
937c896fe29Sbellard     s->nb_globals = 0;
938c896fe29Sbellard 
939c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
940c896fe29Sbellard        space */
941c896fe29Sbellard     total_args = 0;
942c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
943c896fe29Sbellard         def = &tcg_op_defs[op];
944c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
945c896fe29Sbellard         total_args += n;
946c896fe29Sbellard     }
947c896fe29Sbellard 
948bc2b17e6SRichard Henderson     args_ct = g_new0(TCGArgConstraint, total_args);
949c896fe29Sbellard 
950c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
951c896fe29Sbellard         def = &tcg_op_defs[op];
952c896fe29Sbellard         def->args_ct = args_ct;
953c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
954c896fe29Sbellard         args_ct += n;
955c896fe29Sbellard     }
956c896fe29Sbellard 
9575cd8f621SRichard Henderson     /* Register helpers.  */
95884fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
959619205fdSEmilio G. Cota     helper_table = g_hash_table_new(NULL, NULL);
96084fd9dd3SRichard Henderson 
961100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
96239004a71SRichard Henderson         init_call_layout(&all_helpers[i]);
96384fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
96472866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
965100b5e01SRichard Henderson     }
9665cd8f621SRichard Henderson 
96722f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
9680c22e176SPhilippe Mathieu-Daudé     init_ffi_layouts();
96922f15579SRichard Henderson #endif
97022f15579SRichard Henderson 
971c896fe29Sbellard     tcg_target_init(s);
972f69d277eSRichard Henderson     process_op_defs(s);
97391478cefSRichard Henderson 
97491478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
97591478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
97691478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
97791478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
97891478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
97991478cefSRichard Henderson             break;
98091478cefSRichard Henderson         }
98191478cefSRichard Henderson     }
98291478cefSRichard Henderson     for (i = 0; i < n; ++i) {
98391478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
98491478cefSRichard Henderson     }
98591478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
98691478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
98791478cefSRichard Henderson     }
988b1311c4aSEmilio G. Cota 
98938b47b19SEmilio G. Cota     alloc_tcg_plugin_context(s);
99038b47b19SEmilio G. Cota 
991b1311c4aSEmilio G. Cota     tcg_ctx = s;
9923468b59eSEmilio G. Cota     /*
9933468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
9943468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
9953468b59eSEmilio G. Cota      * reasoning behind this.
9963468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
9973468b59eSEmilio G. Cota      */
9983468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
999df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
10000e2d61cfSRichard Henderson     tcg_cur_ctxs = 1;
10010e2d61cfSRichard Henderson     tcg_max_ctxs = 1;
10023468b59eSEmilio G. Cota #else
10030e2d61cfSRichard Henderson     tcg_max_ctxs = max_cpus;
10040e2d61cfSRichard Henderson     tcg_ctxs = g_new0(TCGContext *, max_cpus);
10053468b59eSEmilio G. Cota #endif
10061c2adb95SRichard Henderson 
10071c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
10081c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
10091c2adb95SRichard Henderson     cpu_env = temp_tcgv_ptr(ts);
10109002ec79SRichard Henderson }
1011b03cce8eSbellard 
101243b972b7SRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus)
1013a76aabd3SRichard Henderson {
101443b972b7SRichard Henderson     tcg_context_init(max_cpus);
101543b972b7SRichard Henderson     tcg_region_init(tb_size, splitwx, max_cpus);
1016a76aabd3SRichard Henderson }
1017a76aabd3SRichard Henderson 
10186e3b2bfdSEmilio G. Cota /*
10196e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
10206e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
10216e3b2bfdSEmilio G. Cota  */
10226e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
10236e3b2bfdSEmilio G. Cota {
10246e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
10256e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
10266e3b2bfdSEmilio G. Cota     void *next;
10276e3b2bfdSEmilio G. Cota 
1028e8feb96fSEmilio G. Cota  retry:
10296e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
10306e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
10316e3b2bfdSEmilio G. Cota 
10326e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
1033e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
10346e3b2bfdSEmilio G. Cota             return NULL;
10356e3b2bfdSEmilio G. Cota         }
1036e8feb96fSEmilio G. Cota         goto retry;
1037e8feb96fSEmilio G. Cota     }
1038d73415a3SStefan Hajnoczi     qatomic_set(&s->code_gen_ptr, next);
103957a26946SRichard Henderson     s->data_gen_ptr = NULL;
10406e3b2bfdSEmilio G. Cota     return tb;
10416e3b2bfdSEmilio G. Cota }
10426e3b2bfdSEmilio G. Cota 
10439002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
10449002ec79SRichard Henderson {
1045b0a0794aSRichard Henderson     size_t prologue_size;
10468163b749SRichard Henderson 
1047b0a0794aSRichard Henderson     s->code_ptr = s->code_gen_ptr;
1048b0a0794aSRichard Henderson     s->code_buf = s->code_gen_ptr;
10495b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
1050b91ccb31SRichard Henderson 
1051b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1052b0a0794aSRichard Henderson     tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr);
1053b91ccb31SRichard Henderson #endif
10548163b749SRichard Henderson 
10555b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
10565b38ee31SRichard Henderson     s->pool_labels = NULL;
10575b38ee31SRichard Henderson #endif
10585b38ee31SRichard Henderson 
1059653b87ebSRoman Bolshakov     qemu_thread_jit_write();
10608163b749SRichard Henderson     /* Generate the prologue.  */
1061b03cce8eSbellard     tcg_target_qemu_prologue(s);
10625b38ee31SRichard Henderson 
10635b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
10645b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
10655b38ee31SRichard Henderson     {
10661768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
10671768987bSRichard Henderson         tcg_debug_assert(result == 0);
10685b38ee31SRichard Henderson     }
10695b38ee31SRichard Henderson #endif
10705b38ee31SRichard Henderson 
1071b0a0794aSRichard Henderson     prologue_size = tcg_current_code_size(s);
10725584e2dbSIlya Leoshkevich     perf_report_prologue(s->code_gen_ptr, prologue_size);
1073b0a0794aSRichard Henderson 
1074df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1075b0a0794aSRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
1076b0a0794aSRichard Henderson                         (uintptr_t)s->code_buf, prologue_size);
1077df5d2b16SRichard Henderson #endif
10788163b749SRichard Henderson 
1079d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
1080d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
1081c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
108278b54858SRichard Henderson         if (logfile) {
108378b54858SRichard Henderson             fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size);
10845b38ee31SRichard Henderson             if (s->data_gen_ptr) {
1085b0a0794aSRichard Henderson                 size_t code_size = s->data_gen_ptr - s->code_gen_ptr;
10865b38ee31SRichard Henderson                 size_t data_size = prologue_size - code_size;
10875b38ee31SRichard Henderson                 size_t i;
10885b38ee31SRichard Henderson 
108978b54858SRichard Henderson                 disas(logfile, s->code_gen_ptr, code_size);
10905b38ee31SRichard Henderson 
10915b38ee31SRichard Henderson                 for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
10925b38ee31SRichard Henderson                     if (sizeof(tcg_target_ulong) == 8) {
109378b54858SRichard Henderson                         fprintf(logfile,
109478b54858SRichard Henderson                                 "0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
10955b38ee31SRichard Henderson                                 (uintptr_t)s->data_gen_ptr + i,
10965b38ee31SRichard Henderson                                 *(uint64_t *)(s->data_gen_ptr + i));
10975b38ee31SRichard Henderson                     } else {
109878b54858SRichard Henderson                         fprintf(logfile,
109978b54858SRichard Henderson                                 "0x%08" PRIxPTR ":  .long  0x%08x\n",
11005b38ee31SRichard Henderson                                 (uintptr_t)s->data_gen_ptr + i,
11015b38ee31SRichard Henderson                                 *(uint32_t *)(s->data_gen_ptr + i));
11025b38ee31SRichard Henderson                     }
11035b38ee31SRichard Henderson                 }
11045b38ee31SRichard Henderson             } else {
110578b54858SRichard Henderson                 disas(logfile, s->code_gen_ptr, prologue_size);
11065b38ee31SRichard Henderson             }
110778b54858SRichard Henderson             fprintf(logfile, "\n");
1108fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
1109d6b64b2bSRichard Henderson         }
111078b54858SRichard Henderson     }
1111d6b64b2bSRichard Henderson #endif
1112cedbcb01SEmilio G. Cota 
11136eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
11146eea0434SRichard Henderson     /*
11156eea0434SRichard Henderson      * Assert that goto_ptr is implemented completely, setting an epilogue.
11166eea0434SRichard Henderson      * For tci, we use NULL as the signal to return from the interpreter,
11176eea0434SRichard Henderson      * so skip this check.
11186eea0434SRichard Henderson      */
11198b5c2b62SRichard Henderson     tcg_debug_assert(tcg_code_gen_epilogue != NULL);
11206eea0434SRichard Henderson #endif
1121d1c74ab3SRichard Henderson 
1122d1c74ab3SRichard Henderson     tcg_region_prologue_set(s);
1123c896fe29Sbellard }
1124c896fe29Sbellard 
1125c896fe29Sbellard void tcg_func_start(TCGContext *s)
1126c896fe29Sbellard {
1127c896fe29Sbellard     tcg_pool_reset(s);
1128c896fe29Sbellard     s->nb_temps = s->nb_globals;
11290ec9eabcSRichard Henderson 
11300ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
11310ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
11320ec9eabcSRichard Henderson 
1133c0522136SRichard Henderson     /* No constant temps have been previously allocated. */
1134c0522136SRichard Henderson     for (int i = 0; i < TCG_TYPE_COUNT; ++i) {
1135c0522136SRichard Henderson         if (s->const_table[i]) {
1136c0522136SRichard Henderson             g_hash_table_remove_all(s->const_table[i]);
1137c0522136SRichard Henderson         }
1138c0522136SRichard Henderson     }
1139c0522136SRichard Henderson 
1140abebf925SRichard Henderson     s->nb_ops = 0;
1141c896fe29Sbellard     s->nb_labels = 0;
1142c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1143c896fe29Sbellard 
11440a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
11450a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
11460a209d4bSRichard Henderson #endif
11470a209d4bSRichard Henderson 
114815fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
114915fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
1150bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
1151c896fe29Sbellard }
1152c896fe29Sbellard 
1153ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s)
11547ca4b752SRichard Henderson {
11557ca4b752SRichard Henderson     int n = s->nb_temps++;
1156ae30e866SRichard Henderson 
1157ae30e866SRichard Henderson     if (n >= TCG_MAX_TEMPS) {
1158db6b7d0cSRichard Henderson         tcg_raise_tb_overflow(s);
1159ae30e866SRichard Henderson     }
11607ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
11617ca4b752SRichard Henderson }
11627ca4b752SRichard Henderson 
1163ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s)
11647ca4b752SRichard Henderson {
1165fa477d25SRichard Henderson     TCGTemp *ts;
1166fa477d25SRichard Henderson 
11677ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
1168ae30e866SRichard Henderson     tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS);
11697ca4b752SRichard Henderson     s->nb_globals++;
1170fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1171ee17db83SRichard Henderson     ts->kind = TEMP_GLOBAL;
1172fa477d25SRichard Henderson 
1173fa477d25SRichard Henderson     return ts;
1174c896fe29Sbellard }
1175c896fe29Sbellard 
1176085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1177b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1178c896fe29Sbellard {
1179c896fe29Sbellard     TCGTemp *ts;
1180c896fe29Sbellard 
11811a057554SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32);
11827ca4b752SRichard Henderson 
11837ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1184c896fe29Sbellard     ts->base_type = type;
1185c896fe29Sbellard     ts->type = type;
1186ee17db83SRichard Henderson     ts->kind = TEMP_FIXED;
1187c896fe29Sbellard     ts->reg = reg;
1188c896fe29Sbellard     ts->name = name;
1189c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
11907ca4b752SRichard Henderson 
1191085272b3SRichard Henderson     return ts;
1192a7812ae4Spbrook }
1193a7812ae4Spbrook 
1194b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1195a7812ae4Spbrook {
1196b3a62939SRichard Henderson     s->frame_start = start;
1197b3a62939SRichard Henderson     s->frame_end = start + size;
1198085272b3SRichard Henderson     s->frame_temp
1199085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1200b3a62939SRichard Henderson }
1201a7812ae4Spbrook 
1202085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
1203e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
1204c896fe29Sbellard {
1205b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1206dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
12077ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1208aef85402SRichard Henderson     int indirect_reg = 0;
1209c896fe29Sbellard 
1210c0522136SRichard Henderson     switch (base_ts->kind) {
1211c0522136SRichard Henderson     case TEMP_FIXED:
1212c0522136SRichard Henderson         break;
1213c0522136SRichard Henderson     case TEMP_GLOBAL:
12145a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
12155a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1216b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
12175a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
12185a18407fSRichard Henderson                             ? 2 : 1);
12195a18407fSRichard Henderson         indirect_reg = 1;
1220c0522136SRichard Henderson         break;
1221c0522136SRichard Henderson     default:
1222c0522136SRichard Henderson         g_assert_not_reached();
1223b3915dbbSRichard Henderson     }
1224b3915dbbSRichard Henderson 
12257ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
12267ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1227c896fe29Sbellard         char buf[64];
12287ca4b752SRichard Henderson 
12297ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1230c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1231b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1232c896fe29Sbellard         ts->mem_allocated = 1;
1233b3a62939SRichard Henderson         ts->mem_base = base_ts;
1234aef85402SRichard Henderson         ts->mem_offset = offset;
1235c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1236c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1237c896fe29Sbellard         ts->name = strdup(buf);
1238c896fe29Sbellard 
12397ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
12407ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
12417ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1242b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
12437ca4b752SRichard Henderson         ts2->mem_allocated = 1;
12447ca4b752SRichard Henderson         ts2->mem_base = base_ts;
1245aef85402SRichard Henderson         ts2->mem_offset = offset + 4;
1246fac87bd2SRichard Henderson         ts2->temp_subindex = 1;
1247c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1248c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1249120c1084SRichard Henderson         ts2->name = strdup(buf);
12507ca4b752SRichard Henderson     } else {
1251c896fe29Sbellard         ts->base_type = type;
1252c896fe29Sbellard         ts->type = type;
1253b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1254c896fe29Sbellard         ts->mem_allocated = 1;
1255b3a62939SRichard Henderson         ts->mem_base = base_ts;
1256c896fe29Sbellard         ts->mem_offset = offset;
1257c896fe29Sbellard         ts->name = name;
1258c896fe29Sbellard     }
1259085272b3SRichard Henderson     return ts;
1260c896fe29Sbellard }
1261c896fe29Sbellard 
1262bbf989bfSRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, TCGTempKind kind)
1263c896fe29Sbellard {
1264b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1265c896fe29Sbellard     TCGTemp *ts;
1266e1c08b00SRichard Henderson     int n;
1267c896fe29Sbellard 
1268e1c08b00SRichard Henderson     if (kind == TEMP_EBB) {
1269e1c08b00SRichard Henderson         int idx = find_first_bit(s->free_temps[type].l, TCG_MAX_TEMPS);
1270e1c08b00SRichard Henderson 
12710ec9eabcSRichard Henderson         if (idx < TCG_MAX_TEMPS) {
12720ec9eabcSRichard Henderson             /* There is already an available temp with the right type.  */
1273e1c08b00SRichard Henderson             clear_bit(idx, s->free_temps[type].l);
12740ec9eabcSRichard Henderson 
1275e8996ee0Sbellard             ts = &s->temps[idx];
1276e8996ee0Sbellard             ts->temp_allocated = 1;
12777ca4b752SRichard Henderson             tcg_debug_assert(ts->base_type == type);
1278ee17db83SRichard Henderson             tcg_debug_assert(ts->kind == kind);
12792f2e911dSRichard Henderson             return ts;
1280e1c08b00SRichard Henderson         }
1281e8996ee0Sbellard     } else {
1282e1c08b00SRichard Henderson         tcg_debug_assert(kind == TEMP_TB);
1283e1c08b00SRichard Henderson     }
128443eef72fSRichard Henderson 
128543eef72fSRichard Henderson     switch (type) {
128643eef72fSRichard Henderson     case TCG_TYPE_I32:
128743eef72fSRichard Henderson     case TCG_TYPE_V64:
128843eef72fSRichard Henderson     case TCG_TYPE_V128:
128943eef72fSRichard Henderson     case TCG_TYPE_V256:
129043eef72fSRichard Henderson         n = 1;
129143eef72fSRichard Henderson         break;
129243eef72fSRichard Henderson     case TCG_TYPE_I64:
129343eef72fSRichard Henderson         n = 64 / TCG_TARGET_REG_BITS;
129443eef72fSRichard Henderson         break;
129543eef72fSRichard Henderson     case TCG_TYPE_I128:
129643eef72fSRichard Henderson         n = 128 / TCG_TARGET_REG_BITS;
129743eef72fSRichard Henderson         break;
129843eef72fSRichard Henderson     default:
129943eef72fSRichard Henderson         g_assert_not_reached();
130043eef72fSRichard Henderson     }
130143eef72fSRichard Henderson 
13027ca4b752SRichard Henderson     ts = tcg_temp_alloc(s);
130343eef72fSRichard Henderson     ts->base_type = type;
130443eef72fSRichard Henderson     ts->temp_allocated = 1;
130543eef72fSRichard Henderson     ts->kind = kind;
130643eef72fSRichard Henderson 
130743eef72fSRichard Henderson     if (n == 1) {
130843eef72fSRichard Henderson         ts->type = type;
130943eef72fSRichard Henderson     } else {
131043eef72fSRichard Henderson         ts->type = TCG_TYPE_REG;
131143eef72fSRichard Henderson 
1312e1c08b00SRichard Henderson         for (int i = 1; i < n; ++i) {
13137ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
13147ca4b752SRichard Henderson 
131543eef72fSRichard Henderson             tcg_debug_assert(ts2 == ts + i);
131643eef72fSRichard Henderson             ts2->base_type = type;
131743eef72fSRichard Henderson             ts2->type = TCG_TYPE_REG;
13187ca4b752SRichard Henderson             ts2->temp_allocated = 1;
131943eef72fSRichard Henderson             ts2->temp_subindex = i;
1320ee17db83SRichard Henderson             ts2->kind = kind;
132143eef72fSRichard Henderson         }
1322c896fe29Sbellard     }
1323085272b3SRichard Henderson     return ts;
1324c896fe29Sbellard }
1325c896fe29Sbellard 
1326d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1327d2fd745fSRichard Henderson {
1328d2fd745fSRichard Henderson     TCGTemp *t;
1329d2fd745fSRichard Henderson 
1330d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1331d2fd745fSRichard Henderson     switch (type) {
1332d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1333d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1334d2fd745fSRichard Henderson         break;
1335d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1336d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1337d2fd745fSRichard Henderson         break;
1338d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1339d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1340d2fd745fSRichard Henderson         break;
1341d2fd745fSRichard Henderson     default:
1342d2fd745fSRichard Henderson         g_assert_not_reached();
1343d2fd745fSRichard Henderson     }
1344d2fd745fSRichard Henderson #endif
1345d2fd745fSRichard Henderson 
1346bbf989bfSRichard Henderson     t = tcg_temp_new_internal(type, TEMP_EBB);
1347d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1348d2fd745fSRichard Henderson }
1349d2fd745fSRichard Henderson 
1350d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1351d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1352d2fd745fSRichard Henderson {
1353d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1354d2fd745fSRichard Henderson 
1355d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1356d2fd745fSRichard Henderson 
1357bbf989bfSRichard Henderson     t = tcg_temp_new_internal(t->base_type, TEMP_EBB);
1358d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1359d2fd745fSRichard Henderson }
1360d2fd745fSRichard Henderson 
13615bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1362c896fe29Sbellard {
1363b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1364c896fe29Sbellard 
1365c7482438SRichard Henderson     switch (ts->kind) {
1366c7482438SRichard Henderson     case TEMP_CONST:
1367f57c6915SRichard Henderson     case TEMP_TB:
13682f2e911dSRichard Henderson         /* Silently ignore free. */
1369c7482438SRichard Henderson         break;
13702f2e911dSRichard Henderson     case TEMP_EBB:
1371eabb7b91SAurelien Jarno         tcg_debug_assert(ts->temp_allocated != 0);
1372e8996ee0Sbellard         ts->temp_allocated = 0;
13732f2e911dSRichard Henderson         set_bit(temp_idx(ts), s->free_temps[ts->base_type].l);
13742f2e911dSRichard Henderson         break;
13752f2e911dSRichard Henderson     default:
13762f2e911dSRichard Henderson         /* It never made sense to free TEMP_FIXED or TEMP_GLOBAL. */
13772f2e911dSRichard Henderson         g_assert_not_reached();
1378e1c08b00SRichard Henderson     }
1379e8996ee0Sbellard }
1380e8996ee0Sbellard 
1381c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val)
1382c0522136SRichard Henderson {
1383c0522136SRichard Henderson     TCGContext *s = tcg_ctx;
1384c0522136SRichard Henderson     GHashTable *h = s->const_table[type];
1385c0522136SRichard Henderson     TCGTemp *ts;
1386c0522136SRichard Henderson 
1387c0522136SRichard Henderson     if (h == NULL) {
1388c0522136SRichard Henderson         h = g_hash_table_new(g_int64_hash, g_int64_equal);
1389c0522136SRichard Henderson         s->const_table[type] = h;
1390c0522136SRichard Henderson     }
1391c0522136SRichard Henderson 
1392c0522136SRichard Henderson     ts = g_hash_table_lookup(h, &val);
1393c0522136SRichard Henderson     if (ts == NULL) {
1394aef85402SRichard Henderson         int64_t *val_ptr;
1395aef85402SRichard Henderson 
1396c0522136SRichard Henderson         ts = tcg_temp_alloc(s);
1397c0522136SRichard Henderson 
1398c0522136SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
1399c0522136SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
1400c0522136SRichard Henderson 
1401aef85402SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
1402aef85402SRichard Henderson 
1403c0522136SRichard Henderson             ts->base_type = TCG_TYPE_I64;
1404c0522136SRichard Henderson             ts->type = TCG_TYPE_I32;
1405c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1406c0522136SRichard Henderson             ts->temp_allocated = 1;
1407c0522136SRichard Henderson 
1408c0522136SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
1409c0522136SRichard Henderson             ts2->type = TCG_TYPE_I32;
1410c0522136SRichard Henderson             ts2->kind = TEMP_CONST;
1411c0522136SRichard Henderson             ts2->temp_allocated = 1;
1412fac87bd2SRichard Henderson             ts2->temp_subindex = 1;
1413aef85402SRichard Henderson 
1414aef85402SRichard Henderson             /*
1415aef85402SRichard Henderson              * Retain the full value of the 64-bit constant in the low
1416aef85402SRichard Henderson              * part, so that the hash table works.  Actual uses will
1417aef85402SRichard Henderson              * truncate the value to the low part.
1418aef85402SRichard Henderson              */
1419aef85402SRichard Henderson             ts[HOST_BIG_ENDIAN].val = val;
1420aef85402SRichard Henderson             ts[!HOST_BIG_ENDIAN].val = val >> 32;
1421aef85402SRichard Henderson             val_ptr = &ts[HOST_BIG_ENDIAN].val;
1422c0522136SRichard Henderson         } else {
1423c0522136SRichard Henderson             ts->base_type = type;
1424c0522136SRichard Henderson             ts->type = type;
1425c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1426c0522136SRichard Henderson             ts->temp_allocated = 1;
1427c0522136SRichard Henderson             ts->val = val;
1428aef85402SRichard Henderson             val_ptr = &ts->val;
1429c0522136SRichard Henderson         }
1430aef85402SRichard Henderson         g_hash_table_insert(h, val_ptr, ts);
1431c0522136SRichard Henderson     }
1432c0522136SRichard Henderson 
1433c0522136SRichard Henderson     return ts;
1434c0522136SRichard Henderson }
1435c0522136SRichard Henderson 
1436c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val)
1437c0522136SRichard Henderson {
1438c0522136SRichard Henderson     val = dup_const(vece, val);
1439c0522136SRichard Henderson     return temp_tcgv_vec(tcg_constant_internal(type, val));
1440c0522136SRichard Henderson }
1441c0522136SRichard Henderson 
144288d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val)
144388d4005bSRichard Henderson {
144488d4005bSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
144588d4005bSRichard Henderson 
144688d4005bSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
144788d4005bSRichard Henderson     return tcg_constant_vec(t->base_type, vece, val);
144888d4005bSRichard Henderson }
144988d4005bSRichard Henderson 
1450be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1451be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1452be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1453be0f34b5SRichard Henderson {
1454d2fd745fSRichard Henderson     const bool have_vec
1455d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1456d2fd745fSRichard Henderson 
1457be0f34b5SRichard Henderson     switch (op) {
1458be0f34b5SRichard Henderson     case INDEX_op_discard:
1459be0f34b5SRichard Henderson     case INDEX_op_set_label:
1460be0f34b5SRichard Henderson     case INDEX_op_call:
1461be0f34b5SRichard Henderson     case INDEX_op_br:
1462be0f34b5SRichard Henderson     case INDEX_op_mb:
1463be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1464be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1465be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1466f4e01e30SRichard Henderson     case INDEX_op_goto_ptr:
1467be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i32:
1468be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i32:
1469be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i64:
1470be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i64:
1471be0f34b5SRichard Henderson         return true;
1472be0f34b5SRichard Henderson 
147307ce0b05SRichard Henderson     case INDEX_op_qemu_st8_i32:
147407ce0b05SRichard Henderson         return TCG_TARGET_HAS_qemu_st8_i32;
147507ce0b05SRichard Henderson 
1476be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1477be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1478be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1479be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1480be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1481be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1482be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1483be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1484be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1485be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1486be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1487be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1488be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1489be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1490be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1491be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1492be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1493be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1494be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1495be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1496be0f34b5SRichard Henderson         return true;
1497be0f34b5SRichard Henderson 
1498be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1499be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1500be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1501be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1502be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1503be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1504be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1505be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1506be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1507be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1508be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1509be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1510be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1511be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1512be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1513be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1514be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1515be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1516be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1517be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1518fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
1519fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
1520be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1521be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1522be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1523be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1524be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1525be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1526be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1527be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1528be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1529be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1530be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1531be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1532be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1533be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1534be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1535be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1536be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1537be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1538be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1539be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1540be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1541be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1542be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1543be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1544be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1545be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1546be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1547be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1548be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1549be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1550be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1551be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1552be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1553be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1554be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1555be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1556be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1557be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1558be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1559be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1560be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1561be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1562be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1563be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1564be0f34b5SRichard Henderson 
1565be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1566be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1567be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1568be0f34b5SRichard Henderson 
1569be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1570be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1571be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1572be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1573be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1574be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1575be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1576be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1577be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1578be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1579be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1580be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1581be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1582be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1583be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1584be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1585be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1586be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1587be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1588be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1589be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1590be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1591be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1592be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1593be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1594be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1595be0f34b5SRichard Henderson 
1596be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1597be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1598be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1599be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1600be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1601be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1602be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1603be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1604be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1605be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
1606be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
1607be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
1608be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
1609be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
1610be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
1611be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
1612be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
1613be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
1614be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
1615be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
1616fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
1617fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
1618be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
1619be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrl_i64_i32;
1620be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
1621be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrh_i64_i32;
1622be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
1623be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
1624be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
1625be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
1626be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
1627be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
1628be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
1629be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
1630be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
1631be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
1632be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
1633be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
1634be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
1635be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
1636be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
1637be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
1638be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
1639be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
1640be0f34b5SRichard Henderson     case INDEX_op_not_i64:
1641be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
1642be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
1643be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
1644be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
1645be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
1646be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
1647be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
1648be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
1649be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
1650be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
1651be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
1652be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
1653be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
1654be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
1655be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
1656be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
1657be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
1658be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
1659be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
1660be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
1661be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
1662be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
1663be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
1664be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
1665be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
1666be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
1667be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
1668be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
1669be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
1670be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
1671be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
1672be0f34b5SRichard Henderson 
1673d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
1674d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
167537ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
1676d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
1677d2fd745fSRichard Henderson     case INDEX_op_st_vec:
1678d2fd745fSRichard Henderson     case INDEX_op_add_vec:
1679d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
1680d2fd745fSRichard Henderson     case INDEX_op_and_vec:
1681d2fd745fSRichard Henderson     case INDEX_op_or_vec:
1682d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
1683212be173SRichard Henderson     case INDEX_op_cmp_vec:
1684d2fd745fSRichard Henderson         return have_vec;
1685d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
1686d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
1687d2fd745fSRichard Henderson     case INDEX_op_not_vec:
1688d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
1689d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
1690d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
1691bcefc902SRichard Henderson     case INDEX_op_abs_vec:
1692bcefc902SRichard Henderson         return have_vec && TCG_TARGET_HAS_abs_vec;
1693d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
1694d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
1695d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
1696d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
1697ed523473SRichard Henderson     case INDEX_op_nand_vec:
1698ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_nand_vec;
1699ed523473SRichard Henderson     case INDEX_op_nor_vec:
1700ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_nor_vec;
1701ed523473SRichard Henderson     case INDEX_op_eqv_vec:
1702ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_eqv_vec;
17033774030aSRichard Henderson     case INDEX_op_mul_vec:
17043774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
1705d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
1706d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
1707d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
1708d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
1709d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
1710d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
1711d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
1712d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
1713d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
1714d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
1715d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
1716d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
1717b0f7e744SRichard Henderson     case INDEX_op_rotli_vec:
1718b0f7e744SRichard Henderson         return have_vec && TCG_TARGET_HAS_roti_vec;
171923850a74SRichard Henderson     case INDEX_op_rotls_vec:
172023850a74SRichard Henderson         return have_vec && TCG_TARGET_HAS_rots_vec;
17215d0ceda9SRichard Henderson     case INDEX_op_rotlv_vec:
17225d0ceda9SRichard Henderson     case INDEX_op_rotrv_vec:
17235d0ceda9SRichard Henderson         return have_vec && TCG_TARGET_HAS_rotv_vec;
17248afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
17258afaf050SRichard Henderson     case INDEX_op_usadd_vec:
17268afaf050SRichard Henderson     case INDEX_op_sssub_vec:
17278afaf050SRichard Henderson     case INDEX_op_ussub_vec:
17288afaf050SRichard Henderson         return have_vec && TCG_TARGET_HAS_sat_vec;
1729dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
1730dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
1731dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
1732dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
1733dd0a0fcdSRichard Henderson         return have_vec && TCG_TARGET_HAS_minmax_vec;
173438dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
173538dc1294SRichard Henderson         return have_vec && TCG_TARGET_HAS_bitsel_vec;
1736f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
1737f75da298SRichard Henderson         return have_vec && TCG_TARGET_HAS_cmpsel_vec;
1738d2fd745fSRichard Henderson 
1739db432672SRichard Henderson     default:
1740db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
1741db432672SRichard Henderson         return true;
1742be0f34b5SRichard Henderson     }
1743be0f34b5SRichard Henderson }
1744be0f34b5SRichard Henderson 
174539004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs);
174639004a71SRichard Henderson 
1747ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
1748c896fe29Sbellard {
17493e92aa34SRichard Henderson     const TCGHelperInfo *info;
175039004a71SRichard Henderson     TCGv_i64 extend_free[MAX_CALL_IARGS];
175139004a71SRichard Henderson     int n_extend = 0;
175275e8b9b7SRichard Henderson     TCGOp *op;
175339004a71SRichard Henderson     int i, n, pi = 0, total_args;
1754afb49896SRichard Henderson 
1755619205fdSEmilio G. Cota     info = g_hash_table_lookup(helper_table, (gpointer)func);
175639004a71SRichard Henderson     total_args = info->nr_out + info->nr_in + 2;
175739004a71SRichard Henderson     op = tcg_op_alloc(INDEX_op_call, total_args);
17582bece2c8SRichard Henderson 
175938b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
176017083f6fSEmilio Cota     /* Flag helpers that may affect guest state */
176117083f6fSEmilio Cota     if (tcg_ctx->plugin_insn &&
176217083f6fSEmilio Cota         !(info->flags & TCG_CALL_PLUGIN) &&
176317083f6fSEmilio Cota         !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) {
176438b47b19SEmilio G. Cota         tcg_ctx->plugin_insn->calls_helpers = true;
176538b47b19SEmilio G. Cota     }
176638b47b19SEmilio G. Cota #endif
176738b47b19SEmilio G. Cota 
176839004a71SRichard Henderson     TCGOP_CALLO(op) = n = info->nr_out;
176939004a71SRichard Henderson     switch (n) {
177039004a71SRichard Henderson     case 0:
177139004a71SRichard Henderson         tcg_debug_assert(ret == NULL);
177239004a71SRichard Henderson         break;
177339004a71SRichard Henderson     case 1:
177439004a71SRichard Henderson         tcg_debug_assert(ret != NULL);
177539004a71SRichard Henderson         op->args[pi++] = temp_arg(ret);
177639004a71SRichard Henderson         break;
177739004a71SRichard Henderson     case 2:
1778466d3759SRichard Henderson     case 4:
177939004a71SRichard Henderson         tcg_debug_assert(ret != NULL);
1780466d3759SRichard Henderson         tcg_debug_assert(ret->base_type == ret->type + ctz32(n));
178139004a71SRichard Henderson         tcg_debug_assert(ret->temp_subindex == 0);
1782466d3759SRichard Henderson         for (i = 0; i < n; ++i) {
1783466d3759SRichard Henderson             op->args[pi++] = temp_arg(ret + i);
1784466d3759SRichard Henderson         }
178539004a71SRichard Henderson         break;
178639004a71SRichard Henderson     default:
178739004a71SRichard Henderson         g_assert_not_reached();
178839004a71SRichard Henderson     }
17897319d83aSRichard Henderson 
179039004a71SRichard Henderson     TCGOP_CALLI(op) = n = info->nr_in;
179139004a71SRichard Henderson     for (i = 0; i < n; i++) {
179239004a71SRichard Henderson         const TCGCallArgumentLoc *loc = &info->in[i];
179339004a71SRichard Henderson         TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex;
179439004a71SRichard Henderson 
179539004a71SRichard Henderson         switch (loc->kind) {
179639004a71SRichard Henderson         case TCG_CALL_ARG_NORMAL:
1797313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF:
1798313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF_N:
179939004a71SRichard Henderson             op->args[pi++] = temp_arg(ts);
180039004a71SRichard Henderson             break;
180139004a71SRichard Henderson 
180239004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
180339004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
180439004a71SRichard Henderson             {
18055dd48602SRichard Henderson                 TCGv_i64 temp = tcg_temp_ebb_new_i64();
180639004a71SRichard Henderson                 TCGv_i32 orig = temp_tcgv_i32(ts);
180739004a71SRichard Henderson 
180839004a71SRichard Henderson                 if (loc->kind == TCG_CALL_ARG_EXTEND_S) {
180918cf3d07SRichard Henderson                     tcg_gen_ext_i32_i64(temp, orig);
18102bece2c8SRichard Henderson                 } else {
181118cf3d07SRichard Henderson                     tcg_gen_extu_i32_i64(temp, orig);
18122bece2c8SRichard Henderson                 }
181339004a71SRichard Henderson                 op->args[pi++] = tcgv_i64_arg(temp);
181439004a71SRichard Henderson                 extend_free[n_extend++] = temp;
18152bece2c8SRichard Henderson             }
181639004a71SRichard Henderson             break;
18172bece2c8SRichard Henderson 
1818e2a9dd6bSRichard Henderson         default:
1819e2a9dd6bSRichard Henderson             g_assert_not_reached();
1820e2a9dd6bSRichard Henderson         }
1821c896fe29Sbellard     }
182275e8b9b7SRichard Henderson     op->args[pi++] = (uintptr_t)func;
18233e92aa34SRichard Henderson     op->args[pi++] = (uintptr_t)info;
182439004a71SRichard Henderson     tcg_debug_assert(pi == total_args);
1825a7812ae4Spbrook 
182639004a71SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
18272bece2c8SRichard Henderson 
182839004a71SRichard Henderson     tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free));
182939004a71SRichard Henderson     for (i = 0; i < n_extend; ++i) {
183039004a71SRichard Henderson         tcg_temp_free_i64(extend_free[i]);
1831eb8b0224SRichard Henderson     }
1832a7812ae4Spbrook }
1833c896fe29Sbellard 
18348fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
1835c896fe29Sbellard {
1836ac3b8891SRichard Henderson     int i, n;
1837ac3b8891SRichard Henderson 
1838ee17db83SRichard Henderson     for (i = 0, n = s->nb_temps; i < n; i++) {
1839ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
1840ee17db83SRichard Henderson         TCGTempVal val = TEMP_VAL_MEM;
1841ee17db83SRichard Henderson 
1842ee17db83SRichard Henderson         switch (ts->kind) {
1843c0522136SRichard Henderson         case TEMP_CONST:
1844c0522136SRichard Henderson             val = TEMP_VAL_CONST;
1845c0522136SRichard Henderson             break;
1846ee17db83SRichard Henderson         case TEMP_FIXED:
1847ee17db83SRichard Henderson             val = TEMP_VAL_REG;
1848ee17db83SRichard Henderson             break;
1849ee17db83SRichard Henderson         case TEMP_GLOBAL:
1850ee17db83SRichard Henderson             break;
1851c7482438SRichard Henderson         case TEMP_EBB:
1852ee17db83SRichard Henderson             val = TEMP_VAL_DEAD;
1853ee17db83SRichard Henderson             /* fall through */
1854f57c6915SRichard Henderson         case TEMP_TB:
1855e8996ee0Sbellard             ts->mem_allocated = 0;
1856ee17db83SRichard Henderson             break;
1857ee17db83SRichard Henderson         default:
1858ee17db83SRichard Henderson             g_assert_not_reached();
1859ee17db83SRichard Henderson         }
1860ee17db83SRichard Henderson         ts->val_type = val;
1861e8996ee0Sbellard     }
1862f8b2f202SRichard Henderson 
1863f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
1864c896fe29Sbellard }
1865c896fe29Sbellard 
1866f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
1867f8b2f202SRichard Henderson                                  TCGTemp *ts)
1868c896fe29Sbellard {
18691807f4c4SRichard Henderson     int idx = temp_idx(ts);
1870ac56dd48Spbrook 
1871ee17db83SRichard Henderson     switch (ts->kind) {
1872ee17db83SRichard Henderson     case TEMP_FIXED:
1873ee17db83SRichard Henderson     case TEMP_GLOBAL:
1874ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
1875ee17db83SRichard Henderson         break;
1876f57c6915SRichard Henderson     case TEMP_TB:
1877641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
1878ee17db83SRichard Henderson         break;
1879c7482438SRichard Henderson     case TEMP_EBB:
1880ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
1881ee17db83SRichard Henderson         break;
1882c0522136SRichard Henderson     case TEMP_CONST:
1883c0522136SRichard Henderson         switch (ts->type) {
1884c0522136SRichard Henderson         case TCG_TYPE_I32:
1885c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val);
1886c0522136SRichard Henderson             break;
1887c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32
1888c0522136SRichard Henderson         case TCG_TYPE_I64:
1889c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%" PRIx64, ts->val);
1890c0522136SRichard Henderson             break;
1891c0522136SRichard Henderson #endif
1892c0522136SRichard Henderson         case TCG_TYPE_V64:
1893c0522136SRichard Henderson         case TCG_TYPE_V128:
1894c0522136SRichard Henderson         case TCG_TYPE_V256:
1895c0522136SRichard Henderson             snprintf(buf, buf_size, "v%d$0x%" PRIx64,
1896c0522136SRichard Henderson                      64 << (ts->type - TCG_TYPE_V64), ts->val);
1897c0522136SRichard Henderson             break;
1898c0522136SRichard Henderson         default:
1899c0522136SRichard Henderson             g_assert_not_reached();
1900c0522136SRichard Henderson         }
1901c0522136SRichard Henderson         break;
1902c896fe29Sbellard     }
1903c896fe29Sbellard     return buf;
1904c896fe29Sbellard }
1905c896fe29Sbellard 
190643439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
190743439139SRichard Henderson                              int buf_size, TCGArg arg)
1908f8b2f202SRichard Henderson {
190943439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
1910f8b2f202SRichard Henderson }
1911f8b2f202SRichard Henderson 
1912f48f3edeSblueswir1 static const char * const cond_name[] =
1913f48f3edeSblueswir1 {
19140aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
19150aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
1916f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
1917f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
1918f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
1919f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
1920f48f3edeSblueswir1     [TCG_COND_LE] = "le",
1921f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
1922f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
1923f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
1924f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
1925f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
1926f48f3edeSblueswir1 };
1927f48f3edeSblueswir1 
1928f713d6adSRichard Henderson static const char * const ldst_name[] =
1929f713d6adSRichard Henderson {
1930f713d6adSRichard Henderson     [MO_UB]   = "ub",
1931f713d6adSRichard Henderson     [MO_SB]   = "sb",
1932f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
1933f713d6adSRichard Henderson     [MO_LESW] = "lesw",
1934f713d6adSRichard Henderson     [MO_LEUL] = "leul",
1935f713d6adSRichard Henderson     [MO_LESL] = "lesl",
1936fc313c64SFrédéric Pétrot     [MO_LEUQ] = "leq",
1937f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
1938f713d6adSRichard Henderson     [MO_BESW] = "besw",
1939f713d6adSRichard Henderson     [MO_BEUL] = "beul",
1940f713d6adSRichard Henderson     [MO_BESL] = "besl",
1941fc313c64SFrédéric Pétrot     [MO_BEUQ] = "beq",
1942f713d6adSRichard Henderson };
1943f713d6adSRichard Henderson 
19441f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
194552bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY
19461f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
19471f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
19481f00b27fSSergey Sorokin #else
19491f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
19501f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
19511f00b27fSSergey Sorokin #endif
19521f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
19531f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
19541f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
19551f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
19561f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
19571f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
19581f00b27fSSergey Sorokin };
19591f00b27fSSergey Sorokin 
1960587195bdSRichard Henderson static const char bswap_flag_name[][6] = {
1961587195bdSRichard Henderson     [TCG_BSWAP_IZ] = "iz",
1962587195bdSRichard Henderson     [TCG_BSWAP_OZ] = "oz",
1963587195bdSRichard Henderson     [TCG_BSWAP_OS] = "os",
1964587195bdSRichard Henderson     [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz",
1965587195bdSRichard Henderson     [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os",
1966587195bdSRichard Henderson };
1967587195bdSRichard Henderson 
1968b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
1969b016486eSRichard Henderson {
1970b016486eSRichard Henderson     return (d & (d - 1)) == 0;
1971b016486eSRichard Henderson }
1972b016486eSRichard Henderson 
1973b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
1974b016486eSRichard Henderson {
1975b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
1976b016486eSRichard Henderson         return ctz32(d);
1977b016486eSRichard Henderson     } else {
1978b016486eSRichard Henderson         return ctz64(d);
1979b016486eSRichard Henderson     }
1980b016486eSRichard Henderson }
1981b016486eSRichard Henderson 
1982b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */
1983b7a83ff8SRichard Henderson #define ne_fprintf(...) \
1984b7a83ff8SRichard Henderson     ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; })
1985b7a83ff8SRichard Henderson 
1986b7a83ff8SRichard Henderson static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
1987c896fe29Sbellard {
1988c896fe29Sbellard     char buf[128];
1989c45cb8bbSRichard Henderson     TCGOp *op;
1990c896fe29Sbellard 
199115fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
1992c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
1993c45cb8bbSRichard Henderson         const TCGOpDef *def;
1994c45cb8bbSRichard Henderson         TCGOpcode c;
1995bdfb460eSRichard Henderson         int col = 0;
1996c45cb8bbSRichard Henderson 
1997c45cb8bbSRichard Henderson         c = op->opc;
1998c896fe29Sbellard         def = &tcg_op_defs[c];
1999c45cb8bbSRichard Henderson 
2000765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
2001b016486eSRichard Henderson             nb_oargs = 0;
2002b7a83ff8SRichard Henderson             col += ne_fprintf(f, "\n ----");
20039aef40edSRichard Henderson 
20049aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
20059aef40edSRichard Henderson                 target_ulong a;
20067e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
2007efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
20087e4597d7Sbellard #else
2009efee3746SRichard Henderson                 a = op->args[i];
20107e4597d7Sbellard #endif
2011b7a83ff8SRichard Henderson                 col += ne_fprintf(f, " " TARGET_FMT_lx, a);
2012eeacee4dSBlue Swirl             }
20137e4597d7Sbellard         } else if (c == INDEX_op_call) {
20143e92aa34SRichard Henderson             const TCGHelperInfo *info = tcg_call_info(op);
2015fa52e660SRichard Henderson             void *func = tcg_call_func(op);
20163e92aa34SRichard Henderson 
2017c896fe29Sbellard             /* variable number of arguments */
2018cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2019cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2020c896fe29Sbellard             nb_cargs = def->nb_cargs;
2021b03cce8eSbellard 
2022b7a83ff8SRichard Henderson             col += ne_fprintf(f, " %s ", def->name);
20233e92aa34SRichard Henderson 
20243e92aa34SRichard Henderson             /*
20253e92aa34SRichard Henderson              * Print the function name from TCGHelperInfo, if available.
20263e92aa34SRichard Henderson              * Note that plugins have a template function for the info,
20273e92aa34SRichard Henderson              * but the actual function pointer comes from the plugin.
20283e92aa34SRichard Henderson              */
20293e92aa34SRichard Henderson             if (func == info->func) {
2030b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s", info->name);
20313e92aa34SRichard Henderson             } else {
2032b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "plugin(%p)", func);
20333e92aa34SRichard Henderson             }
20343e92aa34SRichard Henderson 
2035b7a83ff8SRichard Henderson             col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs);
2036b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
2037b7a83ff8SRichard Henderson                 col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf),
2038efee3746SRichard Henderson                                                             op->args[i]));
2039b03cce8eSbellard             }
2040cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
2041efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
204239004a71SRichard Henderson                 const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
2043b7a83ff8SRichard Henderson                 col += ne_fprintf(f, ",%s", t);
2044e8996ee0Sbellard             }
2045b03cce8eSbellard         } else {
2046b7a83ff8SRichard Henderson             col += ne_fprintf(f, " %s ", def->name);
2047c45cb8bbSRichard Henderson 
2048c896fe29Sbellard             nb_oargs = def->nb_oargs;
2049c896fe29Sbellard             nb_iargs = def->nb_iargs;
2050c896fe29Sbellard             nb_cargs = def->nb_cargs;
2051c896fe29Sbellard 
2052d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
2053b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "v%d,e%d,", 64 << TCGOP_VECL(op),
2054d2fd745fSRichard Henderson                                   8 << TCGOP_VECE(op));
2055d2fd745fSRichard Henderson             }
2056d2fd745fSRichard Henderson 
2057c896fe29Sbellard             k = 0;
2058c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
2059b7a83ff8SRichard Henderson                 const char *sep =  k ? "," : "";
2060b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s%s", sep,
2061b7a83ff8SRichard Henderson                                   tcg_get_arg_str(s, buf, sizeof(buf),
2062efee3746SRichard Henderson                                                   op->args[k++]));
2063c896fe29Sbellard             }
2064c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
2065b7a83ff8SRichard Henderson                 const char *sep =  k ? "," : "";
2066b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s%s", sep,
2067b7a83ff8SRichard Henderson                                   tcg_get_arg_str(s, buf, sizeof(buf),
2068efee3746SRichard Henderson                                                   op->args[k++]));
2069c896fe29Sbellard             }
2070be210acbSRichard Henderson             switch (c) {
2071be210acbSRichard Henderson             case INDEX_op_brcond_i32:
2072ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
2073ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
2074be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
2075be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
2076ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
2077be210acbSRichard Henderson             case INDEX_op_setcond_i64:
2078ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
2079212be173SRichard Henderson             case INDEX_op_cmp_vec:
2080f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
2081efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
2082efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
2083b7a83ff8SRichard Henderson                     col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]);
2084eeacee4dSBlue Swirl                 } else {
2085b7a83ff8SRichard Henderson                     col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]);
2086eeacee4dSBlue Swirl                 }
2087f48f3edeSblueswir1                 i = 1;
2088be210acbSRichard Henderson                 break;
2089f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
2090f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
209107ce0b05SRichard Henderson             case INDEX_op_qemu_st8_i32:
2092f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
2093f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
209459227d5dSRichard Henderson                 {
20959002ffcbSRichard Henderson                     MemOpIdx oi = op->args[k++];
209614776ab5STony Nguyen                     MemOp op = get_memop(oi);
209759227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
209859227d5dSRichard Henderson 
209959c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
2100b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",$0x%x,%u", op, ix);
210159c4b7e8SRichard Henderson                     } else {
21021f00b27fSSergey Sorokin                         const char *s_al, *s_op;
21031f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
210459c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
2105b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",%s%s,%u", s_al, s_op, ix);
2106f713d6adSRichard Henderson                     }
2107f713d6adSRichard Henderson                     i = 1;
210859227d5dSRichard Henderson                 }
2109f713d6adSRichard Henderson                 break;
2110587195bdSRichard Henderson             case INDEX_op_bswap16_i32:
2111587195bdSRichard Henderson             case INDEX_op_bswap16_i64:
2112587195bdSRichard Henderson             case INDEX_op_bswap32_i32:
2113587195bdSRichard Henderson             case INDEX_op_bswap32_i64:
2114587195bdSRichard Henderson             case INDEX_op_bswap64_i64:
2115587195bdSRichard Henderson                 {
2116587195bdSRichard Henderson                     TCGArg flags = op->args[k];
2117587195bdSRichard Henderson                     const char *name = NULL;
2118587195bdSRichard Henderson 
2119587195bdSRichard Henderson                     if (flags < ARRAY_SIZE(bswap_flag_name)) {
2120587195bdSRichard Henderson                         name = bswap_flag_name[flags];
2121587195bdSRichard Henderson                     }
2122587195bdSRichard Henderson                     if (name) {
2123b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",%s", name);
2124587195bdSRichard Henderson                     } else {
2125b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags);
2126587195bdSRichard Henderson                     }
2127587195bdSRichard Henderson                     i = k = 1;
2128587195bdSRichard Henderson                 }
2129587195bdSRichard Henderson                 break;
2130be210acbSRichard Henderson             default:
2131f48f3edeSblueswir1                 i = 0;
2132be210acbSRichard Henderson                 break;
2133be210acbSRichard Henderson             }
213451e3972cSRichard Henderson             switch (c) {
213551e3972cSRichard Henderson             case INDEX_op_set_label:
213651e3972cSRichard Henderson             case INDEX_op_br:
213751e3972cSRichard Henderson             case INDEX_op_brcond_i32:
213851e3972cSRichard Henderson             case INDEX_op_brcond_i64:
213951e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2140b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s$L%d", k ? "," : "",
2141efee3746SRichard Henderson                                   arg_label(op->args[k])->id);
214251e3972cSRichard Henderson                 i++, k++;
214351e3972cSRichard Henderson                 break;
21443470867bSRichard Henderson             case INDEX_op_mb:
21453470867bSRichard Henderson                 {
21463470867bSRichard Henderson                     TCGBar membar = op->args[k];
21473470867bSRichard Henderson                     const char *b_op, *m_op;
21483470867bSRichard Henderson 
21493470867bSRichard Henderson                     switch (membar & TCG_BAR_SC) {
21503470867bSRichard Henderson                     case 0:
21513470867bSRichard Henderson                         b_op = "none";
21523470867bSRichard Henderson                         break;
21533470867bSRichard Henderson                     case TCG_BAR_LDAQ:
21543470867bSRichard Henderson                         b_op = "acq";
21553470867bSRichard Henderson                         break;
21563470867bSRichard Henderson                     case TCG_BAR_STRL:
21573470867bSRichard Henderson                         b_op = "rel";
21583470867bSRichard Henderson                         break;
21593470867bSRichard Henderson                     case TCG_BAR_SC:
21603470867bSRichard Henderson                         b_op = "seq";
21613470867bSRichard Henderson                         break;
21623470867bSRichard Henderson                     default:
21633470867bSRichard Henderson                         g_assert_not_reached();
21643470867bSRichard Henderson                     }
21653470867bSRichard Henderson 
21663470867bSRichard Henderson                     switch (membar & TCG_MO_ALL) {
21673470867bSRichard Henderson                     case 0:
21683470867bSRichard Henderson                         m_op = "none";
21693470867bSRichard Henderson                         break;
21703470867bSRichard Henderson                     case TCG_MO_LD_LD:
21713470867bSRichard Henderson                         m_op = "rr";
21723470867bSRichard Henderson                         break;
21733470867bSRichard Henderson                     case TCG_MO_LD_ST:
21743470867bSRichard Henderson                         m_op = "rw";
21753470867bSRichard Henderson                         break;
21763470867bSRichard Henderson                     case TCG_MO_ST_LD:
21773470867bSRichard Henderson                         m_op = "wr";
21783470867bSRichard Henderson                         break;
21793470867bSRichard Henderson                     case TCG_MO_ST_ST:
21803470867bSRichard Henderson                         m_op = "ww";
21813470867bSRichard Henderson                         break;
21823470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_LD_ST:
21833470867bSRichard Henderson                         m_op = "rr+rw";
21843470867bSRichard Henderson                         break;
21853470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_ST_LD:
21863470867bSRichard Henderson                         m_op = "rr+wr";
21873470867bSRichard Henderson                         break;
21883470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_ST_ST:
21893470867bSRichard Henderson                         m_op = "rr+ww";
21903470867bSRichard Henderson                         break;
21913470867bSRichard Henderson                     case TCG_MO_LD_ST | TCG_MO_ST_LD:
21923470867bSRichard Henderson                         m_op = "rw+wr";
21933470867bSRichard Henderson                         break;
21943470867bSRichard Henderson                     case TCG_MO_LD_ST | TCG_MO_ST_ST:
21953470867bSRichard Henderson                         m_op = "rw+ww";
21963470867bSRichard Henderson                         break;
21973470867bSRichard Henderson                     case TCG_MO_ST_LD | TCG_MO_ST_ST:
21983470867bSRichard Henderson                         m_op = "wr+ww";
21993470867bSRichard Henderson                         break;
22003470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_LD:
22013470867bSRichard Henderson                         m_op = "rr+rw+wr";
22023470867bSRichard Henderson                         break;
22033470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST:
22043470867bSRichard Henderson                         m_op = "rr+rw+ww";
22053470867bSRichard Henderson                         break;
22063470867bSRichard Henderson                     case TCG_MO_LD_LD | TCG_MO_ST_LD | TCG_MO_ST_ST:
22073470867bSRichard Henderson                         m_op = "rr+wr+ww";
22083470867bSRichard Henderson                         break;
22093470867bSRichard Henderson                     case TCG_MO_LD_ST | TCG_MO_ST_LD | TCG_MO_ST_ST:
22103470867bSRichard Henderson                         m_op = "rw+wr+ww";
22113470867bSRichard Henderson                         break;
22123470867bSRichard Henderson                     case TCG_MO_ALL:
22133470867bSRichard Henderson                         m_op = "all";
22143470867bSRichard Henderson                         break;
22153470867bSRichard Henderson                     default:
22163470867bSRichard Henderson                         g_assert_not_reached();
22173470867bSRichard Henderson                     }
22183470867bSRichard Henderson 
22193470867bSRichard Henderson                     col += ne_fprintf(f, "%s%s:%s", (k ? "," : ""), b_op, m_op);
22203470867bSRichard Henderson                     i++, k++;
22213470867bSRichard Henderson                 }
22223470867bSRichard Henderson                 break;
222351e3972cSRichard Henderson             default:
222451e3972cSRichard Henderson                 break;
2225eeacee4dSBlue Swirl             }
222651e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
2227b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "",
2228b7a83ff8SRichard Henderson                                   op->args[k]);
2229bdfb460eSRichard Henderson             }
2230bdfb460eSRichard Henderson         }
2231bdfb460eSRichard Henderson 
22321894f69aSRichard Henderson         if (have_prefs || op->life) {
22331894f69aSRichard Henderson             for (; col < 40; ++col) {
2234b7a83ff8SRichard Henderson                 putc(' ', f);
2235bdfb460eSRichard Henderson             }
22361894f69aSRichard Henderson         }
22371894f69aSRichard Henderson 
22381894f69aSRichard Henderson         if (op->life) {
22391894f69aSRichard Henderson             unsigned life = op->life;
2240bdfb460eSRichard Henderson 
2241bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
2242b7a83ff8SRichard Henderson                 ne_fprintf(f, "  sync:");
2243bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
2244bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
2245b7a83ff8SRichard Henderson                         ne_fprintf(f, " %d", i);
2246bdfb460eSRichard Henderson                     }
2247bdfb460eSRichard Henderson                 }
2248bdfb460eSRichard Henderson             }
2249bdfb460eSRichard Henderson             life /= DEAD_ARG;
2250bdfb460eSRichard Henderson             if (life) {
2251b7a83ff8SRichard Henderson                 ne_fprintf(f, "  dead:");
2252bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
2253bdfb460eSRichard Henderson                     if (life & 1) {
2254b7a83ff8SRichard Henderson                         ne_fprintf(f, " %d", i);
2255bdfb460eSRichard Henderson                     }
2256bdfb460eSRichard Henderson                 }
2257c896fe29Sbellard             }
2258b03cce8eSbellard         }
22591894f69aSRichard Henderson 
22601894f69aSRichard Henderson         if (have_prefs) {
22611894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
226231fd884bSRichard Henderson                 TCGRegSet set = output_pref(op, i);
22631894f69aSRichard Henderson 
22641894f69aSRichard Henderson                 if (i == 0) {
2265b7a83ff8SRichard Henderson                     ne_fprintf(f, "  pref=");
22661894f69aSRichard Henderson                 } else {
2267b7a83ff8SRichard Henderson                     ne_fprintf(f, ",");
22681894f69aSRichard Henderson                 }
22691894f69aSRichard Henderson                 if (set == 0) {
2270b7a83ff8SRichard Henderson                     ne_fprintf(f, "none");
22711894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
2272b7a83ff8SRichard Henderson                     ne_fprintf(f, "all");
22731894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
22741894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
22751894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
2276b7a83ff8SRichard Henderson                     ne_fprintf(f, "%s", tcg_target_reg_names[reg]);
22771894f69aSRichard Henderson #endif
22781894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
2279b7a83ff8SRichard Henderson                     ne_fprintf(f, "0x%x", (uint32_t)set);
22801894f69aSRichard Henderson                 } else {
2281b7a83ff8SRichard Henderson                     ne_fprintf(f, "0x%" PRIx64, (uint64_t)set);
22821894f69aSRichard Henderson                 }
22831894f69aSRichard Henderson             }
22841894f69aSRichard Henderson         }
22851894f69aSRichard Henderson 
2286b7a83ff8SRichard Henderson         putc('\n', f);
2287c896fe29Sbellard     }
2288c896fe29Sbellard }
2289c896fe29Sbellard 
2290c896fe29Sbellard /* we give more priority to constraints with less registers */
2291c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2292c896fe29Sbellard {
229374a11790SRichard Henderson     const TCGArgConstraint *arg_ct = &def->args_ct[k];
229429f5e925SRichard Henderson     int n = ctpop64(arg_ct->regs);
2295c896fe29Sbellard 
229629f5e925SRichard Henderson     /*
229729f5e925SRichard Henderson      * Sort constraints of a single register first, which includes output
229829f5e925SRichard Henderson      * aliases (which must exactly match the input already allocated).
229929f5e925SRichard Henderson      */
230029f5e925SRichard Henderson     if (n == 1 || arg_ct->oalias) {
230129f5e925SRichard Henderson         return INT_MAX;
2302c896fe29Sbellard     }
230329f5e925SRichard Henderson 
230429f5e925SRichard Henderson     /*
230529f5e925SRichard Henderson      * Sort register pairs next, first then second immediately after.
230629f5e925SRichard Henderson      * Arbitrarily sort multiple pairs by the index of the first reg;
230729f5e925SRichard Henderson      * there shouldn't be many pairs.
230829f5e925SRichard Henderson      */
230929f5e925SRichard Henderson     switch (arg_ct->pair) {
231029f5e925SRichard Henderson     case 1:
231129f5e925SRichard Henderson     case 3:
231229f5e925SRichard Henderson         return (k + 1) * 2;
231329f5e925SRichard Henderson     case 2:
231429f5e925SRichard Henderson         return (arg_ct->pair_index + 1) * 2 - 1;
231529f5e925SRichard Henderson     }
231629f5e925SRichard Henderson 
231729f5e925SRichard Henderson     /* Finally, sort by decreasing register count. */
231829f5e925SRichard Henderson     assert(n > 1);
231929f5e925SRichard Henderson     return -n;
2320c896fe29Sbellard }
2321c896fe29Sbellard 
2322c896fe29Sbellard /* sort from highest priority to lowest */
2323c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2324c896fe29Sbellard {
232566792f90SRichard Henderson     int i, j;
232666792f90SRichard Henderson     TCGArgConstraint *a = def->args_ct;
2327c896fe29Sbellard 
232866792f90SRichard Henderson     for (i = 0; i < n; i++) {
232966792f90SRichard Henderson         a[start + i].sort_index = start + i;
233066792f90SRichard Henderson     }
233166792f90SRichard Henderson     if (n <= 1) {
2332c896fe29Sbellard         return;
233366792f90SRichard Henderson     }
2334c896fe29Sbellard     for (i = 0; i < n - 1; i++) {
2335c896fe29Sbellard         for (j = i + 1; j < n; j++) {
233666792f90SRichard Henderson             int p1 = get_constraint_priority(def, a[start + i].sort_index);
233766792f90SRichard Henderson             int p2 = get_constraint_priority(def, a[start + j].sort_index);
2338c896fe29Sbellard             if (p1 < p2) {
233966792f90SRichard Henderson                 int tmp = a[start + i].sort_index;
234066792f90SRichard Henderson                 a[start + i].sort_index = a[start + j].sort_index;
234166792f90SRichard Henderson                 a[start + j].sort_index = tmp;
2342c896fe29Sbellard             }
2343c896fe29Sbellard         }
2344c896fe29Sbellard     }
2345c896fe29Sbellard }
2346c896fe29Sbellard 
2347f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2348c896fe29Sbellard {
2349a9751609SRichard Henderson     TCGOpcode op;
2350c896fe29Sbellard 
2351f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
2352f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
2353f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
235429f5e925SRichard Henderson         bool saw_alias_pair = false;
235529f5e925SRichard Henderson         int i, o, i2, o2, nb_args;
2356f69d277eSRichard Henderson 
2357f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
2358f69d277eSRichard Henderson             continue;
2359f69d277eSRichard Henderson         }
2360f69d277eSRichard Henderson 
2361c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
2362f69d277eSRichard Henderson         if (nb_args == 0) {
2363f69d277eSRichard Henderson             continue;
2364f69d277eSRichard Henderson         }
2365f69d277eSRichard Henderson 
23664c22e840SRichard Henderson         /*
23674c22e840SRichard Henderson          * Macro magic should make it impossible, but double-check that
23684c22e840SRichard Henderson          * the array index is in range.  Since the signness of an enum
23694c22e840SRichard Henderson          * is implementation defined, force the result to unsigned.
23704c22e840SRichard Henderson          */
23714c22e840SRichard Henderson         unsigned con_set = tcg_target_op_def(op);
23724c22e840SRichard Henderson         tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets));
23734c22e840SRichard Henderson         tdefs = &constraint_sets[con_set];
2374f69d277eSRichard Henderson 
2375c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2376f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
23778940ea0dSPhilippe Mathieu-Daudé             bool input_p = i >= def->nb_oargs;
23788940ea0dSPhilippe Mathieu-Daudé 
2379f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2380eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2381f69d277eSRichard Henderson 
238217280ff4SRichard Henderson             switch (*ct_str) {
238317280ff4SRichard Henderson             case '0' ... '9':
23848940ea0dSPhilippe Mathieu-Daudé                 o = *ct_str - '0';
23858940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(input_p);
23868940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(o < def->nb_oargs);
23878940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(def->args_ct[o].regs != 0);
23888940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(!def->args_ct[o].oalias);
23898940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i] = def->args_ct[o];
2390bc2b17e6SRichard Henderson                 /* The output sets oalias.  */
23918940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[o].oalias = 1;
23928940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[o].alias_index = i;
2393bc2b17e6SRichard Henderson                 /* The input sets ialias. */
23948940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i].ialias = 1;
23958940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i].alias_index = o;
239629f5e925SRichard Henderson                 if (def->args_ct[i].pair) {
239729f5e925SRichard Henderson                     saw_alias_pair = true;
239829f5e925SRichard Henderson                 }
23998940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(ct_str[1] == '\0');
24008940ea0dSPhilippe Mathieu-Daudé                 continue;
24018940ea0dSPhilippe Mathieu-Daudé 
240282790a87SRichard Henderson             case '&':
24038940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(!input_p);
2404bc2b17e6SRichard Henderson                 def->args_ct[i].newreg = true;
240582790a87SRichard Henderson                 ct_str++;
240682790a87SRichard Henderson                 break;
240729f5e925SRichard Henderson 
240829f5e925SRichard Henderson             case 'p': /* plus */
240929f5e925SRichard Henderson                 /* Allocate to the register after the previous. */
241029f5e925SRichard Henderson                 tcg_debug_assert(i > (input_p ? def->nb_oargs : 0));
241129f5e925SRichard Henderson                 o = i - 1;
241229f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].pair);
241329f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].ct);
241429f5e925SRichard Henderson                 def->args_ct[i] = (TCGArgConstraint){
241529f5e925SRichard Henderson                     .pair = 2,
241629f5e925SRichard Henderson                     .pair_index = o,
241729f5e925SRichard Henderson                     .regs = def->args_ct[o].regs << 1,
241829f5e925SRichard Henderson                 };
241929f5e925SRichard Henderson                 def->args_ct[o].pair = 1;
242029f5e925SRichard Henderson                 def->args_ct[o].pair_index = i;
242129f5e925SRichard Henderson                 tcg_debug_assert(ct_str[1] == '\0');
242229f5e925SRichard Henderson                 continue;
242329f5e925SRichard Henderson 
242429f5e925SRichard Henderson             case 'm': /* minus */
242529f5e925SRichard Henderson                 /* Allocate to the register before the previous. */
242629f5e925SRichard Henderson                 tcg_debug_assert(i > (input_p ? def->nb_oargs : 0));
242729f5e925SRichard Henderson                 o = i - 1;
242829f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].pair);
242929f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].ct);
243029f5e925SRichard Henderson                 def->args_ct[i] = (TCGArgConstraint){
243129f5e925SRichard Henderson                     .pair = 1,
243229f5e925SRichard Henderson                     .pair_index = o,
243329f5e925SRichard Henderson                     .regs = def->args_ct[o].regs >> 1,
243429f5e925SRichard Henderson                 };
243529f5e925SRichard Henderson                 def->args_ct[o].pair = 2;
243629f5e925SRichard Henderson                 def->args_ct[o].pair_index = i;
243729f5e925SRichard Henderson                 tcg_debug_assert(ct_str[1] == '\0');
243829f5e925SRichard Henderson                 continue;
24398940ea0dSPhilippe Mathieu-Daudé             }
24408940ea0dSPhilippe Mathieu-Daudé 
24418940ea0dSPhilippe Mathieu-Daudé             do {
24428940ea0dSPhilippe Mathieu-Daudé                 switch (*ct_str) {
2443c896fe29Sbellard                 case 'i':
2444c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2445c896fe29Sbellard                     break;
2446358b4923SRichard Henderson 
2447358b4923SRichard Henderson                 /* Include all of the target-specific constraints. */
2448358b4923SRichard Henderson 
2449358b4923SRichard Henderson #undef CONST
2450358b4923SRichard Henderson #define CONST(CASE, MASK) \
24518940ea0dSPhilippe Mathieu-Daudé     case CASE: def->args_ct[i].ct |= MASK; break;
2452358b4923SRichard Henderson #define REGS(CASE, MASK) \
24538940ea0dSPhilippe Mathieu-Daudé     case CASE: def->args_ct[i].regs |= MASK; break;
2454358b4923SRichard Henderson 
2455358b4923SRichard Henderson #include "tcg-target-con-str.h"
2456358b4923SRichard Henderson 
2457358b4923SRichard Henderson #undef REGS
2458358b4923SRichard Henderson #undef CONST
2459c896fe29Sbellard                 default:
24608940ea0dSPhilippe Mathieu-Daudé                 case '0' ... '9':
24618940ea0dSPhilippe Mathieu-Daudé                 case '&':
246229f5e925SRichard Henderson                 case 'p':
246329f5e925SRichard Henderson                 case 'm':
2464358b4923SRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2465358b4923SRichard Henderson                     g_assert_not_reached();
2466358b4923SRichard Henderson                 }
24678940ea0dSPhilippe Mathieu-Daudé             } while (*++ct_str != '\0');
2468c896fe29Sbellard         }
2469c896fe29Sbellard 
2470c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2471eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2472c68aaa18SStefan Weil 
247329f5e925SRichard Henderson         /*
247429f5e925SRichard Henderson          * Fix up output pairs that are aliased with inputs.
247529f5e925SRichard Henderson          * When we created the alias, we copied pair from the output.
247629f5e925SRichard Henderson          * There are three cases:
247729f5e925SRichard Henderson          *    (1a) Pairs of inputs alias pairs of outputs.
247829f5e925SRichard Henderson          *    (1b) One input aliases the first of a pair of outputs.
247929f5e925SRichard Henderson          *    (2)  One input aliases the second of a pair of outputs.
248029f5e925SRichard Henderson          *
248129f5e925SRichard Henderson          * Case 1a is handled by making sure that the pair_index'es are
248229f5e925SRichard Henderson          * properly updated so that they appear the same as a pair of inputs.
248329f5e925SRichard Henderson          *
248429f5e925SRichard Henderson          * Case 1b is handled by setting the pair_index of the input to
248529f5e925SRichard Henderson          * itself, simply so it doesn't point to an unrelated argument.
248629f5e925SRichard Henderson          * Since we don't encounter the "second" during the input allocation
248729f5e925SRichard Henderson          * phase, nothing happens with the second half of the input pair.
248829f5e925SRichard Henderson          *
248929f5e925SRichard Henderson          * Case 2 is handled by setting the second input to pair=3, the
249029f5e925SRichard Henderson          * first output to pair=3, and the pair_index'es to match.
249129f5e925SRichard Henderson          */
249229f5e925SRichard Henderson         if (saw_alias_pair) {
249329f5e925SRichard Henderson             for (i = def->nb_oargs; i < nb_args; i++) {
249429f5e925SRichard Henderson                 /*
249529f5e925SRichard Henderson                  * Since [0-9pm] must be alone in the constraint string,
249629f5e925SRichard Henderson                  * the only way they can both be set is if the pair comes
249729f5e925SRichard Henderson                  * from the output alias.
249829f5e925SRichard Henderson                  */
249929f5e925SRichard Henderson                 if (!def->args_ct[i].ialias) {
250029f5e925SRichard Henderson                     continue;
250129f5e925SRichard Henderson                 }
250229f5e925SRichard Henderson                 switch (def->args_ct[i].pair) {
250329f5e925SRichard Henderson                 case 0:
250429f5e925SRichard Henderson                     break;
250529f5e925SRichard Henderson                 case 1:
250629f5e925SRichard Henderson                     o = def->args_ct[i].alias_index;
250729f5e925SRichard Henderson                     o2 = def->args_ct[o].pair_index;
250829f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o].pair == 1);
250929f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o2].pair == 2);
251029f5e925SRichard Henderson                     if (def->args_ct[o2].oalias) {
251129f5e925SRichard Henderson                         /* Case 1a */
251229f5e925SRichard Henderson                         i2 = def->args_ct[o2].alias_index;
251329f5e925SRichard Henderson                         tcg_debug_assert(def->args_ct[i2].pair == 2);
251429f5e925SRichard Henderson                         def->args_ct[i2].pair_index = i;
251529f5e925SRichard Henderson                         def->args_ct[i].pair_index = i2;
251629f5e925SRichard Henderson                     } else {
251729f5e925SRichard Henderson                         /* Case 1b */
251829f5e925SRichard Henderson                         def->args_ct[i].pair_index = i;
251929f5e925SRichard Henderson                     }
252029f5e925SRichard Henderson                     break;
252129f5e925SRichard Henderson                 case 2:
252229f5e925SRichard Henderson                     o = def->args_ct[i].alias_index;
252329f5e925SRichard Henderson                     o2 = def->args_ct[o].pair_index;
252429f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o].pair == 2);
252529f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o2].pair == 1);
252629f5e925SRichard Henderson                     if (def->args_ct[o2].oalias) {
252729f5e925SRichard Henderson                         /* Case 1a */
252829f5e925SRichard Henderson                         i2 = def->args_ct[o2].alias_index;
252929f5e925SRichard Henderson                         tcg_debug_assert(def->args_ct[i2].pair == 1);
253029f5e925SRichard Henderson                         def->args_ct[i2].pair_index = i;
253129f5e925SRichard Henderson                         def->args_ct[i].pair_index = i2;
253229f5e925SRichard Henderson                     } else {
253329f5e925SRichard Henderson                         /* Case 2 */
253429f5e925SRichard Henderson                         def->args_ct[i].pair = 3;
253529f5e925SRichard Henderson                         def->args_ct[o2].pair = 3;
253629f5e925SRichard Henderson                         def->args_ct[i].pair_index = o2;
253729f5e925SRichard Henderson                         def->args_ct[o2].pair_index = i;
253829f5e925SRichard Henderson                     }
253929f5e925SRichard Henderson                     break;
254029f5e925SRichard Henderson                 default:
254129f5e925SRichard Henderson                     g_assert_not_reached();
254229f5e925SRichard Henderson                 }
254329f5e925SRichard Henderson             }
254429f5e925SRichard Henderson         }
254529f5e925SRichard Henderson 
2546c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
2547c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
2548c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
2549c896fe29Sbellard     }
2550c896fe29Sbellard }
2551c896fe29Sbellard 
2552f85b1fc4SRichard Henderson static void remove_label_use(TCGOp *op, int idx)
2553f85b1fc4SRichard Henderson {
2554f85b1fc4SRichard Henderson     TCGLabel *label = arg_label(op->args[idx]);
2555f85b1fc4SRichard Henderson     TCGLabelUse *use;
2556f85b1fc4SRichard Henderson 
2557f85b1fc4SRichard Henderson     QSIMPLEQ_FOREACH(use, &label->branches, next) {
2558f85b1fc4SRichard Henderson         if (use->op == op) {
2559f85b1fc4SRichard Henderson             QSIMPLEQ_REMOVE(&label->branches, use, TCGLabelUse, next);
2560f85b1fc4SRichard Henderson             return;
2561f85b1fc4SRichard Henderson         }
2562f85b1fc4SRichard Henderson     }
2563f85b1fc4SRichard Henderson     g_assert_not_reached();
2564f85b1fc4SRichard Henderson }
2565f85b1fc4SRichard Henderson 
25660c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
25670c627cdcSRichard Henderson {
2568d88a117eSRichard Henderson     switch (op->opc) {
2569d88a117eSRichard Henderson     case INDEX_op_br:
2570f85b1fc4SRichard Henderson         remove_label_use(op, 0);
2571d88a117eSRichard Henderson         break;
2572d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
2573d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
2574f85b1fc4SRichard Henderson         remove_label_use(op, 3);
2575d88a117eSRichard Henderson         break;
2576d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
2577f85b1fc4SRichard Henderson         remove_label_use(op, 5);
2578d88a117eSRichard Henderson         break;
2579d88a117eSRichard Henderson     default:
2580d88a117eSRichard Henderson         break;
2581d88a117eSRichard Henderson     }
2582d88a117eSRichard Henderson 
258315fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
258415fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
2585abebf925SRichard Henderson     s->nb_ops--;
25860c627cdcSRichard Henderson 
25870c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
2588d73415a3SStefan Hajnoczi     qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
25890c627cdcSRichard Henderson #endif
25900c627cdcSRichard Henderson }
25910c627cdcSRichard Henderson 
2592a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op)
2593a80cdd31SRichard Henderson {
2594a80cdd31SRichard Henderson     TCGContext *s = tcg_ctx;
2595a80cdd31SRichard Henderson 
2596a80cdd31SRichard Henderson     while (true) {
2597a80cdd31SRichard Henderson         TCGOp *last = tcg_last_op();
2598a80cdd31SRichard Henderson         if (last == op) {
2599a80cdd31SRichard Henderson             return;
2600a80cdd31SRichard Henderson         }
2601a80cdd31SRichard Henderson         tcg_op_remove(s, last);
2602a80cdd31SRichard Henderson     }
2603a80cdd31SRichard Henderson }
2604a80cdd31SRichard Henderson 
2605d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs)
260615fa08f8SRichard Henderson {
260715fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
2608cb10bc63SRichard Henderson     TCGOp *op = NULL;
260915fa08f8SRichard Henderson 
2610cb10bc63SRichard Henderson     if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) {
2611cb10bc63SRichard Henderson         QTAILQ_FOREACH(op, &s->free_ops, link) {
2612cb10bc63SRichard Henderson             if (nargs <= op->nargs) {
261315fa08f8SRichard Henderson                 QTAILQ_REMOVE(&s->free_ops, op, link);
2614cb10bc63SRichard Henderson                 nargs = op->nargs;
2615cb10bc63SRichard Henderson                 goto found;
261615fa08f8SRichard Henderson             }
2617cb10bc63SRichard Henderson         }
2618cb10bc63SRichard Henderson     }
2619cb10bc63SRichard Henderson 
2620cb10bc63SRichard Henderson     /* Most opcodes have 3 or 4 operands: reduce fragmentation. */
2621cb10bc63SRichard Henderson     nargs = MAX(4, nargs);
2622cb10bc63SRichard Henderson     op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs);
2623cb10bc63SRichard Henderson 
2624cb10bc63SRichard Henderson  found:
262515fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
262615fa08f8SRichard Henderson     op->opc = opc;
2627cb10bc63SRichard Henderson     op->nargs = nargs;
262815fa08f8SRichard Henderson 
2629cb10bc63SRichard Henderson     /* Check for bitfield overflow. */
2630cb10bc63SRichard Henderson     tcg_debug_assert(op->nargs == nargs);
2631cb10bc63SRichard Henderson 
2632cb10bc63SRichard Henderson     s->nb_ops++;
263315fa08f8SRichard Henderson     return op;
263415fa08f8SRichard Henderson }
263515fa08f8SRichard Henderson 
2636d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs)
263715fa08f8SRichard Henderson {
2638d4478943SPhilippe Mathieu-Daudé     TCGOp *op = tcg_op_alloc(opc, nargs);
263915fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
264015fa08f8SRichard Henderson     return op;
264115fa08f8SRichard Henderson }
264215fa08f8SRichard Henderson 
2643d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op,
2644d4478943SPhilippe Mathieu-Daudé                             TCGOpcode opc, unsigned nargs)
26455a18407fSRichard Henderson {
2646d4478943SPhilippe Mathieu-Daudé     TCGOp *new_op = tcg_op_alloc(opc, nargs);
264715fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
26485a18407fSRichard Henderson     return new_op;
26495a18407fSRichard Henderson }
26505a18407fSRichard Henderson 
2651d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op,
2652d4478943SPhilippe Mathieu-Daudé                            TCGOpcode opc, unsigned nargs)
26535a18407fSRichard Henderson {
2654d4478943SPhilippe Mathieu-Daudé     TCGOp *new_op = tcg_op_alloc(opc, nargs);
265515fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
26565a18407fSRichard Henderson     return new_op;
26575a18407fSRichard Henderson }
26585a18407fSRichard Henderson 
2659968f305eSRichard Henderson static void move_label_uses(TCGLabel *to, TCGLabel *from)
2660968f305eSRichard Henderson {
2661968f305eSRichard Henderson     TCGLabelUse *u;
2662968f305eSRichard Henderson 
2663968f305eSRichard Henderson     QSIMPLEQ_FOREACH(u, &from->branches, next) {
2664968f305eSRichard Henderson         TCGOp *op = u->op;
2665968f305eSRichard Henderson         switch (op->opc) {
2666968f305eSRichard Henderson         case INDEX_op_br:
2667968f305eSRichard Henderson             op->args[0] = label_arg(to);
2668968f305eSRichard Henderson             break;
2669968f305eSRichard Henderson         case INDEX_op_brcond_i32:
2670968f305eSRichard Henderson         case INDEX_op_brcond_i64:
2671968f305eSRichard Henderson             op->args[3] = label_arg(to);
2672968f305eSRichard Henderson             break;
2673968f305eSRichard Henderson         case INDEX_op_brcond2_i32:
2674968f305eSRichard Henderson             op->args[5] = label_arg(to);
2675968f305eSRichard Henderson             break;
2676968f305eSRichard Henderson         default:
2677968f305eSRichard Henderson             g_assert_not_reached();
2678968f305eSRichard Henderson         }
2679968f305eSRichard Henderson     }
2680968f305eSRichard Henderson 
2681968f305eSRichard Henderson     QSIMPLEQ_CONCAT(&to->branches, &from->branches);
2682968f305eSRichard Henderson }
2683968f305eSRichard Henderson 
2684b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
26859bbee4c0SRichard Henderson static void __attribute__((noinline))
26869bbee4c0SRichard Henderson reachable_code_pass(TCGContext *s)
2687b4fc67c7SRichard Henderson {
26884d89d0bbSRichard Henderson     TCGOp *op, *op_next, *op_prev;
2689b4fc67c7SRichard Henderson     bool dead = false;
2690b4fc67c7SRichard Henderson 
2691b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
2692b4fc67c7SRichard Henderson         bool remove = dead;
2693b4fc67c7SRichard Henderson         TCGLabel *label;
2694b4fc67c7SRichard Henderson 
2695b4fc67c7SRichard Henderson         switch (op->opc) {
2696b4fc67c7SRichard Henderson         case INDEX_op_set_label:
2697b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
26984d89d0bbSRichard Henderson 
26994d89d0bbSRichard Henderson             /*
2700968f305eSRichard Henderson              * Note that the first op in the TB is always a load,
2701968f305eSRichard Henderson              * so there is always something before a label.
2702968f305eSRichard Henderson              */
2703968f305eSRichard Henderson             op_prev = QTAILQ_PREV(op, link);
2704968f305eSRichard Henderson 
2705968f305eSRichard Henderson             /*
2706968f305eSRichard Henderson              * If we find two sequential labels, move all branches to
2707968f305eSRichard Henderson              * reference the second label and remove the first label.
2708968f305eSRichard Henderson              * Do this before branch to next optimization, so that the
2709968f305eSRichard Henderson              * middle label is out of the way.
2710968f305eSRichard Henderson              */
2711968f305eSRichard Henderson             if (op_prev->opc == INDEX_op_set_label) {
2712968f305eSRichard Henderson                 move_label_uses(label, arg_label(op_prev->args[0]));
2713968f305eSRichard Henderson                 tcg_op_remove(s, op_prev);
2714968f305eSRichard Henderson                 op_prev = QTAILQ_PREV(op, link);
2715968f305eSRichard Henderson             }
2716968f305eSRichard Henderson 
2717968f305eSRichard Henderson             /*
27184d89d0bbSRichard Henderson              * Optimization can fold conditional branches to unconditional.
27194d89d0bbSRichard Henderson              * If we find a label which is preceded by an unconditional
27204d89d0bbSRichard Henderson              * branch to next, remove the branch.  We couldn't do this when
27214d89d0bbSRichard Henderson              * processing the branch because any dead code between the branch
27224d89d0bbSRichard Henderson              * and label had not yet been removed.
27234d89d0bbSRichard Henderson              */
27244d89d0bbSRichard Henderson             if (op_prev->opc == INDEX_op_br &&
27254d89d0bbSRichard Henderson                 label == arg_label(op_prev->args[0])) {
27264d89d0bbSRichard Henderson                 tcg_op_remove(s, op_prev);
27274d89d0bbSRichard Henderson                 /* Fall through means insns become live again.  */
27284d89d0bbSRichard Henderson                 dead = false;
27294d89d0bbSRichard Henderson             }
27304d89d0bbSRichard Henderson 
2731f85b1fc4SRichard Henderson             if (QSIMPLEQ_EMPTY(&label->branches)) {
2732b4fc67c7SRichard Henderson                 /*
2733b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
2734b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
2735b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
2736b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
2737b4fc67c7SRichard Henderson                  * little to be gained by iterating.
2738b4fc67c7SRichard Henderson                  */
2739b4fc67c7SRichard Henderson                 remove = true;
2740b4fc67c7SRichard Henderson             } else {
2741b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
2742b4fc67c7SRichard Henderson                 dead = false;
2743b4fc67c7SRichard Henderson                 remove = false;
2744b4fc67c7SRichard Henderson             }
2745b4fc67c7SRichard Henderson             break;
2746b4fc67c7SRichard Henderson 
2747b4fc67c7SRichard Henderson         case INDEX_op_br:
2748b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
2749b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
2750b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
2751b4fc67c7SRichard Henderson             dead = true;
2752b4fc67c7SRichard Henderson             break;
2753b4fc67c7SRichard Henderson 
2754b4fc67c7SRichard Henderson         case INDEX_op_call:
2755b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
275690163900SRichard Henderson             if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) {
2757b4fc67c7SRichard Henderson                 dead = true;
2758b4fc67c7SRichard Henderson             }
2759b4fc67c7SRichard Henderson             break;
2760b4fc67c7SRichard Henderson 
2761b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
2762b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
2763b4fc67c7SRichard Henderson             remove = false;
2764b4fc67c7SRichard Henderson             break;
2765b4fc67c7SRichard Henderson 
2766b4fc67c7SRichard Henderson         default:
2767b4fc67c7SRichard Henderson             break;
2768b4fc67c7SRichard Henderson         }
2769b4fc67c7SRichard Henderson 
2770b4fc67c7SRichard Henderson         if (remove) {
2771b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
2772b4fc67c7SRichard Henderson         }
2773b4fc67c7SRichard Henderson     }
2774b4fc67c7SRichard Henderson }
2775b4fc67c7SRichard Henderson 
2776c70fbf0aSRichard Henderson #define TS_DEAD  1
2777c70fbf0aSRichard Henderson #define TS_MEM   2
2778c70fbf0aSRichard Henderson 
27795a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
27805a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
27815a18407fSRichard Henderson 
278225f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
278325f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
278425f49c5fSRichard Henderson {
278525f49c5fSRichard Henderson     return ts->state_ptr;
278625f49c5fSRichard Henderson }
278725f49c5fSRichard Henderson 
278825f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
278925f49c5fSRichard Henderson  * maximal regset for its type.
279025f49c5fSRichard Henderson  */
279125f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
279225f49c5fSRichard Henderson {
279325f49c5fSRichard Henderson     *la_temp_pref(ts)
279425f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
279525f49c5fSRichard Henderson }
279625f49c5fSRichard Henderson 
27979c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
27989c43b68dSAurelien Jarno    should be in memory. */
27992616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
2800c896fe29Sbellard {
2801b83eabeaSRichard Henderson     int i;
2802b83eabeaSRichard Henderson 
2803b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2804b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
280525f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2806b83eabeaSRichard Henderson     }
2807b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2808b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
280925f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2810b83eabeaSRichard Henderson     }
2811c896fe29Sbellard }
2812c896fe29Sbellard 
28139c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
28149c43b68dSAurelien Jarno    and local temps should be in memory. */
28152616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
2816641d5fbeSbellard {
2817b83eabeaSRichard Henderson     int i;
2818641d5fbeSbellard 
2819ee17db83SRichard Henderson     for (i = 0; i < nt; ++i) {
2820ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2821ee17db83SRichard Henderson         int state;
2822ee17db83SRichard Henderson 
2823ee17db83SRichard Henderson         switch (ts->kind) {
2824ee17db83SRichard Henderson         case TEMP_FIXED:
2825ee17db83SRichard Henderson         case TEMP_GLOBAL:
2826f57c6915SRichard Henderson         case TEMP_TB:
2827ee17db83SRichard Henderson             state = TS_DEAD | TS_MEM;
2828ee17db83SRichard Henderson             break;
2829c7482438SRichard Henderson         case TEMP_EBB:
2830c0522136SRichard Henderson         case TEMP_CONST:
2831ee17db83SRichard Henderson             state = TS_DEAD;
2832ee17db83SRichard Henderson             break;
2833ee17db83SRichard Henderson         default:
2834ee17db83SRichard Henderson             g_assert_not_reached();
2835c70fbf0aSRichard Henderson         }
2836ee17db83SRichard Henderson         ts->state = state;
2837ee17db83SRichard Henderson         la_reset_pref(ts);
2838641d5fbeSbellard     }
2839641d5fbeSbellard }
2840641d5fbeSbellard 
2841f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
2842f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
2843f65a061cSRichard Henderson {
2844f65a061cSRichard Henderson     int i;
2845f65a061cSRichard Henderson 
2846f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
284725f49c5fSRichard Henderson         int state = s->temps[i].state;
284825f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
284925f49c5fSRichard Henderson         if (state == TS_DEAD) {
285025f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
285125f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
285225f49c5fSRichard Henderson         }
2853f65a061cSRichard Henderson     }
2854f65a061cSRichard Henderson }
2855f65a061cSRichard Henderson 
2856b4cb76e6SRichard Henderson /*
2857c7482438SRichard Henderson  * liveness analysis: conditional branch: all temps are dead unless
2858c7482438SRichard Henderson  * explicitly live-across-conditional-branch, globals and local temps
2859c7482438SRichard Henderson  * should be synced.
2860b4cb76e6SRichard Henderson  */
2861b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
2862b4cb76e6SRichard Henderson {
2863b4cb76e6SRichard Henderson     la_global_sync(s, ng);
2864b4cb76e6SRichard Henderson 
2865b4cb76e6SRichard Henderson     for (int i = ng; i < nt; ++i) {
2866c0522136SRichard Henderson         TCGTemp *ts = &s->temps[i];
2867c0522136SRichard Henderson         int state;
2868c0522136SRichard Henderson 
2869c0522136SRichard Henderson         switch (ts->kind) {
2870f57c6915SRichard Henderson         case TEMP_TB:
2871c0522136SRichard Henderson             state = ts->state;
2872c0522136SRichard Henderson             ts->state = state | TS_MEM;
2873b4cb76e6SRichard Henderson             if (state != TS_DEAD) {
2874b4cb76e6SRichard Henderson                 continue;
2875b4cb76e6SRichard Henderson             }
2876c0522136SRichard Henderson             break;
2877c7482438SRichard Henderson         case TEMP_EBB:
2878c0522136SRichard Henderson         case TEMP_CONST:
2879c0522136SRichard Henderson             continue;
2880c0522136SRichard Henderson         default:
2881c0522136SRichard Henderson             g_assert_not_reached();
2882b4cb76e6SRichard Henderson         }
2883b4cb76e6SRichard Henderson         la_reset_pref(&s->temps[i]);
2884b4cb76e6SRichard Henderson     }
2885b4cb76e6SRichard Henderson }
2886b4cb76e6SRichard Henderson 
2887f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
2888f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
2889f65a061cSRichard Henderson {
2890f65a061cSRichard Henderson     int i;
2891f65a061cSRichard Henderson 
2892f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
2893f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
289425f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
289525f49c5fSRichard Henderson     }
289625f49c5fSRichard Henderson }
289725f49c5fSRichard Henderson 
289825f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
289925f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
290025f49c5fSRichard Henderson {
290125f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
290225f49c5fSRichard Henderson     int i;
290325f49c5fSRichard Henderson 
290425f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
290525f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
290625f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
290725f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
290825f49c5fSRichard Henderson             TCGRegSet set = *pset;
290925f49c5fSRichard Henderson 
291025f49c5fSRichard Henderson             set &= mask;
291125f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
291225f49c5fSRichard Henderson             if (set == 0) {
291325f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
291425f49c5fSRichard Henderson             }
291525f49c5fSRichard Henderson             *pset = set;
291625f49c5fSRichard Henderson         }
2917f65a061cSRichard Henderson     }
2918f65a061cSRichard Henderson }
2919f65a061cSRichard Henderson 
2920874b8574SRichard Henderson /*
2921874b8574SRichard Henderson  * Liveness analysis: Verify the lifetime of TEMP_TB, and reduce
2922874b8574SRichard Henderson  * to TEMP_EBB, if possible.
2923874b8574SRichard Henderson  */
2924874b8574SRichard Henderson static void __attribute__((noinline))
2925874b8574SRichard Henderson liveness_pass_0(TCGContext *s)
2926874b8574SRichard Henderson {
2927874b8574SRichard Henderson     void * const multiple_ebb = (void *)(uintptr_t)-1;
2928874b8574SRichard Henderson     int nb_temps = s->nb_temps;
2929874b8574SRichard Henderson     TCGOp *op, *ebb;
2930874b8574SRichard Henderson 
2931874b8574SRichard Henderson     for (int i = s->nb_globals; i < nb_temps; ++i) {
2932874b8574SRichard Henderson         s->temps[i].state_ptr = NULL;
2933874b8574SRichard Henderson     }
2934874b8574SRichard Henderson 
2935874b8574SRichard Henderson     /*
2936874b8574SRichard Henderson      * Represent each EBB by the op at which it begins.  In the case of
2937874b8574SRichard Henderson      * the first EBB, this is the first op, otherwise it is a label.
2938874b8574SRichard Henderson      * Collect the uses of each TEMP_TB: NULL for unused, EBB for use
2939874b8574SRichard Henderson      * within a single EBB, else MULTIPLE_EBB.
2940874b8574SRichard Henderson      */
2941874b8574SRichard Henderson     ebb = QTAILQ_FIRST(&s->ops);
2942874b8574SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
2943874b8574SRichard Henderson         const TCGOpDef *def;
2944874b8574SRichard Henderson         int nb_oargs, nb_iargs;
2945874b8574SRichard Henderson 
2946874b8574SRichard Henderson         switch (op->opc) {
2947874b8574SRichard Henderson         case INDEX_op_set_label:
2948874b8574SRichard Henderson             ebb = op;
2949874b8574SRichard Henderson             continue;
2950874b8574SRichard Henderson         case INDEX_op_discard:
2951874b8574SRichard Henderson             continue;
2952874b8574SRichard Henderson         case INDEX_op_call:
2953874b8574SRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2954874b8574SRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2955874b8574SRichard Henderson             break;
2956874b8574SRichard Henderson         default:
2957874b8574SRichard Henderson             def = &tcg_op_defs[op->opc];
2958874b8574SRichard Henderson             nb_oargs = def->nb_oargs;
2959874b8574SRichard Henderson             nb_iargs = def->nb_iargs;
2960874b8574SRichard Henderson             break;
2961874b8574SRichard Henderson         }
2962874b8574SRichard Henderson 
2963874b8574SRichard Henderson         for (int i = 0; i < nb_oargs + nb_iargs; ++i) {
2964874b8574SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
2965874b8574SRichard Henderson 
2966874b8574SRichard Henderson             if (ts->kind != TEMP_TB) {
2967874b8574SRichard Henderson                 continue;
2968874b8574SRichard Henderson             }
2969874b8574SRichard Henderson             if (ts->state_ptr == NULL) {
2970874b8574SRichard Henderson                 ts->state_ptr = ebb;
2971874b8574SRichard Henderson             } else if (ts->state_ptr != ebb) {
2972874b8574SRichard Henderson                 ts->state_ptr = multiple_ebb;
2973874b8574SRichard Henderson             }
2974874b8574SRichard Henderson         }
2975874b8574SRichard Henderson     }
2976874b8574SRichard Henderson 
2977874b8574SRichard Henderson     /*
2978874b8574SRichard Henderson      * For TEMP_TB that turned out not to be used beyond one EBB,
2979874b8574SRichard Henderson      * reduce the liveness to TEMP_EBB.
2980874b8574SRichard Henderson      */
2981874b8574SRichard Henderson     for (int i = s->nb_globals; i < nb_temps; ++i) {
2982874b8574SRichard Henderson         TCGTemp *ts = &s->temps[i];
2983874b8574SRichard Henderson         if (ts->kind == TEMP_TB && ts->state_ptr != multiple_ebb) {
2984874b8574SRichard Henderson             ts->kind = TEMP_EBB;
2985874b8574SRichard Henderson         }
2986874b8574SRichard Henderson     }
2987874b8574SRichard Henderson }
2988874b8574SRichard Henderson 
2989a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
2990c896fe29Sbellard    given input arguments is dead. Instructions updating dead
2991c896fe29Sbellard    temporaries are removed. */
29929bbee4c0SRichard Henderson static void __attribute__((noinline))
29939bbee4c0SRichard Henderson liveness_pass_1(TCGContext *s)
2994c896fe29Sbellard {
2995c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
29962616c808SRichard Henderson     int nb_temps = s->nb_temps;
299715fa08f8SRichard Henderson     TCGOp *op, *op_prev;
299825f49c5fSRichard Henderson     TCGRegSet *prefs;
299925f49c5fSRichard Henderson     int i;
300025f49c5fSRichard Henderson 
300125f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
300225f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
300325f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
300425f49c5fSRichard Henderson     }
3005c896fe29Sbellard 
3006ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
30072616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
3008c896fe29Sbellard 
3009eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
301025f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
3011c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
3012c45cb8bbSRichard Henderson         bool have_opc_new2;
3013a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
301425f49c5fSRichard Henderson         TCGTemp *ts;
3015c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
3016c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
3017c45cb8bbSRichard Henderson 
3018c45cb8bbSRichard Henderson         switch (opc) {
3019c896fe29Sbellard         case INDEX_op_call:
3020c6e113f5Sbellard             {
302139004a71SRichard Henderson                 const TCGHelperInfo *info = tcg_call_info(op);
302239004a71SRichard Henderson                 int call_flags = tcg_call_flags(op);
3023c6e113f5Sbellard 
3024cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
3025cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
3026c6e113f5Sbellard 
3027c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
302878505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
3029c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
303025f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
303125f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
3032c6e113f5Sbellard                             goto do_not_remove_call;
3033c6e113f5Sbellard                         }
30349c43b68dSAurelien Jarno                     }
3035c45cb8bbSRichard Henderson                     goto do_remove;
3036152c35aaSRichard Henderson                 }
3037c6e113f5Sbellard             do_not_remove_call:
3038c896fe29Sbellard 
303925f49c5fSRichard Henderson                 /* Output args are dead.  */
3040c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
304125f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
304225f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
3043a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
30446b64b624SAurelien Jarno                     }
304525f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
3046a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
30479c43b68dSAurelien Jarno                     }
304825f49c5fSRichard Henderson                     ts->state = TS_DEAD;
304925f49c5fSRichard Henderson                     la_reset_pref(ts);
3050c896fe29Sbellard                 }
3051c896fe29Sbellard 
305231fd884bSRichard Henderson                 /* Not used -- it will be tcg_target_call_oarg_reg().  */
305331fd884bSRichard Henderson                 memset(op->output_pref, 0, sizeof(op->output_pref));
305431fd884bSRichard Henderson 
305578505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
305678505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
3057f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
3058c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
3059f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
3060b9c18f56Saurel32                 }
3061c896fe29Sbellard 
306225f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
3063866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
306425f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
306539004a71SRichard Henderson                     if (ts->state & TS_DEAD) {
3066a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
3067c896fe29Sbellard                     }
3068c896fe29Sbellard                 }
306925f49c5fSRichard Henderson 
307025f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
307125f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
307225f49c5fSRichard Henderson 
307339004a71SRichard Henderson                 /*
307439004a71SRichard Henderson                  * Input arguments are live for preceding opcodes.
307539004a71SRichard Henderson                  *
307639004a71SRichard Henderson                  * For those arguments that die, and will be allocated in
307739004a71SRichard Henderson                  * registers, clear the register set for that arg, to be
307839004a71SRichard Henderson                  * filled in below.  For args that will be on the stack,
307939004a71SRichard Henderson                  * reset to any available reg.  Process arguments in reverse
308039004a71SRichard Henderson                  * order so that if a temp is used more than once, the stack
308139004a71SRichard Henderson                  * reset to max happens before the register reset to 0.
308225f49c5fSRichard Henderson                  */
308339004a71SRichard Henderson                 for (i = nb_iargs - 1; i >= 0; i--) {
308439004a71SRichard Henderson                     const TCGCallArgumentLoc *loc = &info->in[i];
308539004a71SRichard Henderson                     ts = arg_temp(op->args[nb_oargs + i]);
308639004a71SRichard Henderson 
308739004a71SRichard Henderson                     if (ts->state & TS_DEAD) {
308839004a71SRichard Henderson                         switch (loc->kind) {
308939004a71SRichard Henderson                         case TCG_CALL_ARG_NORMAL:
309039004a71SRichard Henderson                         case TCG_CALL_ARG_EXTEND_U:
309139004a71SRichard Henderson                         case TCG_CALL_ARG_EXTEND_S:
309239004a71SRichard Henderson                             if (REG_P(loc)) {
309339004a71SRichard Henderson                                 *la_temp_pref(ts) = 0;
309439004a71SRichard Henderson                                 break;
309539004a71SRichard Henderson                             }
309639004a71SRichard Henderson                             /* fall through */
309739004a71SRichard Henderson                         default:
309839004a71SRichard Henderson                             *la_temp_pref(ts) =
309939004a71SRichard Henderson                                 tcg_target_available_regs[ts->type];
310039004a71SRichard Henderson                             break;
310139004a71SRichard Henderson                         }
310225f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
310325f49c5fSRichard Henderson                     }
310425f49c5fSRichard Henderson                 }
310525f49c5fSRichard Henderson 
310639004a71SRichard Henderson                 /*
310739004a71SRichard Henderson                  * For each input argument, add its input register to prefs.
310839004a71SRichard Henderson                  * If a temp is used once, this produces a single set bit;
310939004a71SRichard Henderson                  * if a temp is used multiple times, this produces a set.
311039004a71SRichard Henderson                  */
311139004a71SRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
311239004a71SRichard Henderson                     const TCGCallArgumentLoc *loc = &info->in[i];
311339004a71SRichard Henderson                     ts = arg_temp(op->args[nb_oargs + i]);
311439004a71SRichard Henderson 
311539004a71SRichard Henderson                     switch (loc->kind) {
311639004a71SRichard Henderson                     case TCG_CALL_ARG_NORMAL:
311739004a71SRichard Henderson                     case TCG_CALL_ARG_EXTEND_U:
311839004a71SRichard Henderson                     case TCG_CALL_ARG_EXTEND_S:
311939004a71SRichard Henderson                         if (REG_P(loc)) {
312025f49c5fSRichard Henderson                             tcg_regset_set_reg(*la_temp_pref(ts),
312139004a71SRichard Henderson                                 tcg_target_call_iarg_regs[loc->arg_slot]);
312239004a71SRichard Henderson                         }
312339004a71SRichard Henderson                         break;
312439004a71SRichard Henderson                     default:
312539004a71SRichard Henderson                         break;
3126c70fbf0aSRichard Henderson                     }
3127c19f47bfSAurelien Jarno                 }
3128c6e113f5Sbellard             }
3129c896fe29Sbellard             break;
3130765b842aSRichard Henderson         case INDEX_op_insn_start:
3131c896fe29Sbellard             break;
31325ff9d6a4Sbellard         case INDEX_op_discard:
31335ff9d6a4Sbellard             /* mark the temporary as dead */
313425f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
313525f49c5fSRichard Henderson             ts->state = TS_DEAD;
313625f49c5fSRichard Henderson             la_reset_pref(ts);
31375ff9d6a4Sbellard             break;
31381305c451SRichard Henderson 
31391305c451SRichard Henderson         case INDEX_op_add2_i32:
3140c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
3141f1fae40cSRichard Henderson             goto do_addsub2;
31421305c451SRichard Henderson         case INDEX_op_sub2_i32:
3143c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
3144f1fae40cSRichard Henderson             goto do_addsub2;
3145f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
3146c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
3147f1fae40cSRichard Henderson             goto do_addsub2;
3148f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
3149c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
3150f1fae40cSRichard Henderson         do_addsub2:
31511305c451SRichard Henderson             nb_iargs = 4;
31521305c451SRichard Henderson             nb_oargs = 2;
31531305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
31541305c451SRichard Henderson                the low part.  The result can be optimized to a simple
31551305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
31561305c451SRichard Henderson                cpu mode is set to 32 bit.  */
3157b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
3158b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
31591305c451SRichard Henderson                     goto do_remove;
31601305c451SRichard Henderson                 }
3161c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
3162c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
3163c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
3164efee3746SRichard Henderson                 op->args[1] = op->args[2];
3165efee3746SRichard Henderson                 op->args[2] = op->args[4];
31661305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
31671305c451SRichard Henderson                 nb_iargs = 2;
31681305c451SRichard Henderson                 nb_oargs = 1;
31691305c451SRichard Henderson             }
31701305c451SRichard Henderson             goto do_not_remove;
31711305c451SRichard Henderson 
31721414968aSRichard Henderson         case INDEX_op_mulu2_i32:
3173c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
3174c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
3175c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
317603271524SRichard Henderson             goto do_mul2;
3177f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
3178c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
3179c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
3180c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
3181f1fae40cSRichard Henderson             goto do_mul2;
3182f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
3183c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
3184c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
3185c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
318603271524SRichard Henderson             goto do_mul2;
3187f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
3188c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
3189c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
3190c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
319103271524SRichard Henderson             goto do_mul2;
3192f1fae40cSRichard Henderson         do_mul2:
31931414968aSRichard Henderson             nb_iargs = 2;
31941414968aSRichard Henderson             nb_oargs = 2;
3195b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
3196b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
319703271524SRichard Henderson                     /* Both parts of the operation are dead.  */
31981414968aSRichard Henderson                     goto do_remove;
31991414968aSRichard Henderson                 }
320003271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
3201c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
3202efee3746SRichard Henderson                 op->args[1] = op->args[2];
3203efee3746SRichard Henderson                 op->args[2] = op->args[3];
3204b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
320503271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
3206c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
3207efee3746SRichard Henderson                 op->args[0] = op->args[1];
3208efee3746SRichard Henderson                 op->args[1] = op->args[2];
3209efee3746SRichard Henderson                 op->args[2] = op->args[3];
321003271524SRichard Henderson             } else {
321103271524SRichard Henderson                 goto do_not_remove;
321203271524SRichard Henderson             }
321303271524SRichard Henderson             /* Mark the single-word operation live.  */
32141414968aSRichard Henderson             nb_oargs = 1;
32151414968aSRichard Henderson             goto do_not_remove;
32161414968aSRichard Henderson 
3217c896fe29Sbellard         default:
32181305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
3219c896fe29Sbellard             nb_iargs = def->nb_iargs;
3220c896fe29Sbellard             nb_oargs = def->nb_oargs;
3221c896fe29Sbellard 
3222c896fe29Sbellard             /* Test if the operation can be removed because all
32235ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
32245ff9d6a4Sbellard                implies side effects */
32255ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
3226c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
3227b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
3228c896fe29Sbellard                         goto do_not_remove;
3229c896fe29Sbellard                     }
32309c43b68dSAurelien Jarno                 }
3231152c35aaSRichard Henderson                 goto do_remove;
3232152c35aaSRichard Henderson             }
3233152c35aaSRichard Henderson             goto do_not_remove;
3234152c35aaSRichard Henderson 
32351305c451SRichard Henderson         do_remove:
32360c627cdcSRichard Henderson             tcg_op_remove(s, op);
3237152c35aaSRichard Henderson             break;
3238152c35aaSRichard Henderson 
3239c896fe29Sbellard         do_not_remove:
3240c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
324125f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
324225f49c5fSRichard Henderson 
324325f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
324431fd884bSRichard Henderson                 if (i < ARRAY_SIZE(op->output_pref)) {
324525f49c5fSRichard Henderson                     op->output_pref[i] = *la_temp_pref(ts);
324631fd884bSRichard Henderson                 }
324725f49c5fSRichard Henderson 
324825f49c5fSRichard Henderson                 /* Output args are dead.  */
324925f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
3250a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
32516b64b624SAurelien Jarno                 }
325225f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
3253a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
32549c43b68dSAurelien Jarno                 }
325525f49c5fSRichard Henderson                 ts->state = TS_DEAD;
325625f49c5fSRichard Henderson                 la_reset_pref(ts);
3257c896fe29Sbellard             }
3258c896fe29Sbellard 
325925f49c5fSRichard Henderson             /* If end of basic block, update.  */
3260ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
3261ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
3262b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_COND_BRANCH) {
3263b4cb76e6SRichard Henderson                 la_bb_sync(s, nb_globals, nb_temps);
3264ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
32652616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
32663d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
3267f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
326825f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
326925f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
327025f49c5fSRichard Henderson                 }
3271c896fe29Sbellard             }
3272c896fe29Sbellard 
327325f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
3274866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
327525f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
327625f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
3277a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
3278c896fe29Sbellard                 }
3279c19f47bfSAurelien Jarno             }
328025f49c5fSRichard Henderson 
328125f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
3282c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
328325f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
328425f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
328525f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
328625f49c5fSRichard Henderson                        all regs for the type.  */
328725f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
328825f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
328925f49c5fSRichard Henderson                 }
329025f49c5fSRichard Henderson             }
329125f49c5fSRichard Henderson 
329225f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
329325f49c5fSRichard Henderson             switch (opc) {
329425f49c5fSRichard Henderson             case INDEX_op_mov_i32:
329525f49c5fSRichard Henderson             case INDEX_op_mov_i64:
329625f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
329725f49c5fSRichard Henderson                    have proper constraints.  That said, special case
329825f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
329925f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
330025f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
330125f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
330225f49c5fSRichard Henderson                 }
330325f49c5fSRichard Henderson                 break;
330425f49c5fSRichard Henderson 
330525f49c5fSRichard Henderson             default:
330625f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
330725f49c5fSRichard Henderson                     const TCGArgConstraint *ct = &def->args_ct[i];
330825f49c5fSRichard Henderson                     TCGRegSet set, *pset;
330925f49c5fSRichard Henderson 
331025f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
331125f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
331225f49c5fSRichard Henderson                     set = *pset;
331325f49c5fSRichard Henderson 
33149be0d080SRichard Henderson                     set &= ct->regs;
3315bc2b17e6SRichard Henderson                     if (ct->ialias) {
331631fd884bSRichard Henderson                         set &= output_pref(op, ct->alias_index);
331725f49c5fSRichard Henderson                     }
331825f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
331925f49c5fSRichard Henderson                     if (set == 0) {
33209be0d080SRichard Henderson                         set = ct->regs;
332125f49c5fSRichard Henderson                     }
332225f49c5fSRichard Henderson                     *pset = set;
332325f49c5fSRichard Henderson                 }
332425f49c5fSRichard Henderson                 break;
3325c896fe29Sbellard             }
3326c896fe29Sbellard             break;
3327c896fe29Sbellard         }
3328bee158cbSRichard Henderson         op->life = arg_life;
3329c896fe29Sbellard     }
33301ff0a2c5SEvgeny Voevodin }
3331c896fe29Sbellard 
33325a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
33339bbee4c0SRichard Henderson static bool __attribute__((noinline))
33349bbee4c0SRichard Henderson liveness_pass_2(TCGContext *s)
33355a18407fSRichard Henderson {
33365a18407fSRichard Henderson     int nb_globals = s->nb_globals;
333715fa08f8SRichard Henderson     int nb_temps, i;
33385a18407fSRichard Henderson     bool changes = false;
333915fa08f8SRichard Henderson     TCGOp *op, *op_next;
33405a18407fSRichard Henderson 
33415a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
33425a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
33435a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
33445a18407fSRichard Henderson         if (its->indirect_reg) {
33455a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
33465a18407fSRichard Henderson             dts->type = its->type;
33475a18407fSRichard Henderson             dts->base_type = its->base_type;
3348e1e64652SRichard Henderson             dts->temp_subindex = its->temp_subindex;
3349c7482438SRichard Henderson             dts->kind = TEMP_EBB;
3350b83eabeaSRichard Henderson             its->state_ptr = dts;
3351b83eabeaSRichard Henderson         } else {
3352b83eabeaSRichard Henderson             its->state_ptr = NULL;
33535a18407fSRichard Henderson         }
3354b83eabeaSRichard Henderson         /* All globals begin dead.  */
3355b83eabeaSRichard Henderson         its->state = TS_DEAD;
33565a18407fSRichard Henderson     }
3357b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
3358b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
3359b83eabeaSRichard Henderson         its->state_ptr = NULL;
3360b83eabeaSRichard Henderson         its->state = TS_DEAD;
3361b83eabeaSRichard Henderson     }
33625a18407fSRichard Henderson 
336315fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
33645a18407fSRichard Henderson         TCGOpcode opc = op->opc;
33655a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
33665a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
33675a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
3368b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
33695a18407fSRichard Henderson 
33705a18407fSRichard Henderson         if (opc == INDEX_op_call) {
3371cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
3372cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
337390163900SRichard Henderson             call_flags = tcg_call_flags(op);
33745a18407fSRichard Henderson         } else {
33755a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
33765a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
33775a18407fSRichard Henderson 
33785a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
3379b4cb76e6SRichard Henderson             if (def->flags & TCG_OPF_COND_BRANCH) {
3380b4cb76e6SRichard Henderson                 /* Like reading globals: sync_globals */
3381b4cb76e6SRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
3382b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
33835a18407fSRichard Henderson                 /* Like writing globals: save_globals */
33845a18407fSRichard Henderson                 call_flags = 0;
33855a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
33865a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
33875a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
33885a18407fSRichard Henderson             } else {
33895a18407fSRichard Henderson                 /* No effect on globals.  */
33905a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
33915a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
33925a18407fSRichard Henderson             }
33935a18407fSRichard Henderson         }
33945a18407fSRichard Henderson 
33955a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
33965a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3397b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3398b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
3399b83eabeaSRichard Henderson             if (dir_ts && arg_ts->state == TS_DEAD) {
3400b83eabeaSRichard Henderson                 TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
34015a18407fSRichard Henderson                                   ? INDEX_op_ld_i32
34025a18407fSRichard Henderson                                   : INDEX_op_ld_i64);
3403d4478943SPhilippe Mathieu-Daudé                 TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3);
34045a18407fSRichard Henderson 
3405b83eabeaSRichard Henderson                 lop->args[0] = temp_arg(dir_ts);
3406b83eabeaSRichard Henderson                 lop->args[1] = temp_arg(arg_ts->mem_base);
3407b83eabeaSRichard Henderson                 lop->args[2] = arg_ts->mem_offset;
34085a18407fSRichard Henderson 
34095a18407fSRichard Henderson                 /* Loaded, but synced with memory.  */
3410b83eabeaSRichard Henderson                 arg_ts->state = TS_MEM;
34115a18407fSRichard Henderson             }
34125a18407fSRichard Henderson         }
34135a18407fSRichard Henderson 
34145a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
34155a18407fSRichard Henderson            No action is required except keeping temp_state up to date
34165a18407fSRichard Henderson            so that we reload when needed.  */
34175a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3418b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3419b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
3420b83eabeaSRichard Henderson             if (dir_ts) {
3421b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
34225a18407fSRichard Henderson                 changes = true;
34235a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3424b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
34255a18407fSRichard Henderson                 }
34265a18407fSRichard Henderson             }
34275a18407fSRichard Henderson         }
34285a18407fSRichard Henderson 
34295a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
34305a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
34315a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
34325a18407fSRichard Henderson             /* Nothing to do */
34335a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
34345a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
34355a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
34365a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
3437b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3438b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3439b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
34405a18407fSRichard Henderson             }
34415a18407fSRichard Henderson         } else {
34425a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
34435a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
34445a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
3445b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3446b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3447b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
34485a18407fSRichard Henderson             }
34495a18407fSRichard Henderson         }
34505a18407fSRichard Henderson 
34515a18407fSRichard Henderson         /* Outputs become available.  */
345261f15c48SRichard Henderson         if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) {
345361f15c48SRichard Henderson             arg_ts = arg_temp(op->args[0]);
345461f15c48SRichard Henderson             dir_ts = arg_ts->state_ptr;
345561f15c48SRichard Henderson             if (dir_ts) {
345661f15c48SRichard Henderson                 op->args[0] = temp_arg(dir_ts);
345761f15c48SRichard Henderson                 changes = true;
345861f15c48SRichard Henderson 
345961f15c48SRichard Henderson                 /* The output is now live and modified.  */
346061f15c48SRichard Henderson                 arg_ts->state = 0;
346161f15c48SRichard Henderson 
346261f15c48SRichard Henderson                 if (NEED_SYNC_ARG(0)) {
346361f15c48SRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
346461f15c48SRichard Henderson                                       ? INDEX_op_st_i32
346561f15c48SRichard Henderson                                       : INDEX_op_st_i64);
3466d4478943SPhilippe Mathieu-Daudé                     TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
346761f15c48SRichard Henderson                     TCGTemp *out_ts = dir_ts;
346861f15c48SRichard Henderson 
346961f15c48SRichard Henderson                     if (IS_DEAD_ARG(0)) {
347061f15c48SRichard Henderson                         out_ts = arg_temp(op->args[1]);
347161f15c48SRichard Henderson                         arg_ts->state = TS_DEAD;
347261f15c48SRichard Henderson                         tcg_op_remove(s, op);
347361f15c48SRichard Henderson                     } else {
347461f15c48SRichard Henderson                         arg_ts->state = TS_MEM;
347561f15c48SRichard Henderson                     }
347661f15c48SRichard Henderson 
347761f15c48SRichard Henderson                     sop->args[0] = temp_arg(out_ts);
347861f15c48SRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
347961f15c48SRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
348061f15c48SRichard Henderson                 } else {
348161f15c48SRichard Henderson                     tcg_debug_assert(!IS_DEAD_ARG(0));
348261f15c48SRichard Henderson                 }
348361f15c48SRichard Henderson             }
348461f15c48SRichard Henderson         } else {
34855a18407fSRichard Henderson             for (i = 0; i < nb_oargs; i++) {
3486b83eabeaSRichard Henderson                 arg_ts = arg_temp(op->args[i]);
3487b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3488b83eabeaSRichard Henderson                 if (!dir_ts) {
34895a18407fSRichard Henderson                     continue;
34905a18407fSRichard Henderson                 }
3491b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
34925a18407fSRichard Henderson                 changes = true;
34935a18407fSRichard Henderson 
34945a18407fSRichard Henderson                 /* The output is now live and modified.  */
3495b83eabeaSRichard Henderson                 arg_ts->state = 0;
34965a18407fSRichard Henderson 
34975a18407fSRichard Henderson                 /* Sync outputs upon their last write.  */
34985a18407fSRichard Henderson                 if (NEED_SYNC_ARG(i)) {
3499b83eabeaSRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
35005a18407fSRichard Henderson                                       ? INDEX_op_st_i32
35015a18407fSRichard Henderson                                       : INDEX_op_st_i64);
3502d4478943SPhilippe Mathieu-Daudé                     TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
35035a18407fSRichard Henderson 
3504b83eabeaSRichard Henderson                     sop->args[0] = temp_arg(dir_ts);
3505b83eabeaSRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
3506b83eabeaSRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
35075a18407fSRichard Henderson 
3508b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
35095a18407fSRichard Henderson                 }
35105a18407fSRichard Henderson                 /* Drop outputs that are dead.  */
35115a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3512b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
35135a18407fSRichard Henderson                 }
35145a18407fSRichard Henderson             }
35155a18407fSRichard Henderson         }
351661f15c48SRichard Henderson     }
35175a18407fSRichard Henderson 
35185a18407fSRichard Henderson     return changes;
35195a18407fSRichard Henderson }
35205a18407fSRichard Henderson 
35212272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
3522c896fe29Sbellard {
352331c96417SRichard Henderson     intptr_t off;
3524273eb50cSRichard Henderson     int size, align;
3525c1c09194SRichard Henderson 
3526273eb50cSRichard Henderson     /* When allocating an object, look at the full type. */
3527273eb50cSRichard Henderson     size = tcg_type_size(ts->base_type);
3528273eb50cSRichard Henderson     switch (ts->base_type) {
3529c1c09194SRichard Henderson     case TCG_TYPE_I32:
353031c96417SRichard Henderson         align = 4;
3531c1c09194SRichard Henderson         break;
3532c1c09194SRichard Henderson     case TCG_TYPE_I64:
3533c1c09194SRichard Henderson     case TCG_TYPE_V64:
353431c96417SRichard Henderson         align = 8;
3535c1c09194SRichard Henderson         break;
353643eef72fSRichard Henderson     case TCG_TYPE_I128:
3537c1c09194SRichard Henderson     case TCG_TYPE_V128:
3538c1c09194SRichard Henderson     case TCG_TYPE_V256:
353943eef72fSRichard Henderson         /*
354043eef72fSRichard Henderson          * Note that we do not require aligned storage for V256,
354143eef72fSRichard Henderson          * and that we provide alignment for I128 to match V128,
354243eef72fSRichard Henderson          * even if that's above what the host ABI requires.
354343eef72fSRichard Henderson          */
354431c96417SRichard Henderson         align = 16;
3545c1c09194SRichard Henderson         break;
3546c1c09194SRichard Henderson     default:
3547c1c09194SRichard Henderson         g_assert_not_reached();
3548b591dc59SBlue Swirl     }
3549c1c09194SRichard Henderson 
3550b9537d59SRichard Henderson     /*
3551b9537d59SRichard Henderson      * Assume the stack is sufficiently aligned.
3552b9537d59SRichard Henderson      * This affects e.g. ARM NEON, where we have 8 byte stack alignment
3553b9537d59SRichard Henderson      * and do not require 16 byte vector alignment.  This seems slightly
3554b9537d59SRichard Henderson      * easier than fully parameterizing the above switch statement.
3555b9537d59SRichard Henderson      */
3556b9537d59SRichard Henderson     align = MIN(TCG_TARGET_STACK_ALIGN, align);
3557c1c09194SRichard Henderson     off = ROUND_UP(s->current_frame_offset, align);
3558732d5897SRichard Henderson 
3559732d5897SRichard Henderson     /* If we've exhausted the stack frame, restart with a smaller TB. */
3560732d5897SRichard Henderson     if (off + size > s->frame_end) {
3561732d5897SRichard Henderson         tcg_raise_tb_overflow(s);
3562732d5897SRichard Henderson     }
3563c1c09194SRichard Henderson     s->current_frame_offset = off + size;
35649defd1bdSRichard Henderson #if defined(__sparc__)
3565273eb50cSRichard Henderson     off += TCG_TARGET_STACK_BIAS;
35669defd1bdSRichard Henderson #endif
3567273eb50cSRichard Henderson 
3568273eb50cSRichard Henderson     /* If the object was subdivided, assign memory to all the parts. */
3569273eb50cSRichard Henderson     if (ts->base_type != ts->type) {
3570273eb50cSRichard Henderson         int part_size = tcg_type_size(ts->type);
3571273eb50cSRichard Henderson         int part_count = size / part_size;
3572273eb50cSRichard Henderson 
3573273eb50cSRichard Henderson         /*
3574273eb50cSRichard Henderson          * Each part is allocated sequentially in tcg_temp_new_internal.
3575273eb50cSRichard Henderson          * Jump back to the first part by subtracting the current index.
3576273eb50cSRichard Henderson          */
3577273eb50cSRichard Henderson         ts -= ts->temp_subindex;
3578273eb50cSRichard Henderson         for (int i = 0; i < part_count; ++i) {
3579273eb50cSRichard Henderson             ts[i].mem_offset = off + i * part_size;
3580273eb50cSRichard Henderson             ts[i].mem_base = s->frame_temp;
3581273eb50cSRichard Henderson             ts[i].mem_allocated = 1;
3582273eb50cSRichard Henderson         }
3583273eb50cSRichard Henderson     } else {
3584273eb50cSRichard Henderson         ts->mem_offset = off;
3585b3a62939SRichard Henderson         ts->mem_base = s->frame_temp;
3586c896fe29Sbellard         ts->mem_allocated = 1;
3587c896fe29Sbellard     }
3588273eb50cSRichard Henderson }
3589c896fe29Sbellard 
3590098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */
3591098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg)
3592098859f1SRichard Henderson {
3593098859f1SRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
3594098859f1SRichard Henderson         TCGReg old = ts->reg;
3595098859f1SRichard Henderson         tcg_debug_assert(s->reg_to_temp[old] == ts);
3596098859f1SRichard Henderson         if (old == reg) {
3597098859f1SRichard Henderson             return;
3598098859f1SRichard Henderson         }
3599098859f1SRichard Henderson         s->reg_to_temp[old] = NULL;
3600098859f1SRichard Henderson     }
3601098859f1SRichard Henderson     tcg_debug_assert(s->reg_to_temp[reg] == NULL);
3602098859f1SRichard Henderson     s->reg_to_temp[reg] = ts;
3603098859f1SRichard Henderson     ts->val_type = TEMP_VAL_REG;
3604098859f1SRichard Henderson     ts->reg = reg;
3605098859f1SRichard Henderson }
3606098859f1SRichard Henderson 
3607098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */
3608098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type)
3609098859f1SRichard Henderson {
3610098859f1SRichard Henderson     tcg_debug_assert(type != TEMP_VAL_REG);
3611098859f1SRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
3612098859f1SRichard Henderson         TCGReg reg = ts->reg;
3613098859f1SRichard Henderson         tcg_debug_assert(s->reg_to_temp[reg] == ts);
3614098859f1SRichard Henderson         s->reg_to_temp[reg] = NULL;
3615098859f1SRichard Henderson     }
3616098859f1SRichard Henderson     ts->val_type = type;
3617098859f1SRichard Henderson }
3618098859f1SRichard Henderson 
3619b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
3620b3915dbbSRichard Henderson 
362159d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
362259d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
362359d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
3624c896fe29Sbellard {
3625c0522136SRichard Henderson     TCGTempVal new_type;
3626c0522136SRichard Henderson 
3627c0522136SRichard Henderson     switch (ts->kind) {
3628c0522136SRichard Henderson     case TEMP_FIXED:
362959d7c14eSRichard Henderson         return;
3630c0522136SRichard Henderson     case TEMP_GLOBAL:
3631f57c6915SRichard Henderson     case TEMP_TB:
3632c0522136SRichard Henderson         new_type = TEMP_VAL_MEM;
3633c0522136SRichard Henderson         break;
3634c7482438SRichard Henderson     case TEMP_EBB:
3635c0522136SRichard Henderson         new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD;
3636c0522136SRichard Henderson         break;
3637c0522136SRichard Henderson     case TEMP_CONST:
3638c0522136SRichard Henderson         new_type = TEMP_VAL_CONST;
3639c0522136SRichard Henderson         break;
3640c0522136SRichard Henderson     default:
3641c0522136SRichard Henderson         g_assert_not_reached();
364259d7c14eSRichard Henderson     }
3643098859f1SRichard Henderson     set_temp_val_nonreg(s, ts, new_type);
364459d7c14eSRichard Henderson }
3645c896fe29Sbellard 
364659d7c14eSRichard Henderson /* Mark a temporary as dead.  */
364759d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
364859d7c14eSRichard Henderson {
364959d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
365059d7c14eSRichard Henderson }
365159d7c14eSRichard Henderson 
365259d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
365359d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
365459d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
365559d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
365698b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
365798b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
365859d7c14eSRichard Henderson {
3659c0522136SRichard Henderson     if (!temp_readonly(ts) && !ts->mem_coherent) {
36607f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
36612272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
366259d7c14eSRichard Henderson         }
366359d7c14eSRichard Henderson         switch (ts->val_type) {
366459d7c14eSRichard Henderson         case TEMP_VAL_CONST:
366559d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
366659d7c14eSRichard Henderson                require it later in a register, so attempt to store the
366759d7c14eSRichard Henderson                constant to memory directly.  */
366859d7c14eSRichard Henderson             if (free_or_dead
366959d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
367059d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
367159d7c14eSRichard Henderson                 break;
367259d7c14eSRichard Henderson             }
367359d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
367498b4e186SRichard Henderson                       allocated_regs, preferred_regs);
367559d7c14eSRichard Henderson             /* fallthrough */
367659d7c14eSRichard Henderson 
367759d7c14eSRichard Henderson         case TEMP_VAL_REG:
367859d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
367959d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
368059d7c14eSRichard Henderson             break;
368159d7c14eSRichard Henderson 
368259d7c14eSRichard Henderson         case TEMP_VAL_MEM:
368359d7c14eSRichard Henderson             break;
368459d7c14eSRichard Henderson 
368559d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
368659d7c14eSRichard Henderson         default:
3687732e89f4SRichard Henderson             g_assert_not_reached();
3688c896fe29Sbellard         }
36897f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
36907f6ceedfSAurelien Jarno     }
369159d7c14eSRichard Henderson     if (free_or_dead) {
369259d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
369359d7c14eSRichard Henderson     }
369459d7c14eSRichard Henderson }
36957f6ceedfSAurelien Jarno 
36967f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
3697b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
36987f6ceedfSAurelien Jarno {
3699f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
3700f8b2f202SRichard Henderson     if (ts != NULL) {
370198b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
3702c896fe29Sbellard     }
3703c896fe29Sbellard }
3704c896fe29Sbellard 
3705b016486eSRichard Henderson /**
3706b016486eSRichard Henderson  * tcg_reg_alloc:
3707b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
3708b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
3709b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
3710b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
3711b016486eSRichard Henderson  *
3712b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
3713b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
3714b016486eSRichard Henderson  */
3715b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
3716b016486eSRichard Henderson                             TCGRegSet allocated_regs,
3717b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
3718c896fe29Sbellard {
3719b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
3720b016486eSRichard Henderson     TCGRegSet reg_ct[2];
372191478cefSRichard Henderson     const int *order;
3722c896fe29Sbellard 
3723b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
3724b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
3725b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
3726b016486eSRichard Henderson 
3727b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
3728b016486eSRichard Henderson        or if the preference made no difference.  */
3729b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
3730b016486eSRichard Henderson 
373191478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
3732c896fe29Sbellard 
3733b016486eSRichard Henderson     /* Try free registers, preferences first.  */
3734b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3735b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3736b016486eSRichard Henderson 
3737b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3738b016486eSRichard Henderson             /* One register in the set.  */
3739b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3740b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
3741c896fe29Sbellard                 return reg;
3742c896fe29Sbellard             }
3743b016486eSRichard Henderson         } else {
374491478cefSRichard Henderson             for (i = 0; i < n; i++) {
3745b016486eSRichard Henderson                 TCGReg reg = order[i];
3746b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
3747b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
3748b016486eSRichard Henderson                     return reg;
3749b016486eSRichard Henderson                 }
3750b016486eSRichard Henderson             }
3751b016486eSRichard Henderson         }
3752b016486eSRichard Henderson     }
3753b016486eSRichard Henderson 
3754b016486eSRichard Henderson     /* We must spill something.  */
3755b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3756b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3757b016486eSRichard Henderson 
3758b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3759b016486eSRichard Henderson             /* One register in the set.  */
3760b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3761b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
3762c896fe29Sbellard             return reg;
3763b016486eSRichard Henderson         } else {
3764b016486eSRichard Henderson             for (i = 0; i < n; i++) {
3765b016486eSRichard Henderson                 TCGReg reg = order[i];
3766b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
3767b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
3768b016486eSRichard Henderson                     return reg;
3769b016486eSRichard Henderson                 }
3770b016486eSRichard Henderson             }
3771c896fe29Sbellard         }
3772c896fe29Sbellard     }
3773c896fe29Sbellard 
3774732e89f4SRichard Henderson     g_assert_not_reached();
3775c896fe29Sbellard }
3776c896fe29Sbellard 
377729f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs,
377829f5e925SRichard Henderson                                  TCGRegSet allocated_regs,
377929f5e925SRichard Henderson                                  TCGRegSet preferred_regs, bool rev)
378029f5e925SRichard Henderson {
378129f5e925SRichard Henderson     int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
378229f5e925SRichard Henderson     TCGRegSet reg_ct[2];
378329f5e925SRichard Henderson     const int *order;
378429f5e925SRichard Henderson 
378529f5e925SRichard Henderson     /* Ensure that if I is not in allocated_regs, I+1 is not either. */
378629f5e925SRichard Henderson     reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1));
378729f5e925SRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
378829f5e925SRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
378929f5e925SRichard Henderson 
379029f5e925SRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
379129f5e925SRichard Henderson 
379229f5e925SRichard Henderson     /*
379329f5e925SRichard Henderson      * Skip the preferred_regs option if it cannot be satisfied,
379429f5e925SRichard Henderson      * or if the preference made no difference.
379529f5e925SRichard Henderson      */
379629f5e925SRichard Henderson     k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
379729f5e925SRichard Henderson 
379829f5e925SRichard Henderson     /*
379929f5e925SRichard Henderson      * Minimize the number of flushes by looking for 2 free registers first,
380029f5e925SRichard Henderson      * then a single flush, then two flushes.
380129f5e925SRichard Henderson      */
380229f5e925SRichard Henderson     for (fmin = 2; fmin >= 0; fmin--) {
380329f5e925SRichard Henderson         for (j = k; j < 2; j++) {
380429f5e925SRichard Henderson             TCGRegSet set = reg_ct[j];
380529f5e925SRichard Henderson 
380629f5e925SRichard Henderson             for (i = 0; i < n; i++) {
380729f5e925SRichard Henderson                 TCGReg reg = order[i];
380829f5e925SRichard Henderson 
380929f5e925SRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
381029f5e925SRichard Henderson                     int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1];
381129f5e925SRichard Henderson                     if (f >= fmin) {
381229f5e925SRichard Henderson                         tcg_reg_free(s, reg, allocated_regs);
381329f5e925SRichard Henderson                         tcg_reg_free(s, reg + 1, allocated_regs);
381429f5e925SRichard Henderson                         return reg;
381529f5e925SRichard Henderson                     }
381629f5e925SRichard Henderson                 }
381729f5e925SRichard Henderson             }
381829f5e925SRichard Henderson         }
381929f5e925SRichard Henderson     }
3820732e89f4SRichard Henderson     g_assert_not_reached();
382129f5e925SRichard Henderson }
382229f5e925SRichard Henderson 
382340ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
382440ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
382540ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
3826b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
382740ae5c62SRichard Henderson {
382840ae5c62SRichard Henderson     TCGReg reg;
382940ae5c62SRichard Henderson 
383040ae5c62SRichard Henderson     switch (ts->val_type) {
383140ae5c62SRichard Henderson     case TEMP_VAL_REG:
383240ae5c62SRichard Henderson         return;
383340ae5c62SRichard Henderson     case TEMP_VAL_CONST:
3834b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3835b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
38360a6a8bc8SRichard Henderson         if (ts->type <= TCG_TYPE_I64) {
383740ae5c62SRichard Henderson             tcg_out_movi(s, ts->type, reg, ts->val);
38380a6a8bc8SRichard Henderson         } else {
38394e186175SRichard Henderson             uint64_t val = ts->val;
38404e186175SRichard Henderson             MemOp vece = MO_64;
38414e186175SRichard Henderson 
38424e186175SRichard Henderson             /*
38434e186175SRichard Henderson              * Find the minimal vector element that matches the constant.
38444e186175SRichard Henderson              * The targets will, in general, have to do this search anyway,
38454e186175SRichard Henderson              * do this generically.
38464e186175SRichard Henderson              */
38474e186175SRichard Henderson             if (val == dup_const(MO_8, val)) {
38484e186175SRichard Henderson                 vece = MO_8;
38494e186175SRichard Henderson             } else if (val == dup_const(MO_16, val)) {
38504e186175SRichard Henderson                 vece = MO_16;
38510b4286ddSRichard Henderson             } else if (val == dup_const(MO_32, val)) {
38524e186175SRichard Henderson                 vece = MO_32;
38534e186175SRichard Henderson             }
38544e186175SRichard Henderson 
38554e186175SRichard Henderson             tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val);
38560a6a8bc8SRichard Henderson         }
385740ae5c62SRichard Henderson         ts->mem_coherent = 0;
385840ae5c62SRichard Henderson         break;
385940ae5c62SRichard Henderson     case TEMP_VAL_MEM:
3860b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3861b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
386240ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
386340ae5c62SRichard Henderson         ts->mem_coherent = 1;
386440ae5c62SRichard Henderson         break;
386540ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
386640ae5c62SRichard Henderson     default:
3867732e89f4SRichard Henderson         g_assert_not_reached();
386840ae5c62SRichard Henderson     }
3869098859f1SRichard Henderson     set_temp_val_reg(s, ts, reg);
387040ae5c62SRichard Henderson }
387140ae5c62SRichard Henderson 
387259d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
3873e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
387459d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
38751ad80729SAurelien Jarno {
38762c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
3877eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
3878e01fa97dSRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts));
38791ad80729SAurelien Jarno }
38801ad80729SAurelien Jarno 
38819814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
3882641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
3883641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
3884641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
3885641d5fbeSbellard {
3886ac3b8891SRichard Henderson     int i, n;
3887641d5fbeSbellard 
3888ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
3889b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
3890641d5fbeSbellard     }
3891e5097dc8Sbellard }
3892e5097dc8Sbellard 
38933d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
38943d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
38953d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
38963d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
38973d5c5f87SAurelien Jarno {
3898ac3b8891SRichard Henderson     int i, n;
38993d5c5f87SAurelien Jarno 
3900ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
390112b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
390212b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
3903ee17db83SRichard Henderson                          || ts->kind == TEMP_FIXED
390412b9b11aSRichard Henderson                          || ts->mem_coherent);
39053d5c5f87SAurelien Jarno     }
39063d5c5f87SAurelien Jarno }
39073d5c5f87SAurelien Jarno 
3908e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
3909e8996ee0Sbellard    all globals are stored at their canonical location. */
3910e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
3911e5097dc8Sbellard {
3912e5097dc8Sbellard     int i;
3913e5097dc8Sbellard 
3914c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
3915b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
3916c0522136SRichard Henderson 
3917c0522136SRichard Henderson         switch (ts->kind) {
3918f57c6915SRichard Henderson         case TEMP_TB:
3919b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
3920c0522136SRichard Henderson             break;
3921c7482438SRichard Henderson         case TEMP_EBB:
39222c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
3923eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
3924eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3925c0522136SRichard Henderson             break;
3926c0522136SRichard Henderson         case TEMP_CONST:
3927c0522136SRichard Henderson             /* Similarly, we should have freed any allocated register. */
3928c0522136SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_CONST);
3929c0522136SRichard Henderson             break;
3930c0522136SRichard Henderson         default:
3931c0522136SRichard Henderson             g_assert_not_reached();
3932c896fe29Sbellard         }
3933641d5fbeSbellard     }
3934e8996ee0Sbellard 
3935e8996ee0Sbellard     save_globals(s, allocated_regs);
3936c896fe29Sbellard }
3937c896fe29Sbellard 
3938bab1671fSRichard Henderson /*
3939c7482438SRichard Henderson  * At a conditional branch, we assume all temporaries are dead unless
3940c7482438SRichard Henderson  * explicitly live-across-conditional-branch; all globals and local
3941c7482438SRichard Henderson  * temps are synced to their location.
3942b4cb76e6SRichard Henderson  */
3943b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
3944b4cb76e6SRichard Henderson {
3945b4cb76e6SRichard Henderson     sync_globals(s, allocated_regs);
3946b4cb76e6SRichard Henderson 
3947b4cb76e6SRichard Henderson     for (int i = s->nb_globals; i < s->nb_temps; i++) {
3948b4cb76e6SRichard Henderson         TCGTemp *ts = &s->temps[i];
3949b4cb76e6SRichard Henderson         /*
3950b4cb76e6SRichard Henderson          * The liveness analysis already ensures that temps are dead.
3951b4cb76e6SRichard Henderson          * Keep tcg_debug_asserts for safety.
3952b4cb76e6SRichard Henderson          */
3953c0522136SRichard Henderson         switch (ts->kind) {
3954f57c6915SRichard Henderson         case TEMP_TB:
3955b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
3956c0522136SRichard Henderson             break;
3957c7482438SRichard Henderson         case TEMP_EBB:
3958c0522136SRichard Henderson         case TEMP_CONST:
3959c0522136SRichard Henderson             break;
3960c0522136SRichard Henderson         default:
3961c0522136SRichard Henderson             g_assert_not_reached();
3962b4cb76e6SRichard Henderson         }
3963b4cb76e6SRichard Henderson     }
3964b4cb76e6SRichard Henderson }
3965b4cb76e6SRichard Henderson 
3966b4cb76e6SRichard Henderson /*
3967c58f4c97SRichard Henderson  * Specialized code generation for INDEX_op_mov_* with a constant.
3968bab1671fSRichard Henderson  */
39690fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
3970ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
3971ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
3972e8996ee0Sbellard {
3973d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3974e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
397559d7c14eSRichard Henderson 
397659d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
3977098859f1SRichard Henderson     set_temp_val_nonreg(s, ots, TEMP_VAL_CONST);
3978e8996ee0Sbellard     ots->val = val;
397959d7c14eSRichard Henderson     ots->mem_coherent = 0;
3980ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
3981ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
398259d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
3983f8bf00f1SRichard Henderson         temp_dead(s, ots);
39844c4e1ab2SAurelien Jarno     }
3985e8996ee0Sbellard }
3986e8996ee0Sbellard 
3987bab1671fSRichard Henderson /*
3988bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
3989bab1671fSRichard Henderson  */
3990dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
3991c896fe29Sbellard {
3992dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
399369e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
3994c896fe29Sbellard     TCGTemp *ts, *ots;
3995450445d5SRichard Henderson     TCGType otype, itype;
3996098859f1SRichard Henderson     TCGReg oreg, ireg;
3997c896fe29Sbellard 
3998d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
399931fd884bSRichard Henderson     preferred_regs = output_pref(op, 0);
400043439139SRichard Henderson     ots = arg_temp(op->args[0]);
400143439139SRichard Henderson     ts = arg_temp(op->args[1]);
4002450445d5SRichard Henderson 
4003d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
4004e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4005d63e3b6eSRichard Henderson 
4006450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
4007450445d5SRichard Henderson     otype = ots->type;
4008450445d5SRichard Henderson     itype = ts->type;
4009c896fe29Sbellard 
40100fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
40110fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
40120fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
40130fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
40140fe4fca4SPaolo Bonzini             temp_dead(s, ts);
40150fe4fca4SPaolo Bonzini         }
401669e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
40170fe4fca4SPaolo Bonzini         return;
40180fe4fca4SPaolo Bonzini     }
40190fe4fca4SPaolo Bonzini 
40200fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
40210fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
40220fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
40230fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
40240fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
402569e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
402669e3706dSRichard Henderson                   allocated_regs, preferred_regs);
4027c29c1d7eSAurelien Jarno     }
40280fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
4029098859f1SRichard Henderson     ireg = ts->reg;
4030098859f1SRichard Henderson 
4031d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
4032c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
4033c29c1d7eSAurelien Jarno            liveness analysis disabled). */
4034eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
4035c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
40362272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
4037c29c1d7eSAurelien Jarno         }
4038098859f1SRichard Henderson         tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset);
4039c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
4040f8bf00f1SRichard Henderson             temp_dead(s, ts);
4041c29c1d7eSAurelien Jarno         }
4042f8bf00f1SRichard Henderson         temp_dead(s, ots);
4043098859f1SRichard Henderson         return;
4044098859f1SRichard Henderson     }
4045098859f1SRichard Henderson 
4046ee17db83SRichard Henderson     if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) {
4047098859f1SRichard Henderson         /*
4048098859f1SRichard Henderson          * The mov can be suppressed.  Kill input first, so that it
4049098859f1SRichard Henderson          * is unlinked from reg_to_temp, then set the output to the
4050098859f1SRichard Henderson          * reg that we saved from the input.
4051098859f1SRichard Henderson          */
4052f8bf00f1SRichard Henderson         temp_dead(s, ts);
4053098859f1SRichard Henderson         oreg = ireg;
4054c29c1d7eSAurelien Jarno     } else {
4055098859f1SRichard Henderson         if (ots->val_type == TEMP_VAL_REG) {
4056098859f1SRichard Henderson             oreg = ots->reg;
4057098859f1SRichard Henderson         } else {
4058098859f1SRichard Henderson             /* Make sure to not spill the input register during allocation. */
4059098859f1SRichard Henderson             oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
4060098859f1SRichard Henderson                                  allocated_regs | ((TCGRegSet)1 << ireg),
4061098859f1SRichard Henderson                                  preferred_regs, ots->indirect_base);
4062c29c1d7eSAurelien Jarno         }
4063098859f1SRichard Henderson         if (!tcg_out_mov(s, otype, oreg, ireg)) {
4064240c08d0SRichard Henderson             /*
4065240c08d0SRichard Henderson              * Cross register class move not supported.
4066240c08d0SRichard Henderson              * Store the source register into the destination slot
4067240c08d0SRichard Henderson              * and leave the destination temp as TEMP_VAL_MEM.
4068240c08d0SRichard Henderson              */
4069e01fa97dSRichard Henderson             assert(!temp_readonly(ots));
4070240c08d0SRichard Henderson             if (!ts->mem_allocated) {
4071240c08d0SRichard Henderson                 temp_allocate_frame(s, ots);
4072240c08d0SRichard Henderson             }
4073098859f1SRichard Henderson             tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset);
4074098859f1SRichard Henderson             set_temp_val_nonreg(s, ts, TEMP_VAL_MEM);
4075240c08d0SRichard Henderson             ots->mem_coherent = 1;
4076240c08d0SRichard Henderson             return;
407778113e83SRichard Henderson         }
4078c29c1d7eSAurelien Jarno     }
4079098859f1SRichard Henderson     set_temp_val_reg(s, ots, oreg);
4080c896fe29Sbellard     ots->mem_coherent = 0;
4081098859f1SRichard Henderson 
4082ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
408398b4e186SRichard Henderson         temp_sync(s, ots, allocated_regs, 0, 0);
4084c29c1d7eSAurelien Jarno     }
4085ec7a869dSAurelien Jarno }
4086c896fe29Sbellard 
4087bab1671fSRichard Henderson /*
4088bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
4089bab1671fSRichard Henderson  */
4090bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
4091bab1671fSRichard Henderson {
4092bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
4093bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
4094bab1671fSRichard Henderson     TCGTemp *its, *ots;
4095bab1671fSRichard Henderson     TCGType itype, vtype;
4096bab1671fSRichard Henderson     unsigned vece;
409731c96417SRichard Henderson     int lowpart_ofs;
4098bab1671fSRichard Henderson     bool ok;
4099bab1671fSRichard Henderson 
4100bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
4101bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
4102bab1671fSRichard Henderson 
4103bab1671fSRichard Henderson     /* ENV should not be modified.  */
4104e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4105bab1671fSRichard Henderson 
4106bab1671fSRichard Henderson     itype = its->type;
4107bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
4108bab1671fSRichard Henderson     vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
4109bab1671fSRichard Henderson 
4110bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
4111bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
4112bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
4113bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
4114bab1671fSRichard Henderson             temp_dead(s, its);
4115bab1671fSRichard Henderson         }
411631fd884bSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0));
4117bab1671fSRichard Henderson         return;
4118bab1671fSRichard Henderson     }
4119bab1671fSRichard Henderson 
41209be0d080SRichard Henderson     dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
41219be0d080SRichard Henderson     dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs;
4122bab1671fSRichard Henderson 
4123bab1671fSRichard Henderson     /* Allocate the output register now.  */
4124bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
4125bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
4126098859f1SRichard Henderson         TCGReg oreg;
4127bab1671fSRichard Henderson 
4128bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
4129bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
4130bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
4131bab1671fSRichard Henderson         }
4132098859f1SRichard Henderson         oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
413331fd884bSRichard Henderson                              output_pref(op, 0), ots->indirect_base);
4134098859f1SRichard Henderson         set_temp_val_reg(s, ots, oreg);
4135bab1671fSRichard Henderson     }
4136bab1671fSRichard Henderson 
4137bab1671fSRichard Henderson     switch (its->val_type) {
4138bab1671fSRichard Henderson     case TEMP_VAL_REG:
4139bab1671fSRichard Henderson         /*
4140bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
4141bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
4142bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
4143bab1671fSRichard Henderson          */
4144bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
4145bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
4146bab1671fSRichard Henderson                 goto done;
4147bab1671fSRichard Henderson             }
4148bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
4149bab1671fSRichard Henderson         }
4150bab1671fSRichard Henderson         if (!its->mem_coherent) {
4151bab1671fSRichard Henderson             /*
4152bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
4153bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
4154bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
4155bab1671fSRichard Henderson              */
4156bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
4157bab1671fSRichard Henderson                 break;
4158bab1671fSRichard Henderson             }
4159bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
4160bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
4161bab1671fSRichard Henderson         }
4162bab1671fSRichard Henderson         /* fall through */
4163bab1671fSRichard Henderson 
4164bab1671fSRichard Henderson     case TEMP_VAL_MEM:
416531c96417SRichard Henderson         lowpart_ofs = 0;
416631c96417SRichard Henderson         if (HOST_BIG_ENDIAN) {
416731c96417SRichard Henderson             lowpart_ofs = tcg_type_size(itype) - (1 << vece);
416831c96417SRichard Henderson         }
4169d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
417031c96417SRichard Henderson                              its->mem_offset + lowpart_ofs)) {
4171d6ecb4a9SRichard Henderson             goto done;
4172d6ecb4a9SRichard Henderson         }
4173098859f1SRichard Henderson         /* Load the input into the destination vector register. */
4174bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
4175bab1671fSRichard Henderson         break;
4176bab1671fSRichard Henderson 
4177bab1671fSRichard Henderson     default:
4178bab1671fSRichard Henderson         g_assert_not_reached();
4179bab1671fSRichard Henderson     }
4180bab1671fSRichard Henderson 
4181bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
4182bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
4183bab1671fSRichard Henderson     tcg_debug_assert(ok);
4184bab1671fSRichard Henderson 
4185bab1671fSRichard Henderson  done:
418636f5539cSRichard Henderson     ots->mem_coherent = 0;
4187bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
4188bab1671fSRichard Henderson         temp_dead(s, its);
4189bab1671fSRichard Henderson     }
4190bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
4191bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
4192bab1671fSRichard Henderson     }
4193bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
4194bab1671fSRichard Henderson         temp_dead(s, ots);
4195bab1671fSRichard Henderson     }
4196bab1671fSRichard Henderson }
4197bab1671fSRichard Henderson 
4198dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
4199c896fe29Sbellard {
4200dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
4201dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
420282790a87SRichard Henderson     TCGRegSet i_allocated_regs;
420382790a87SRichard Henderson     TCGRegSet o_allocated_regs;
4204b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
4205b6638662SRichard Henderson     TCGReg reg;
4206c896fe29Sbellard     TCGArg arg;
4207c896fe29Sbellard     const TCGArgConstraint *arg_ct;
4208c896fe29Sbellard     TCGTemp *ts;
4209c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
4210c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
4211c896fe29Sbellard 
4212c896fe29Sbellard     nb_oargs = def->nb_oargs;
4213c896fe29Sbellard     nb_iargs = def->nb_iargs;
4214c896fe29Sbellard 
4215c896fe29Sbellard     /* copy constants */
4216c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
4217dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
4218c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
4219c896fe29Sbellard 
4220d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
4221d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
422282790a87SRichard Henderson 
4223c896fe29Sbellard     /* satisfy input constraints */
4224c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
422529f5e925SRichard Henderson         TCGRegSet i_preferred_regs, i_required_regs;
422629f5e925SRichard Henderson         bool allocate_new_reg, copyto_new_reg;
422729f5e925SRichard Henderson         TCGTemp *ts2;
422829f5e925SRichard Henderson         int i1, i2;
4229d62816f2SRichard Henderson 
423066792f90SRichard Henderson         i = def->args_ct[nb_oargs + k].sort_index;
4231dd186292SRichard Henderson         arg = op->args[i];
4232c896fe29Sbellard         arg_ct = &def->args_ct[i];
423343439139SRichard Henderson         ts = arg_temp(arg);
423440ae5c62SRichard Henderson 
423540ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
4236a4fbbd77SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct->ct)) {
4237c896fe29Sbellard             /* constant is OK for instruction */
4238c896fe29Sbellard             const_args[i] = 1;
4239c896fe29Sbellard             new_args[i] = ts->val;
4240d62816f2SRichard Henderson             continue;
4241c896fe29Sbellard         }
424240ae5c62SRichard Henderson 
42431c1824dcSRichard Henderson         reg = ts->reg;
42441c1824dcSRichard Henderson         i_preferred_regs = 0;
424529f5e925SRichard Henderson         i_required_regs = arg_ct->regs;
42461c1824dcSRichard Henderson         allocate_new_reg = false;
424729f5e925SRichard Henderson         copyto_new_reg = false;
42481c1824dcSRichard Henderson 
424929f5e925SRichard Henderson         switch (arg_ct->pair) {
425029f5e925SRichard Henderson         case 0: /* not paired */
4251bc2b17e6SRichard Henderson             if (arg_ct->ialias) {
425231fd884bSRichard Henderson                 i_preferred_regs = output_pref(op, arg_ct->alias_index);
4253c0522136SRichard Henderson 
4254c0522136SRichard Henderson                 /*
4255c0522136SRichard Henderson                  * If the input is readonly, then it cannot also be an
4256c0522136SRichard Henderson                  * output and aliased to itself.  If the input is not
4257c0522136SRichard Henderson                  * dead after the instruction, we must allocate a new
4258c0522136SRichard Henderson                  * register and move it.
4259c0522136SRichard Henderson                  */
4260c0522136SRichard Henderson                 if (temp_readonly(ts) || !IS_DEAD_ARG(i)) {
42611c1824dcSRichard Henderson                     allocate_new_reg = true;
42621c1824dcSRichard Henderson                 } else if (ts->val_type == TEMP_VAL_REG) {
4263c0522136SRichard Henderson                     /*
42641c1824dcSRichard Henderson                      * Check if the current register has already been
42651c1824dcSRichard Henderson                      * allocated for another input.
4266c0522136SRichard Henderson                      */
426729f5e925SRichard Henderson                     allocate_new_reg =
426829f5e925SRichard Henderson                         tcg_regset_test_reg(i_allocated_regs, reg);
42697e1df267SAurelien Jarno                 }
42707e1df267SAurelien Jarno             }
42711c1824dcSRichard Henderson             if (!allocate_new_reg) {
427229f5e925SRichard Henderson                 temp_load(s, ts, i_required_regs, i_allocated_regs,
427329f5e925SRichard Henderson                           i_preferred_regs);
4274c896fe29Sbellard                 reg = ts->reg;
427529f5e925SRichard Henderson                 allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg);
42761c1824dcSRichard Henderson             }
42771c1824dcSRichard Henderson             if (allocate_new_reg) {
4278c0522136SRichard Henderson                 /*
4279c0522136SRichard Henderson                  * Allocate a new register matching the constraint
4280c0522136SRichard Henderson                  * and move the temporary register into it.
4281c0522136SRichard Henderson                  */
4282d62816f2SRichard Henderson                 temp_load(s, ts, tcg_target_available_regs[ts->type],
4283d62816f2SRichard Henderson                           i_allocated_regs, 0);
428429f5e925SRichard Henderson                 reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs,
42851c1824dcSRichard Henderson                                     i_preferred_regs, ts->indirect_base);
428629f5e925SRichard Henderson                 copyto_new_reg = true;
428729f5e925SRichard Henderson             }
428829f5e925SRichard Henderson             break;
428929f5e925SRichard Henderson 
429029f5e925SRichard Henderson         case 1:
429129f5e925SRichard Henderson             /* First of an input pair; if i1 == i2, the second is an output. */
429229f5e925SRichard Henderson             i1 = i;
429329f5e925SRichard Henderson             i2 = arg_ct->pair_index;
429429f5e925SRichard Henderson             ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL;
429529f5e925SRichard Henderson 
429629f5e925SRichard Henderson             /*
429729f5e925SRichard Henderson              * It is easier to default to allocating a new pair
429829f5e925SRichard Henderson              * and to identify a few cases where it's not required.
429929f5e925SRichard Henderson              */
430029f5e925SRichard Henderson             if (arg_ct->ialias) {
430131fd884bSRichard Henderson                 i_preferred_regs = output_pref(op, arg_ct->alias_index);
430229f5e925SRichard Henderson                 if (IS_DEAD_ARG(i1) &&
430329f5e925SRichard Henderson                     IS_DEAD_ARG(i2) &&
430429f5e925SRichard Henderson                     !temp_readonly(ts) &&
430529f5e925SRichard Henderson                     ts->val_type == TEMP_VAL_REG &&
430629f5e925SRichard Henderson                     ts->reg < TCG_TARGET_NB_REGS - 1 &&
430729f5e925SRichard Henderson                     tcg_regset_test_reg(i_required_regs, reg) &&
430829f5e925SRichard Henderson                     !tcg_regset_test_reg(i_allocated_regs, reg) &&
430929f5e925SRichard Henderson                     !tcg_regset_test_reg(i_allocated_regs, reg + 1) &&
431029f5e925SRichard Henderson                     (ts2
431129f5e925SRichard Henderson                      ? ts2->val_type == TEMP_VAL_REG &&
431229f5e925SRichard Henderson                        ts2->reg == reg + 1 &&
431329f5e925SRichard Henderson                        !temp_readonly(ts2)
431429f5e925SRichard Henderson                      : s->reg_to_temp[reg + 1] == NULL)) {
431529f5e925SRichard Henderson                     break;
431629f5e925SRichard Henderson                 }
431729f5e925SRichard Henderson             } else {
431829f5e925SRichard Henderson                 /* Without aliasing, the pair must also be an input. */
431929f5e925SRichard Henderson                 tcg_debug_assert(ts2);
432029f5e925SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG &&
432129f5e925SRichard Henderson                     ts2->val_type == TEMP_VAL_REG &&
432229f5e925SRichard Henderson                     ts2->reg == reg + 1 &&
432329f5e925SRichard Henderson                     tcg_regset_test_reg(i_required_regs, reg)) {
432429f5e925SRichard Henderson                     break;
432529f5e925SRichard Henderson                 }
432629f5e925SRichard Henderson             }
432729f5e925SRichard Henderson             reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs,
432829f5e925SRichard Henderson                                      0, ts->indirect_base);
432929f5e925SRichard Henderson             goto do_pair;
433029f5e925SRichard Henderson 
433129f5e925SRichard Henderson         case 2: /* pair second */
433229f5e925SRichard Henderson             reg = new_args[arg_ct->pair_index] + 1;
433329f5e925SRichard Henderson             goto do_pair;
433429f5e925SRichard Henderson 
433529f5e925SRichard Henderson         case 3: /* ialias with second output, no first input */
433629f5e925SRichard Henderson             tcg_debug_assert(arg_ct->ialias);
433731fd884bSRichard Henderson             i_preferred_regs = output_pref(op, arg_ct->alias_index);
433829f5e925SRichard Henderson 
433929f5e925SRichard Henderson             if (IS_DEAD_ARG(i) &&
434029f5e925SRichard Henderson                 !temp_readonly(ts) &&
434129f5e925SRichard Henderson                 ts->val_type == TEMP_VAL_REG &&
434229f5e925SRichard Henderson                 reg > 0 &&
434329f5e925SRichard Henderson                 s->reg_to_temp[reg - 1] == NULL &&
434429f5e925SRichard Henderson                 tcg_regset_test_reg(i_required_regs, reg) &&
434529f5e925SRichard Henderson                 !tcg_regset_test_reg(i_allocated_regs, reg) &&
434629f5e925SRichard Henderson                 !tcg_regset_test_reg(i_allocated_regs, reg - 1)) {
434729f5e925SRichard Henderson                 tcg_regset_set_reg(i_allocated_regs, reg - 1);
434829f5e925SRichard Henderson                 break;
434929f5e925SRichard Henderson             }
435029f5e925SRichard Henderson             reg = tcg_reg_alloc_pair(s, i_required_regs >> 1,
435129f5e925SRichard Henderson                                      i_allocated_regs, 0,
435229f5e925SRichard Henderson                                      ts->indirect_base);
435329f5e925SRichard Henderson             tcg_regset_set_reg(i_allocated_regs, reg);
435429f5e925SRichard Henderson             reg += 1;
435529f5e925SRichard Henderson             goto do_pair;
435629f5e925SRichard Henderson 
435729f5e925SRichard Henderson         do_pair:
435829f5e925SRichard Henderson             /*
435929f5e925SRichard Henderson              * If an aliased input is not dead after the instruction,
436029f5e925SRichard Henderson              * we must allocate a new register and move it.
436129f5e925SRichard Henderson              */
436229f5e925SRichard Henderson             if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) {
436329f5e925SRichard Henderson                 TCGRegSet t_allocated_regs = i_allocated_regs;
436429f5e925SRichard Henderson 
436529f5e925SRichard Henderson                 /*
436629f5e925SRichard Henderson                  * Because of the alias, and the continued life, make sure
436729f5e925SRichard Henderson                  * that the temp is somewhere *other* than the reg pair,
436829f5e925SRichard Henderson                  * and we get a copy in reg.
436929f5e925SRichard Henderson                  */
437029f5e925SRichard Henderson                 tcg_regset_set_reg(t_allocated_regs, reg);
437129f5e925SRichard Henderson                 tcg_regset_set_reg(t_allocated_regs, reg + 1);
437229f5e925SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) {
437329f5e925SRichard Henderson                     /* If ts was already in reg, copy it somewhere else. */
437429f5e925SRichard Henderson                     TCGReg nr;
437529f5e925SRichard Henderson                     bool ok;
437629f5e925SRichard Henderson 
437729f5e925SRichard Henderson                     tcg_debug_assert(ts->kind != TEMP_FIXED);
437829f5e925SRichard Henderson                     nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
437929f5e925SRichard Henderson                                        t_allocated_regs, 0, ts->indirect_base);
438029f5e925SRichard Henderson                     ok = tcg_out_mov(s, ts->type, nr, reg);
438129f5e925SRichard Henderson                     tcg_debug_assert(ok);
438229f5e925SRichard Henderson 
438329f5e925SRichard Henderson                     set_temp_val_reg(s, ts, nr);
438429f5e925SRichard Henderson                 } else {
438529f5e925SRichard Henderson                     temp_load(s, ts, tcg_target_available_regs[ts->type],
438629f5e925SRichard Henderson                               t_allocated_regs, 0);
438729f5e925SRichard Henderson                     copyto_new_reg = true;
438829f5e925SRichard Henderson                 }
438929f5e925SRichard Henderson             } else {
439029f5e925SRichard Henderson                 /* Preferably allocate to reg, otherwise copy. */
439129f5e925SRichard Henderson                 i_required_regs = (TCGRegSet)1 << reg;
439229f5e925SRichard Henderson                 temp_load(s, ts, i_required_regs, i_allocated_regs,
439329f5e925SRichard Henderson                           i_preferred_regs);
439429f5e925SRichard Henderson                 copyto_new_reg = ts->reg != reg;
439529f5e925SRichard Henderson             }
439629f5e925SRichard Henderson             break;
439729f5e925SRichard Henderson 
439829f5e925SRichard Henderson         default:
439929f5e925SRichard Henderson             g_assert_not_reached();
440029f5e925SRichard Henderson         }
440129f5e925SRichard Henderson 
440229f5e925SRichard Henderson         if (copyto_new_reg) {
440378113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4404240c08d0SRichard Henderson                 /*
4405240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
4406240c08d0SRichard Henderson                  * temp back to its slot and load from there.
4407240c08d0SRichard Henderson                  */
4408240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
4409240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
4410240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
441178113e83SRichard Henderson             }
4412c896fe29Sbellard         }
4413c896fe29Sbellard         new_args[i] = reg;
4414c896fe29Sbellard         const_args[i] = 0;
441582790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
4416c896fe29Sbellard     }
4417c896fe29Sbellard 
4418c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
4419866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
4420866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
442143439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4422c896fe29Sbellard         }
4423c896fe29Sbellard     }
4424c896fe29Sbellard 
4425b4cb76e6SRichard Henderson     if (def->flags & TCG_OPF_COND_BRANCH) {
4426b4cb76e6SRichard Henderson         tcg_reg_alloc_cbranch(s, i_allocated_regs);
4427b4cb76e6SRichard Henderson     } else if (def->flags & TCG_OPF_BB_END) {
442882790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
4429a52ad07eSAurelien Jarno     } else {
4430c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
4431b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
4432c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4433c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
443482790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
4435c896fe29Sbellard                 }
4436c896fe29Sbellard             }
44373d5c5f87SAurelien Jarno         }
44383d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
44393d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
44403d5c5f87SAurelien Jarno                an exception. */
444182790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
4442c896fe29Sbellard         }
4443c896fe29Sbellard 
4444c896fe29Sbellard         /* satisfy the output constraints */
4445c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
444666792f90SRichard Henderson             i = def->args_ct[k].sort_index;
4447dd186292SRichard Henderson             arg = op->args[i];
4448c896fe29Sbellard             arg_ct = &def->args_ct[i];
444943439139SRichard Henderson             ts = arg_temp(arg);
4450d63e3b6eSRichard Henderson 
4451d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
4452e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
4453d63e3b6eSRichard Henderson 
445429f5e925SRichard Henderson             switch (arg_ct->pair) {
445529f5e925SRichard Henderson             case 0: /* not paired */
4456bc2b17e6SRichard Henderson                 if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
44575ff9d6a4Sbellard                     reg = new_args[arg_ct->alias_index];
4458bc2b17e6SRichard Henderson                 } else if (arg_ct->newreg) {
44599be0d080SRichard Henderson                     reg = tcg_reg_alloc(s, arg_ct->regs,
446082790a87SRichard Henderson                                         i_allocated_regs | o_allocated_regs,
446131fd884bSRichard Henderson                                         output_pref(op, k), ts->indirect_base);
4462c896fe29Sbellard                 } else {
44639be0d080SRichard Henderson                     reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
446431fd884bSRichard Henderson                                         output_pref(op, k), ts->indirect_base);
4465c896fe29Sbellard                 }
446629f5e925SRichard Henderson                 break;
446729f5e925SRichard Henderson 
446829f5e925SRichard Henderson             case 1: /* first of pair */
446929f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
447029f5e925SRichard Henderson                 if (arg_ct->oalias) {
447129f5e925SRichard Henderson                     reg = new_args[arg_ct->alias_index];
447229f5e925SRichard Henderson                     break;
447329f5e925SRichard Henderson                 }
447429f5e925SRichard Henderson                 reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs,
447531fd884bSRichard Henderson                                          output_pref(op, k), ts->indirect_base);
447629f5e925SRichard Henderson                 break;
447729f5e925SRichard Henderson 
447829f5e925SRichard Henderson             case 2: /* second of pair */
447929f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
448029f5e925SRichard Henderson                 if (arg_ct->oalias) {
448129f5e925SRichard Henderson                     reg = new_args[arg_ct->alias_index];
448229f5e925SRichard Henderson                 } else {
448329f5e925SRichard Henderson                     reg = new_args[arg_ct->pair_index] + 1;
448429f5e925SRichard Henderson                 }
448529f5e925SRichard Henderson                 break;
448629f5e925SRichard Henderson 
448729f5e925SRichard Henderson             case 3: /* first of pair, aliasing with a second input */
448829f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
448929f5e925SRichard Henderson                 reg = new_args[arg_ct->pair_index] - 1;
449029f5e925SRichard Henderson                 break;
449129f5e925SRichard Henderson 
449229f5e925SRichard Henderson             default:
449329f5e925SRichard Henderson                 g_assert_not_reached();
449429f5e925SRichard Henderson             }
449582790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
4496098859f1SRichard Henderson             set_temp_val_reg(s, ts, reg);
4497c896fe29Sbellard             ts->mem_coherent = 0;
4498c896fe29Sbellard             new_args[i] = reg;
4499c896fe29Sbellard         }
4500e8996ee0Sbellard     }
4501c896fe29Sbellard 
4502c896fe29Sbellard     /* emit instruction */
4503678155b2SRichard Henderson     switch (op->opc) {
4504678155b2SRichard Henderson     case INDEX_op_ext8s_i32:
4505678155b2SRichard Henderson         tcg_out_ext8s(s, TCG_TYPE_I32, new_args[0], new_args[1]);
4506678155b2SRichard Henderson         break;
4507678155b2SRichard Henderson     case INDEX_op_ext8s_i64:
4508678155b2SRichard Henderson         tcg_out_ext8s(s, TCG_TYPE_I64, new_args[0], new_args[1]);
4509678155b2SRichard Henderson         break;
4510d0e66c89SRichard Henderson     case INDEX_op_ext8u_i32:
4511d0e66c89SRichard Henderson     case INDEX_op_ext8u_i64:
4512d0e66c89SRichard Henderson         tcg_out_ext8u(s, new_args[0], new_args[1]);
4513d0e66c89SRichard Henderson         break;
4514753e42eaSRichard Henderson     case INDEX_op_ext16s_i32:
4515753e42eaSRichard Henderson         tcg_out_ext16s(s, TCG_TYPE_I32, new_args[0], new_args[1]);
4516753e42eaSRichard Henderson         break;
4517753e42eaSRichard Henderson     case INDEX_op_ext16s_i64:
4518753e42eaSRichard Henderson         tcg_out_ext16s(s, TCG_TYPE_I64, new_args[0], new_args[1]);
4519753e42eaSRichard Henderson         break;
4520*379afdffSRichard Henderson     case INDEX_op_ext16u_i32:
4521*379afdffSRichard Henderson     case INDEX_op_ext16u_i64:
4522*379afdffSRichard Henderson         tcg_out_ext16u(s, new_args[0], new_args[1]);
4523*379afdffSRichard Henderson         break;
4524678155b2SRichard Henderson     default:
4525d2fd745fSRichard Henderson         if (def->flags & TCG_OPF_VECTOR) {
4526d2fd745fSRichard Henderson             tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
4527d2fd745fSRichard Henderson                            new_args, const_args);
4528d2fd745fSRichard Henderson         } else {
4529dd186292SRichard Henderson             tcg_out_op(s, op->opc, new_args, const_args);
4530d2fd745fSRichard Henderson         }
4531678155b2SRichard Henderson         break;
4532678155b2SRichard Henderson     }
4533c896fe29Sbellard 
4534c896fe29Sbellard     /* move the outputs in the correct register if needed */
4535c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
453643439139SRichard Henderson         ts = arg_temp(op->args[i]);
4537d63e3b6eSRichard Henderson 
4538d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
4539e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
4540d63e3b6eSRichard Henderson 
4541ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
454298b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
454359d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4544f8bf00f1SRichard Henderson             temp_dead(s, ts);
4545ec7a869dSAurelien Jarno         }
4546c896fe29Sbellard     }
4547c896fe29Sbellard }
4548c896fe29Sbellard 
4549efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op)
4550efe86b21SRichard Henderson {
4551efe86b21SRichard Henderson     const TCGLifeData arg_life = op->life;
4552efe86b21SRichard Henderson     TCGTemp *ots, *itsl, *itsh;
4553efe86b21SRichard Henderson     TCGType vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
4554efe86b21SRichard Henderson 
4555efe86b21SRichard Henderson     /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */
4556efe86b21SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 32);
4557efe86b21SRichard Henderson     tcg_debug_assert(TCGOP_VECE(op) == MO_64);
4558efe86b21SRichard Henderson 
4559efe86b21SRichard Henderson     ots = arg_temp(op->args[0]);
4560efe86b21SRichard Henderson     itsl = arg_temp(op->args[1]);
4561efe86b21SRichard Henderson     itsh = arg_temp(op->args[2]);
4562efe86b21SRichard Henderson 
4563efe86b21SRichard Henderson     /* ENV should not be modified.  */
4564efe86b21SRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4565efe86b21SRichard Henderson 
4566efe86b21SRichard Henderson     /* Allocate the output register now.  */
4567efe86b21SRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
4568efe86b21SRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
4569efe86b21SRichard Henderson         TCGRegSet dup_out_regs =
4570efe86b21SRichard Henderson             tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
4571098859f1SRichard Henderson         TCGReg oreg;
4572efe86b21SRichard Henderson 
4573efe86b21SRichard Henderson         /* Make sure to not spill the input registers. */
4574efe86b21SRichard Henderson         if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) {
4575efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsl->reg);
4576efe86b21SRichard Henderson         }
4577efe86b21SRichard Henderson         if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) {
4578efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsh->reg);
4579efe86b21SRichard Henderson         }
4580efe86b21SRichard Henderson 
4581098859f1SRichard Henderson         oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
458231fd884bSRichard Henderson                              output_pref(op, 0), ots->indirect_base);
4583098859f1SRichard Henderson         set_temp_val_reg(s, ots, oreg);
4584efe86b21SRichard Henderson     }
4585efe86b21SRichard Henderson 
4586efe86b21SRichard Henderson     /* Promote dup2 of immediates to dupi_vec. */
4587efe86b21SRichard Henderson     if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) {
4588efe86b21SRichard Henderson         uint64_t val = deposit64(itsl->val, 32, 32, itsh->val);
4589efe86b21SRichard Henderson         MemOp vece = MO_64;
4590efe86b21SRichard Henderson 
4591efe86b21SRichard Henderson         if (val == dup_const(MO_8, val)) {
4592efe86b21SRichard Henderson             vece = MO_8;
4593efe86b21SRichard Henderson         } else if (val == dup_const(MO_16, val)) {
4594efe86b21SRichard Henderson             vece = MO_16;
4595efe86b21SRichard Henderson         } else if (val == dup_const(MO_32, val)) {
4596efe86b21SRichard Henderson             vece = MO_32;
4597efe86b21SRichard Henderson         }
4598efe86b21SRichard Henderson 
4599efe86b21SRichard Henderson         tcg_out_dupi_vec(s, vtype, vece, ots->reg, val);
4600efe86b21SRichard Henderson         goto done;
4601efe86b21SRichard Henderson     }
4602efe86b21SRichard Henderson 
4603efe86b21SRichard Henderson     /* If the two inputs form one 64-bit value, try dupm_vec. */
4604aef85402SRichard Henderson     if (itsl->temp_subindex == HOST_BIG_ENDIAN &&
4605aef85402SRichard Henderson         itsh->temp_subindex == !HOST_BIG_ENDIAN &&
4606aef85402SRichard Henderson         itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) {
4607aef85402SRichard Henderson         TCGTemp *its = itsl - HOST_BIG_ENDIAN;
4608aef85402SRichard Henderson 
4609aef85402SRichard Henderson         temp_sync(s, its + 0, s->reserved_regs, 0, 0);
4610aef85402SRichard Henderson         temp_sync(s, its + 1, s->reserved_regs, 0, 0);
4611aef85402SRichard Henderson 
4612efe86b21SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg,
4613efe86b21SRichard Henderson                              its->mem_base->reg, its->mem_offset)) {
4614efe86b21SRichard Henderson             goto done;
4615efe86b21SRichard Henderson         }
4616efe86b21SRichard Henderson     }
4617efe86b21SRichard Henderson 
4618efe86b21SRichard Henderson     /* Fall back to generic expansion. */
4619efe86b21SRichard Henderson     return false;
4620efe86b21SRichard Henderson 
4621efe86b21SRichard Henderson  done:
462236f5539cSRichard Henderson     ots->mem_coherent = 0;
4623efe86b21SRichard Henderson     if (IS_DEAD_ARG(1)) {
4624efe86b21SRichard Henderson         temp_dead(s, itsl);
4625efe86b21SRichard Henderson     }
4626efe86b21SRichard Henderson     if (IS_DEAD_ARG(2)) {
4627efe86b21SRichard Henderson         temp_dead(s, itsh);
4628efe86b21SRichard Henderson     }
4629efe86b21SRichard Henderson     if (NEED_SYNC_ARG(0)) {
4630efe86b21SRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0));
4631efe86b21SRichard Henderson     } else if (IS_DEAD_ARG(0)) {
4632efe86b21SRichard Henderson         temp_dead(s, ots);
4633efe86b21SRichard Henderson     }
4634efe86b21SRichard Henderson     return true;
4635efe86b21SRichard Henderson }
4636efe86b21SRichard Henderson 
463739004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts,
463839004a71SRichard Henderson                          TCGRegSet allocated_regs)
4639c896fe29Sbellard {
4640c896fe29Sbellard     if (ts->val_type == TEMP_VAL_REG) {
4641c896fe29Sbellard         if (ts->reg != reg) {
46424250da10SRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
464378113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4644240c08d0SRichard Henderson                 /*
4645240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
4646240c08d0SRichard Henderson                  * temp back to its slot and load from there.
4647240c08d0SRichard Henderson                  */
4648240c08d0SRichard Henderson                 temp_sync(s, ts, allocated_regs, 0, 0);
4649240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
4650240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
465178113e83SRichard Henderson             }
4652c896fe29Sbellard         }
4653c896fe29Sbellard     } else {
4654ccb1bb66SRichard Henderson         TCGRegSet arg_set = 0;
465540ae5c62SRichard Henderson 
46564250da10SRichard Henderson         tcg_reg_free(s, reg, allocated_regs);
465740ae5c62SRichard Henderson         tcg_regset_set_reg(arg_set, reg);
4658b722452aSRichard Henderson         temp_load(s, ts, arg_set, allocated_regs, 0);
4659c896fe29Sbellard     }
466039004a71SRichard Henderson }
466140ae5c62SRichard Henderson 
466239004a71SRichard Henderson static void load_arg_stk(TCGContext *s, int stk_slot, TCGTemp *ts,
466339004a71SRichard Henderson                          TCGRegSet allocated_regs)
466439004a71SRichard Henderson {
466539004a71SRichard Henderson     /*
466639004a71SRichard Henderson      * When the destination is on the stack, load up the temp and store.
466739004a71SRichard Henderson      * If there are many call-saved registers, the temp might live to
466839004a71SRichard Henderson      * see another use; otherwise it'll be discarded.
466939004a71SRichard Henderson      */
467039004a71SRichard Henderson     temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0);
467139004a71SRichard Henderson     tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK,
467239004a71SRichard Henderson                TCG_TARGET_CALL_STACK_OFFSET +
467339004a71SRichard Henderson                stk_slot * sizeof(tcg_target_long));
467439004a71SRichard Henderson }
467539004a71SRichard Henderson 
467639004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l,
467739004a71SRichard Henderson                             TCGTemp *ts, TCGRegSet *allocated_regs)
467839004a71SRichard Henderson {
467939004a71SRichard Henderson     if (REG_P(l)) {
468039004a71SRichard Henderson         TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot];
468139004a71SRichard Henderson         load_arg_reg(s, reg, ts, *allocated_regs);
468239004a71SRichard Henderson         tcg_regset_set_reg(*allocated_regs, reg);
468339004a71SRichard Henderson     } else {
468439004a71SRichard Henderson         load_arg_stk(s, l->arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs),
468539004a71SRichard Henderson                      ts, *allocated_regs);
4686c896fe29Sbellard     }
468739cf05d3Sbellard }
4688c896fe29Sbellard 
4689313bdea8SRichard Henderson static void load_arg_ref(TCGContext *s, int arg_slot, TCGReg ref_base,
4690313bdea8SRichard Henderson                          intptr_t ref_off, TCGRegSet *allocated_regs)
4691313bdea8SRichard Henderson {
4692313bdea8SRichard Henderson     TCGReg reg;
4693313bdea8SRichard Henderson     int stk_slot = arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs);
4694313bdea8SRichard Henderson 
4695313bdea8SRichard Henderson     if (stk_slot < 0) {
4696313bdea8SRichard Henderson         reg = tcg_target_call_iarg_regs[arg_slot];
4697313bdea8SRichard Henderson         tcg_reg_free(s, reg, *allocated_regs);
4698313bdea8SRichard Henderson         tcg_out_addi_ptr(s, reg, ref_base, ref_off);
4699313bdea8SRichard Henderson         tcg_regset_set_reg(*allocated_regs, reg);
4700313bdea8SRichard Henderson     } else {
4701313bdea8SRichard Henderson         reg = tcg_reg_alloc(s, tcg_target_available_regs[TCG_TYPE_PTR],
4702313bdea8SRichard Henderson                             *allocated_regs, 0, false);
4703313bdea8SRichard Henderson         tcg_out_addi_ptr(s, reg, ref_base, ref_off);
4704313bdea8SRichard Henderson         tcg_out_st(s, TCG_TYPE_PTR, reg, TCG_REG_CALL_STACK,
4705313bdea8SRichard Henderson                    TCG_TARGET_CALL_STACK_OFFSET
4706313bdea8SRichard Henderson                    + stk_slot * sizeof(tcg_target_long));
4707313bdea8SRichard Henderson     }
4708313bdea8SRichard Henderson }
4709313bdea8SRichard Henderson 
471039004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
471139004a71SRichard Henderson {
471239004a71SRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
471339004a71SRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
471439004a71SRichard Henderson     const TCGLifeData arg_life = op->life;
471539004a71SRichard Henderson     const TCGHelperInfo *info = tcg_call_info(op);
471639004a71SRichard Henderson     TCGRegSet allocated_regs = s->reserved_regs;
471739004a71SRichard Henderson     int i;
471839004a71SRichard Henderson 
471939004a71SRichard Henderson     /*
472039004a71SRichard Henderson      * Move inputs into place in reverse order,
472139004a71SRichard Henderson      * so that we place stacked arguments first.
472239004a71SRichard Henderson      */
472339004a71SRichard Henderson     for (i = nb_iargs - 1; i >= 0; --i) {
472439004a71SRichard Henderson         const TCGCallArgumentLoc *loc = &info->in[i];
472539004a71SRichard Henderson         TCGTemp *ts = arg_temp(op->args[nb_oargs + i]);
472639004a71SRichard Henderson 
472739004a71SRichard Henderson         switch (loc->kind) {
472839004a71SRichard Henderson         case TCG_CALL_ARG_NORMAL:
472939004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
473039004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
473139004a71SRichard Henderson             load_arg_normal(s, loc, ts, &allocated_regs);
473239004a71SRichard Henderson             break;
4733313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF:
4734313bdea8SRichard Henderson             load_arg_stk(s, loc->ref_slot, ts, allocated_regs);
4735313bdea8SRichard Henderson             load_arg_ref(s, loc->arg_slot, TCG_REG_CALL_STACK,
4736313bdea8SRichard Henderson                          TCG_TARGET_CALL_STACK_OFFSET
4737313bdea8SRichard Henderson                          + loc->ref_slot * sizeof(tcg_target_long),
4738313bdea8SRichard Henderson                          &allocated_regs);
4739313bdea8SRichard Henderson             break;
4740313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF_N:
4741313bdea8SRichard Henderson             load_arg_stk(s, loc->ref_slot, ts, allocated_regs);
4742313bdea8SRichard Henderson             break;
474339004a71SRichard Henderson         default:
474439004a71SRichard Henderson             g_assert_not_reached();
474539004a71SRichard Henderson         }
474639004a71SRichard Henderson     }
474739004a71SRichard Henderson 
474839004a71SRichard Henderson     /* Mark dead temporaries and free the associated registers.  */
4749866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4750866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
475143439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4752c896fe29Sbellard         }
4753c896fe29Sbellard     }
4754c896fe29Sbellard 
475539004a71SRichard Henderson     /* Clobber call registers.  */
4756c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4757c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
4758b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
4759c896fe29Sbellard         }
4760c896fe29Sbellard     }
4761c896fe29Sbellard 
476239004a71SRichard Henderson     /*
476339004a71SRichard Henderson      * Save globals if they might be written by the helper,
476439004a71SRichard Henderson      * sync them if they might be read.
476539004a71SRichard Henderson      */
476639004a71SRichard Henderson     if (info->flags & TCG_CALL_NO_READ_GLOBALS) {
476778505279SAurelien Jarno         /* Nothing to do */
476839004a71SRichard Henderson     } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) {
476978505279SAurelien Jarno         sync_globals(s, allocated_regs);
477078505279SAurelien Jarno     } else {
4771e8996ee0Sbellard         save_globals(s, allocated_regs);
4772b9c18f56Saurel32     }
4773c896fe29Sbellard 
4774313bdea8SRichard Henderson     /*
4775313bdea8SRichard Henderson      * If the ABI passes a pointer to the returned struct as the first
4776313bdea8SRichard Henderson      * argument, load that now.  Pass a pointer to the output home slot.
4777313bdea8SRichard Henderson      */
4778313bdea8SRichard Henderson     if (info->out_kind == TCG_CALL_RET_BY_REF) {
4779313bdea8SRichard Henderson         TCGTemp *ts = arg_temp(op->args[0]);
4780313bdea8SRichard Henderson 
4781313bdea8SRichard Henderson         if (!ts->mem_allocated) {
4782313bdea8SRichard Henderson             temp_allocate_frame(s, ts);
4783313bdea8SRichard Henderson         }
4784313bdea8SRichard Henderson         load_arg_ref(s, 0, ts->mem_base->reg, ts->mem_offset, &allocated_regs);
4785313bdea8SRichard Henderson     }
4786313bdea8SRichard Henderson 
4787cee44b03SRichard Henderson     tcg_out_call(s, tcg_call_func(op), info);
4788c896fe29Sbellard 
478939004a71SRichard Henderson     /* Assign output registers and emit moves if needed.  */
479039004a71SRichard Henderson     switch (info->out_kind) {
479139004a71SRichard Henderson     case TCG_CALL_RET_NORMAL:
4792c896fe29Sbellard         for (i = 0; i < nb_oargs; i++) {
479339004a71SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
47945e3d0c19SRichard Henderson             TCGReg reg = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, i);
4795d63e3b6eSRichard Henderson 
4796d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
4797e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
4798d63e3b6eSRichard Henderson 
4799098859f1SRichard Henderson             set_temp_val_reg(s, ts, reg);
4800c896fe29Sbellard             ts->mem_coherent = 0;
480139004a71SRichard Henderson         }
480239004a71SRichard Henderson         break;
4803313bdea8SRichard Henderson 
4804c6556aa0SRichard Henderson     case TCG_CALL_RET_BY_VEC:
4805c6556aa0SRichard Henderson         {
4806c6556aa0SRichard Henderson             TCGTemp *ts = arg_temp(op->args[0]);
4807c6556aa0SRichard Henderson 
4808c6556aa0SRichard Henderson             tcg_debug_assert(ts->base_type == TCG_TYPE_I128);
4809c6556aa0SRichard Henderson             tcg_debug_assert(ts->temp_subindex == 0);
4810c6556aa0SRichard Henderson             if (!ts->mem_allocated) {
4811c6556aa0SRichard Henderson                 temp_allocate_frame(s, ts);
4812c6556aa0SRichard Henderson             }
4813c6556aa0SRichard Henderson             tcg_out_st(s, TCG_TYPE_V128,
4814c6556aa0SRichard Henderson                        tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0),
4815c6556aa0SRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
4816c6556aa0SRichard Henderson         }
4817c6556aa0SRichard Henderson         /* fall through to mark all parts in memory */
4818c6556aa0SRichard Henderson 
4819313bdea8SRichard Henderson     case TCG_CALL_RET_BY_REF:
4820313bdea8SRichard Henderson         /* The callee has performed a write through the reference. */
4821313bdea8SRichard Henderson         for (i = 0; i < nb_oargs; i++) {
4822313bdea8SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
4823313bdea8SRichard Henderson             ts->val_type = TEMP_VAL_MEM;
4824313bdea8SRichard Henderson         }
4825313bdea8SRichard Henderson         break;
4826313bdea8SRichard Henderson 
482739004a71SRichard Henderson     default:
482839004a71SRichard Henderson         g_assert_not_reached();
482939004a71SRichard Henderson     }
483039004a71SRichard Henderson 
483139004a71SRichard Henderson     /* Flush or discard output registers as needed. */
483239004a71SRichard Henderson     for (i = 0; i < nb_oargs; i++) {
483339004a71SRichard Henderson         TCGTemp *ts = arg_temp(op->args[i]);
4834ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
483539004a71SRichard Henderson             temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i));
483659d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4837f8bf00f1SRichard Henderson             temp_dead(s, ts);
4838c896fe29Sbellard         }
4839c896fe29Sbellard     }
48408c11ad25SAurelien Jarno }
4841c896fe29Sbellard 
4842c896fe29Sbellard #ifdef CONFIG_PROFILER
4843c896fe29Sbellard 
4844c3fac113SEmilio G. Cota /* avoid copy/paste errors */
4845c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field)                       \
4846c3fac113SEmilio G. Cota     do {                                                \
4847d73415a3SStefan Hajnoczi         (to)->field += qatomic_read(&((from)->field));  \
4848c3fac113SEmilio G. Cota     } while (0)
4849c896fe29Sbellard 
4850c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field)                                       \
4851c3fac113SEmilio G. Cota     do {                                                                \
4852d73415a3SStefan Hajnoczi         typeof((from)->field) val__ = qatomic_read(&((from)->field));   \
4853c3fac113SEmilio G. Cota         if (val__ > (to)->field) {                                      \
4854c3fac113SEmilio G. Cota             (to)->field = val__;                                        \
4855c3fac113SEmilio G. Cota         }                                                               \
4856c3fac113SEmilio G. Cota     } while (0)
4857c3fac113SEmilio G. Cota 
4858c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */
4859c3fac113SEmilio G. Cota static inline
4860c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
4861c896fe29Sbellard {
48620e2d61cfSRichard Henderson     unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
4863c3fac113SEmilio G. Cota     unsigned int i;
4864c3fac113SEmilio G. Cota 
48653468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4866d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
48673468b59eSEmilio G. Cota         const TCGProfile *orig = &s->prof;
4868c3fac113SEmilio G. Cota 
4869c3fac113SEmilio G. Cota         if (counters) {
487072fd2efbSEmilio G. Cota             PROF_ADD(prof, orig, cpu_exec_time);
4871c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count1);
4872c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count);
4873c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, op_count);
4874c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, op_count_max);
4875c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, temp_count);
4876c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, temp_count_max);
4877c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, del_op_count);
4878c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_in_len);
4879c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_out_len);
4880c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, search_out_len);
4881c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, interm_time);
4882c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_time);
4883c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, la_time);
4884c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, opt_time);
4885c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_count);
4886c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_time);
4887c3fac113SEmilio G. Cota         }
4888c3fac113SEmilio G. Cota         if (table) {
4889c896fe29Sbellard             int i;
4890d70724ceSzhanghailiang 
489115fc7daaSRichard Henderson             for (i = 0; i < NB_OPS; i++) {
4892c3fac113SEmilio G. Cota                 PROF_ADD(prof, orig, table_op_count[i]);
4893c3fac113SEmilio G. Cota             }
4894c3fac113SEmilio G. Cota         }
4895c3fac113SEmilio G. Cota     }
4896c3fac113SEmilio G. Cota }
4897c3fac113SEmilio G. Cota 
4898c3fac113SEmilio G. Cota #undef PROF_ADD
4899c3fac113SEmilio G. Cota #undef PROF_MAX
4900c3fac113SEmilio G. Cota 
4901c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof)
4902c3fac113SEmilio G. Cota {
4903c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, true, false);
4904c3fac113SEmilio G. Cota }
4905c3fac113SEmilio G. Cota 
4906c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof)
4907c3fac113SEmilio G. Cota {
4908c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, false, true);
4909c3fac113SEmilio G. Cota }
4910c3fac113SEmilio G. Cota 
4911b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf)
4912c3fac113SEmilio G. Cota {
4913c3fac113SEmilio G. Cota     TCGProfile prof = {};
4914c3fac113SEmilio G. Cota     int i;
4915c3fac113SEmilio G. Cota 
4916c3fac113SEmilio G. Cota     tcg_profile_snapshot_table(&prof);
4917c3fac113SEmilio G. Cota     for (i = 0; i < NB_OPS; i++) {
4918b6a7f3e0SDaniel P. Berrangé         g_string_append_printf(buf, "%s %" PRId64 "\n", tcg_op_defs[i].name,
4919c3fac113SEmilio G. Cota                                prof.table_op_count[i]);
4920c896fe29Sbellard     }
4921c896fe29Sbellard }
492272fd2efbSEmilio G. Cota 
492372fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
492472fd2efbSEmilio G. Cota {
49250e2d61cfSRichard Henderson     unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
492672fd2efbSEmilio G. Cota     unsigned int i;
492772fd2efbSEmilio G. Cota     int64_t ret = 0;
492872fd2efbSEmilio G. Cota 
492972fd2efbSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4930d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
493172fd2efbSEmilio G. Cota         const TCGProfile *prof = &s->prof;
493272fd2efbSEmilio G. Cota 
4933d73415a3SStefan Hajnoczi         ret += qatomic_read(&prof->cpu_exec_time);
493472fd2efbSEmilio G. Cota     }
493572fd2efbSEmilio G. Cota     return ret;
493672fd2efbSEmilio G. Cota }
4937246ae24dSMax Filippov #else
4938b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf)
4939246ae24dSMax Filippov {
4940b6a7f3e0SDaniel P. Berrangé     g_string_append_printf(buf, "[TCG profiler not compiled]\n");
4941246ae24dSMax Filippov }
494272fd2efbSEmilio G. Cota 
494372fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
494472fd2efbSEmilio G. Cota {
494572fd2efbSEmilio G. Cota     error_report("%s: TCG profiler not compiled", __func__);
494672fd2efbSEmilio G. Cota     exit(EXIT_FAILURE);
494772fd2efbSEmilio G. Cota }
4948c896fe29Sbellard #endif
4949c896fe29Sbellard 
4950c896fe29Sbellard 
4951fbf59aadSRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start)
4952c896fe29Sbellard {
4953c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER
4954c3fac113SEmilio G. Cota     TCGProfile *prof = &s->prof;
4955c3fac113SEmilio G. Cota #endif
495615fa08f8SRichard Henderson     int i, num_insns;
495715fa08f8SRichard Henderson     TCGOp *op;
4958c896fe29Sbellard 
495904fe6400SRichard Henderson #ifdef CONFIG_PROFILER
496004fe6400SRichard Henderson     {
4961c1f543b7SEmilio G. Cota         int n = 0;
496204fe6400SRichard Henderson 
496315fa08f8SRichard Henderson         QTAILQ_FOREACH(op, &s->ops, link) {
496415fa08f8SRichard Henderson             n++;
496515fa08f8SRichard Henderson         }
4966d73415a3SStefan Hajnoczi         qatomic_set(&prof->op_count, prof->op_count + n);
4967c3fac113SEmilio G. Cota         if (n > prof->op_count_max) {
4968d73415a3SStefan Hajnoczi             qatomic_set(&prof->op_count_max, n);
496904fe6400SRichard Henderson         }
497004fe6400SRichard Henderson 
497104fe6400SRichard Henderson         n = s->nb_temps;
4972d73415a3SStefan Hajnoczi         qatomic_set(&prof->temp_count, prof->temp_count + n);
4973c3fac113SEmilio G. Cota         if (n > prof->temp_count_max) {
4974d73415a3SStefan Hajnoczi             qatomic_set(&prof->temp_count_max, n);
497504fe6400SRichard Henderson         }
497604fe6400SRichard Henderson     }
497704fe6400SRichard Henderson #endif
497804fe6400SRichard Henderson 
4979c896fe29Sbellard #ifdef DEBUG_DISAS
4980d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
4981fbf59aadSRichard Henderson                  && qemu_log_in_addr_range(pc_start))) {
4982c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
498378b54858SRichard Henderson         if (logfile) {
498478b54858SRichard Henderson             fprintf(logfile, "OP:\n");
4985b7a83ff8SRichard Henderson             tcg_dump_ops(s, logfile, false);
498678b54858SRichard Henderson             fprintf(logfile, "\n");
4987fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
4988c896fe29Sbellard         }
498978b54858SRichard Henderson     }
4990c896fe29Sbellard #endif
4991c896fe29Sbellard 
4992bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
4993bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
4994bef16ab4SRichard Henderson     {
4995bef16ab4SRichard Henderson         TCGLabel *l;
4996bef16ab4SRichard Henderson         bool error = false;
4997bef16ab4SRichard Henderson 
4998bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
4999f85b1fc4SRichard Henderson             if (unlikely(!l->present) && !QSIMPLEQ_EMPTY(&l->branches)) {
5000bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
5001bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
5002bef16ab4SRichard Henderson                 error = true;
5003bef16ab4SRichard Henderson             }
5004bef16ab4SRichard Henderson         }
5005bef16ab4SRichard Henderson         assert(!error);
5006bef16ab4SRichard Henderson     }
5007bef16ab4SRichard Henderson #endif
5008bef16ab4SRichard Henderson 
5009c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
5010d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
5011c5cc28ffSAurelien Jarno #endif
5012c5cc28ffSAurelien Jarno 
50138f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
5014c45cb8bbSRichard Henderson     tcg_optimize(s);
50158f2e8c07SKirill Batuzov #endif
50168f2e8c07SKirill Batuzov 
5017a23a9ec6Sbellard #ifdef CONFIG_PROFILER
5018d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
5019d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time - profile_getclock());
5020a23a9ec6Sbellard #endif
5021c5cc28ffSAurelien Jarno 
5022b4fc67c7SRichard Henderson     reachable_code_pass(s);
5023874b8574SRichard Henderson     liveness_pass_0(s);
5024b83eabeaSRichard Henderson     liveness_pass_1(s);
50255a18407fSRichard Henderson 
50265a18407fSRichard Henderson     if (s->nb_indirects > 0) {
50275a18407fSRichard Henderson #ifdef DEBUG_DISAS
50285a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
5029fbf59aadSRichard Henderson                      && qemu_log_in_addr_range(pc_start))) {
5030c60f599bSRichard Henderson             FILE *logfile = qemu_log_trylock();
503178b54858SRichard Henderson             if (logfile) {
503278b54858SRichard Henderson                 fprintf(logfile, "OP before indirect lowering:\n");
5033b7a83ff8SRichard Henderson                 tcg_dump_ops(s, logfile, false);
503478b54858SRichard Henderson                 fprintf(logfile, "\n");
5035fc59d2d8SRobert Foley                 qemu_log_unlock(logfile);
50365a18407fSRichard Henderson             }
503778b54858SRichard Henderson         }
50385a18407fSRichard Henderson #endif
50395a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
5040b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
50415a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
5042b83eabeaSRichard Henderson             liveness_pass_1(s);
50435a18407fSRichard Henderson         }
50445a18407fSRichard Henderson     }
5045c5cc28ffSAurelien Jarno 
5046a23a9ec6Sbellard #ifdef CONFIG_PROFILER
5047d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time + profile_getclock());
5048a23a9ec6Sbellard #endif
5049c896fe29Sbellard 
5050c896fe29Sbellard #ifdef DEBUG_DISAS
5051d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
5052fbf59aadSRichard Henderson                  && qemu_log_in_addr_range(pc_start))) {
5053c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
505478b54858SRichard Henderson         if (logfile) {
505578b54858SRichard Henderson             fprintf(logfile, "OP after optimization and liveness analysis:\n");
5056b7a83ff8SRichard Henderson             tcg_dump_ops(s, logfile, true);
505778b54858SRichard Henderson             fprintf(logfile, "\n");
5058fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
5059c896fe29Sbellard         }
506078b54858SRichard Henderson     }
5061c896fe29Sbellard #endif
5062c896fe29Sbellard 
506335abb009SRichard Henderson     /* Initialize goto_tb jump offsets. */
50643a50f424SRichard Henderson     tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID;
50653a50f424SRichard Henderson     tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID;
50669da6079bSRichard Henderson     tb->jmp_insn_offset[0] = TB_JMP_OFFSET_INVALID;
50679da6079bSRichard Henderson     tb->jmp_insn_offset[1] = TB_JMP_OFFSET_INVALID;
506835abb009SRichard Henderson 
5069c896fe29Sbellard     tcg_reg_alloc_start(s);
5070c896fe29Sbellard 
5071db0c51a3SRichard Henderson     /*
5072db0c51a3SRichard Henderson      * Reset the buffer pointers when restarting after overflow.
5073db0c51a3SRichard Henderson      * TODO: Move this into translate-all.c with the rest of the
5074db0c51a3SRichard Henderson      * buffer management.  Having only this done here is confusing.
5075db0c51a3SRichard Henderson      */
5076db0c51a3SRichard Henderson     s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr);
5077db0c51a3SRichard Henderson     s->code_ptr = s->code_buf;
5078c896fe29Sbellard 
5079659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
50806001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
5081659ef5cbSRichard Henderson #endif
508257a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
508357a26946SRichard Henderson     s->pool_labels = NULL;
508457a26946SRichard Henderson #endif
50859ecefc84SRichard Henderson 
5086fca8a500SRichard Henderson     num_insns = -1;
508715fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
5088c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
5089b3db8758Sblueswir1 
5090c896fe29Sbellard #ifdef CONFIG_PROFILER
5091d73415a3SStefan Hajnoczi         qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
5092c896fe29Sbellard #endif
5093c45cb8bbSRichard Henderson 
5094c896fe29Sbellard         switch (opc) {
5095c896fe29Sbellard         case INDEX_op_mov_i32:
5096c896fe29Sbellard         case INDEX_op_mov_i64:
5097d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
5098dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
5099c896fe29Sbellard             break;
5100bab1671fSRichard Henderson         case INDEX_op_dup_vec:
5101bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
5102bab1671fSRichard Henderson             break;
5103765b842aSRichard Henderson         case INDEX_op_insn_start:
5104fca8a500SRichard Henderson             if (num_insns >= 0) {
51059f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
51069f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
51079f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
51089f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
5109fca8a500SRichard Henderson             }
5110fca8a500SRichard Henderson             num_insns++;
5111bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
5112bad729e2SRichard Henderson                 target_ulong a;
5113bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
5114efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
5115bad729e2SRichard Henderson #else
5116efee3746SRichard Henderson                 a = op->args[i];
5117bad729e2SRichard Henderson #endif
5118fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
5119bad729e2SRichard Henderson             }
5120c896fe29Sbellard             break;
51215ff9d6a4Sbellard         case INDEX_op_discard:
512243439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
51235ff9d6a4Sbellard             break;
5124c896fe29Sbellard         case INDEX_op_set_label:
5125e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
512692ab8e7dSRichard Henderson             tcg_out_label(s, arg_label(op->args[0]));
5127c896fe29Sbellard             break;
5128c896fe29Sbellard         case INDEX_op_call:
5129dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
5130c45cb8bbSRichard Henderson             break;
5131b55a8d9dSRichard Henderson         case INDEX_op_exit_tb:
5132b55a8d9dSRichard Henderson             tcg_out_exit_tb(s, op->args[0]);
5133b55a8d9dSRichard Henderson             break;
5134cf7d6b8eSRichard Henderson         case INDEX_op_goto_tb:
5135cf7d6b8eSRichard Henderson             tcg_out_goto_tb(s, op->args[0]);
5136cf7d6b8eSRichard Henderson             break;
5137efe86b21SRichard Henderson         case INDEX_op_dup2_vec:
5138efe86b21SRichard Henderson             if (tcg_reg_alloc_dup2(s, op)) {
5139efe86b21SRichard Henderson                 break;
5140efe86b21SRichard Henderson             }
5141efe86b21SRichard Henderson             /* fall through */
5142c896fe29Sbellard         default:
514325c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
5144be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
5145c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
5146c896fe29Sbellard                faster to have specialized register allocator functions for
5147c896fe29Sbellard                some common argument patterns */
5148dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
5149c896fe29Sbellard             break;
5150c896fe29Sbellard         }
5151b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
5152b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
5153b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
5154b125f9dcSRichard Henderson            generating code without having to check during generation.  */
5155644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
5156b125f9dcSRichard Henderson             return -1;
5157b125f9dcSRichard Henderson         }
51586e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
51596e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
51606e6c4efeSRichard Henderson             return -2;
51616e6c4efeSRichard Henderson         }
5162c896fe29Sbellard     }
5163fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
5164fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
5165c45cb8bbSRichard Henderson 
5166b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
5167659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
5168aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
5169aeee05f5SRichard Henderson     if (i < 0) {
5170aeee05f5SRichard Henderson         return i;
517123dceda6SRichard Henderson     }
5172659ef5cbSRichard Henderson #endif
517357a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
51741768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
51751768987bSRichard Henderson     if (i < 0) {
51761768987bSRichard Henderson         return i;
517757a26946SRichard Henderson     }
517857a26946SRichard Henderson #endif
51797ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
51807ecd02a0SRichard Henderson         return -2;
51817ecd02a0SRichard Henderson     }
5182c896fe29Sbellard 
5183df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
5184c896fe29Sbellard     /* flush instruction cache */
5185db0c51a3SRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
5186db0c51a3SRichard Henderson                         (uintptr_t)s->code_buf,
51871da8de39SRichard Henderson                         tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
5188df5d2b16SRichard Henderson #endif
51892aeabc08SStefan Weil 
51901813e175SRichard Henderson     return tcg_current_code_size(s);
5191c896fe29Sbellard }
5192c896fe29Sbellard 
5193a23a9ec6Sbellard #ifdef CONFIG_PROFILER
51943a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf)
5195a23a9ec6Sbellard {
5196c3fac113SEmilio G. Cota     TCGProfile prof = {};
5197c3fac113SEmilio G. Cota     const TCGProfile *s;
5198c3fac113SEmilio G. Cota     int64_t tb_count;
5199c3fac113SEmilio G. Cota     int64_t tb_div_count;
5200c3fac113SEmilio G. Cota     int64_t tot;
5201c3fac113SEmilio G. Cota 
5202c3fac113SEmilio G. Cota     tcg_profile_snapshot_counters(&prof);
5203c3fac113SEmilio G. Cota     s = &prof;
5204c3fac113SEmilio G. Cota     tb_count = s->tb_count;
5205c3fac113SEmilio G. Cota     tb_div_count = tb_count ? tb_count : 1;
5206c3fac113SEmilio G. Cota     tot = s->interm_time + s->code_time;
5207a23a9ec6Sbellard 
52083a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "JIT cycles          %" PRId64
52093a841ab5SDaniel P. Berrangé                            " (%0.3f s at 2.4 GHz)\n",
5210a23a9ec6Sbellard                            tot, tot / 2.4e9);
52113a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "translated TBs      %" PRId64
52123a841ab5SDaniel P. Berrangé                            " (aborted=%" PRId64 " %0.1f%%)\n",
5213fca8a500SRichard Henderson                            tb_count, s->tb_count1 - tb_count,
5214fca8a500SRichard Henderson                            (double)(s->tb_count1 - s->tb_count)
5215fca8a500SRichard Henderson                            / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
52163a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg ops/TB          %0.1f max=%d\n",
5217fca8a500SRichard Henderson                            (double)s->op_count / tb_div_count, s->op_count_max);
52183a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "deleted ops/TB      %0.2f\n",
5219fca8a500SRichard Henderson                            (double)s->del_op_count / tb_div_count);
52203a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg temps/TB        %0.2f max=%d\n",
52213a841ab5SDaniel P. Berrangé                            (double)s->temp_count / tb_div_count,
52223a841ab5SDaniel P. Berrangé                            s->temp_count_max);
52233a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg host code/TB    %0.1f\n",
5224fca8a500SRichard Henderson                            (double)s->code_out_len / tb_div_count);
52253a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg search data/TB  %0.1f\n",
5226fca8a500SRichard Henderson                            (double)s->search_out_len / tb_div_count);
5227a23a9ec6Sbellard 
52283a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/op           %0.1f\n",
5229a23a9ec6Sbellard                            s->op_count ? (double)tot / s->op_count : 0);
52303a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/in byte      %0.1f\n",
5231a23a9ec6Sbellard                            s->code_in_len ? (double)tot / s->code_in_len : 0);
52323a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/out byte     %0.1f\n",
5233a23a9ec6Sbellard                            s->code_out_len ? (double)tot / s->code_out_len : 0);
52343a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/search byte     %0.1f\n",
52353a841ab5SDaniel P. Berrangé                            s->search_out_len ?
52363a841ab5SDaniel P. Berrangé                            (double)tot / s->search_out_len : 0);
5237fca8a500SRichard Henderson     if (tot == 0) {
5238a23a9ec6Sbellard         tot = 1;
5239fca8a500SRichard Henderson     }
52403a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "  gen_interm time   %0.1f%%\n",
5241a23a9ec6Sbellard                            (double)s->interm_time / tot * 100.0);
52423a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "  gen_code time     %0.1f%%\n",
5243a23a9ec6Sbellard                            (double)s->code_time / tot * 100.0);
52443a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "optim./code time    %0.1f%%\n",
52453a841ab5SDaniel P. Berrangé                            (double)s->opt_time / (s->code_time ?
52463a841ab5SDaniel P. Berrangé                                                   s->code_time : 1)
5247c5cc28ffSAurelien Jarno                            * 100.0);
52483a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "liveness/code time  %0.1f%%\n",
52493a841ab5SDaniel P. Berrangé                            (double)s->la_time / (s->code_time ?
52503a841ab5SDaniel P. Berrangé                                                  s->code_time : 1) * 100.0);
52513a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cpu_restore count   %" PRId64 "\n",
5252a23a9ec6Sbellard                            s->restore_count);
52533a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "  avg cycles        %0.1f\n",
52543a841ab5SDaniel P. Berrangé                            s->restore_count ?
52553a841ab5SDaniel P. Berrangé                            (double)s->restore_time / s->restore_count : 0);
5256a23a9ec6Sbellard }
5257a23a9ec6Sbellard #else
52583a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf)
5259a23a9ec6Sbellard {
52603a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "[TCG profiler not compiled]\n");
5261a23a9ec6Sbellard }
5262a23a9ec6Sbellard #endif
5263813da627SRichard Henderson 
5264813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
52655872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
52665872bbf2SRichard Henderson 
52675872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
52685872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
52695872bbf2SRichard Henderson 
52705872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
52715872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
52725872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
52735872bbf2SRichard Henderson 
52745872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
52755872bbf2SRichard Henderson */
5276813da627SRichard Henderson 
5277813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
5278813da627SRichard Henderson typedef enum {
5279813da627SRichard Henderson     JIT_NOACTION = 0,
5280813da627SRichard Henderson     JIT_REGISTER_FN,
5281813da627SRichard Henderson     JIT_UNREGISTER_FN
5282813da627SRichard Henderson } jit_actions_t;
5283813da627SRichard Henderson 
5284813da627SRichard Henderson struct jit_code_entry {
5285813da627SRichard Henderson     struct jit_code_entry *next_entry;
5286813da627SRichard Henderson     struct jit_code_entry *prev_entry;
5287813da627SRichard Henderson     const void *symfile_addr;
5288813da627SRichard Henderson     uint64_t symfile_size;
5289813da627SRichard Henderson };
5290813da627SRichard Henderson 
5291813da627SRichard Henderson struct jit_descriptor {
5292813da627SRichard Henderson     uint32_t version;
5293813da627SRichard Henderson     uint32_t action_flag;
5294813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
5295813da627SRichard Henderson     struct jit_code_entry *first_entry;
5296813da627SRichard Henderson };
5297813da627SRichard Henderson 
5298813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
5299813da627SRichard Henderson void __jit_debug_register_code(void)
5300813da627SRichard Henderson {
5301813da627SRichard Henderson     asm("");
5302813da627SRichard Henderson }
5303813da627SRichard Henderson 
5304813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
5305813da627SRichard Henderson    the version before we can set it.  */
5306813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
5307813da627SRichard Henderson 
5308813da627SRichard Henderson /* End GDB interface.  */
5309813da627SRichard Henderson 
5310813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
5311813da627SRichard Henderson {
5312813da627SRichard Henderson     const char *p = strtab + 1;
5313813da627SRichard Henderson 
5314813da627SRichard Henderson     while (1) {
5315813da627SRichard Henderson         if (strcmp(p, str) == 0) {
5316813da627SRichard Henderson             return p - strtab;
5317813da627SRichard Henderson         }
5318813da627SRichard Henderson         p += strlen(p) + 1;
5319813da627SRichard Henderson     }
5320813da627SRichard Henderson }
5321813da627SRichard Henderson 
5322755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size,
53232c90784aSRichard Henderson                                  const void *debug_frame,
53242c90784aSRichard Henderson                                  size_t debug_frame_size)
5325813da627SRichard Henderson {
53265872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
53275872bbf2SRichard Henderson         uint32_t  len;
53285872bbf2SRichard Henderson         uint16_t  version;
53295872bbf2SRichard Henderson         uint32_t  abbrev;
53305872bbf2SRichard Henderson         uint8_t   ptr_size;
53315872bbf2SRichard Henderson         uint8_t   cu_die;
53325872bbf2SRichard Henderson         uint16_t  cu_lang;
53335872bbf2SRichard Henderson         uintptr_t cu_low_pc;
53345872bbf2SRichard Henderson         uintptr_t cu_high_pc;
53355872bbf2SRichard Henderson         uint8_t   fn_die;
53365872bbf2SRichard Henderson         char      fn_name[16];
53375872bbf2SRichard Henderson         uintptr_t fn_low_pc;
53385872bbf2SRichard Henderson         uintptr_t fn_high_pc;
53395872bbf2SRichard Henderson         uint8_t   cu_eoc;
53405872bbf2SRichard Henderson     };
5341813da627SRichard Henderson 
5342813da627SRichard Henderson     struct ElfImage {
5343813da627SRichard Henderson         ElfW(Ehdr) ehdr;
5344813da627SRichard Henderson         ElfW(Phdr) phdr;
53455872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
53465872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
53475872bbf2SRichard Henderson         struct DebugInfo di;
53485872bbf2SRichard Henderson         uint8_t    da[24];
53495872bbf2SRichard Henderson         char       str[80];
53505872bbf2SRichard Henderson     };
53515872bbf2SRichard Henderson 
53525872bbf2SRichard Henderson     struct ElfImage *img;
53535872bbf2SRichard Henderson 
53545872bbf2SRichard Henderson     static const struct ElfImage img_template = {
53555872bbf2SRichard Henderson         .ehdr = {
53565872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
53575872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
53585872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
53595872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
53605872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
53615872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
53625872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
53635872bbf2SRichard Henderson             .e_type = ET_EXEC,
53645872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
53655872bbf2SRichard Henderson             .e_version = EV_CURRENT,
53665872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
53675872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
53685872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
53695872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
53705872bbf2SRichard Henderson             .e_phnum = 1,
53715872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
53725872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
53735872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
5374abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
5375abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
5376abbb3eaeSRichard Henderson #endif
5377abbb3eaeSRichard Henderson #ifdef ELF_OSABI
5378abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
5379abbb3eaeSRichard Henderson #endif
53805872bbf2SRichard Henderson         },
53815872bbf2SRichard Henderson         .phdr = {
53825872bbf2SRichard Henderson             .p_type = PT_LOAD,
53835872bbf2SRichard Henderson             .p_flags = PF_X,
53845872bbf2SRichard Henderson         },
53855872bbf2SRichard Henderson         .shdr = {
53865872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
53875872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
53885872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
53895872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
53905872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
53915872bbf2SRichard Henderson             [1] = { /* .text */
53925872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
53935872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
53945872bbf2SRichard Henderson             },
53955872bbf2SRichard Henderson             [2] = { /* .debug_info */
53965872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
53975872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
53985872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
53995872bbf2SRichard Henderson             },
54005872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
54015872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
54025872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
54035872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
54045872bbf2SRichard Henderson             },
54055872bbf2SRichard Henderson             [4] = { /* .debug_frame */
54065872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
54075872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
54085872bbf2SRichard Henderson             },
54095872bbf2SRichard Henderson             [5] = { /* .symtab */
54105872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
54115872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
54125872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
54135872bbf2SRichard Henderson                 .sh_info = 1,
54145872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
54155872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
54165872bbf2SRichard Henderson             },
54175872bbf2SRichard Henderson             [6] = { /* .strtab */
54185872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
54195872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
54205872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
54215872bbf2SRichard Henderson             }
54225872bbf2SRichard Henderson         },
54235872bbf2SRichard Henderson         .sym = {
54245872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
54255872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
54265872bbf2SRichard Henderson                 .st_shndx = 1,
54275872bbf2SRichard Henderson             }
54285872bbf2SRichard Henderson         },
54295872bbf2SRichard Henderson         .di = {
54305872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
54315872bbf2SRichard Henderson             .version = 2,
54325872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
54335872bbf2SRichard Henderson             .cu_die = 1,
54345872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
54355872bbf2SRichard Henderson             .fn_die = 2,
54365872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
54375872bbf2SRichard Henderson         },
54385872bbf2SRichard Henderson         .da = {
54395872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
54405872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
54415872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
54425872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
54435872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
54445872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
54455872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
54465872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
54475872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
54485872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
54495872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
54505872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
54515872bbf2SRichard Henderson             0           /* no more abbrev */
54525872bbf2SRichard Henderson         },
54535872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
54545872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
5455813da627SRichard Henderson     };
5456813da627SRichard Henderson 
5457813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
5458813da627SRichard Henderson     static struct jit_code_entry one_entry;
5459813da627SRichard Henderson 
54605872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
5461813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
54622c90784aSRichard Henderson     DebugFrameHeader *dfh;
5463813da627SRichard Henderson 
54645872bbf2SRichard Henderson     img = g_malloc(img_size);
54655872bbf2SRichard Henderson     *img = img_template;
5466813da627SRichard Henderson 
54675872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
54685872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
54695872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
5470813da627SRichard Henderson 
54715872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
54725872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
54735872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
5474813da627SRichard Henderson 
54755872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
54765872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
54775872bbf2SRichard Henderson 
54785872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
54795872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
54805872bbf2SRichard Henderson 
54815872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
54825872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
54835872bbf2SRichard Henderson 
54845872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
54855872bbf2SRichard Henderson     img->sym[1].st_value = buf;
54865872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
54875872bbf2SRichard Henderson 
54885872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
548945aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
54905872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
549145aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
5492813da627SRichard Henderson 
54932c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
54942c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
54952c90784aSRichard Henderson     dfh->fde.func_start = buf;
54962c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
54972c90784aSRichard Henderson 
5498813da627SRichard Henderson #ifdef DEBUG_JIT
5499813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
5500813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
5501813da627SRichard Henderson     {
5502eb6b2edfSBin Meng         g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir());
5503eb6b2edfSBin Meng         FILE *f = fopen(jit, "w+b");
5504813da627SRichard Henderson         if (f) {
55055872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
5506813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
5507813da627SRichard Henderson             }
5508813da627SRichard Henderson             fclose(f);
5509813da627SRichard Henderson         }
5510813da627SRichard Henderson     }
5511813da627SRichard Henderson #endif
5512813da627SRichard Henderson 
5513813da627SRichard Henderson     one_entry.symfile_addr = img;
5514813da627SRichard Henderson     one_entry.symfile_size = img_size;
5515813da627SRichard Henderson 
5516813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
5517813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
5518813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
5519813da627SRichard Henderson     __jit_debug_register_code();
5520813da627SRichard Henderson }
5521813da627SRichard Henderson #else
55225872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
55235872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
5524813da627SRichard Henderson 
5525755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
55262c90784aSRichard Henderson                                  const void *debug_frame,
55272c90784aSRichard Henderson                                  size_t debug_frame_size)
5528813da627SRichard Henderson {
5529813da627SRichard Henderson }
5530813da627SRichard Henderson 
5531755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size)
5532813da627SRichard Henderson {
5533813da627SRichard Henderson }
5534813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
5535db432672SRichard Henderson 
5536db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
5537db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
5538db432672SRichard Henderson {
5539db432672SRichard Henderson     g_assert_not_reached();
5540db432672SRichard Henderson }
5541db432672SRichard Henderson #endif
5542