xref: /qemu/tcg/tcg.c (revision 874b85746107d4acf6ad6f28393cf45ef833e1ee)
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"
39c896fe29Sbellard 
40c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU
41c896fe29Sbellard    CPU definitions. Currently they are used for qemu_ld/st
42c896fe29Sbellard    instructions */
43c896fe29Sbellard #define NO_CPU_IO_DEFS
44c896fe29Sbellard 
4563c91552SPaolo Bonzini #include "exec/exec-all.h"
46dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
47813da627SRichard Henderson 
48edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX
49813da627SRichard Henderson # define ELF_CLASS  ELFCLASS32
50edee2579SRichard Henderson #else
51edee2579SRichard Henderson # define ELF_CLASS  ELFCLASS64
52813da627SRichard Henderson #endif
53e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
54813da627SRichard Henderson # define ELF_DATA   ELFDATA2MSB
55813da627SRichard Henderson #else
56813da627SRichard Henderson # define ELF_DATA   ELFDATA2LSB
57813da627SRichard Henderson #endif
58813da627SRichard Henderson 
59c896fe29Sbellard #include "elf.h"
60508127e2SPaolo Bonzini #include "exec/log.h"
61d2ba8026SRichard Henderson #include "tcg/tcg-ldst.h"
625ff7258cSRichard Henderson #include "tcg-internal.h"
635584e2dbSIlya Leoshkevich #include "accel/tcg/perf.h"
64c896fe29Sbellard 
65139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and
66ce151109SPeter Maydell    used here. */
67e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s);
68e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
696ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
702ba7fae2SRichard Henderson                         intptr_t value, intptr_t addend);
71c896fe29Sbellard 
72497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts.  */
73497a22ebSRichard Henderson typedef struct {
74497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
75497a22ebSRichard Henderson     uint32_t id;
76497a22ebSRichard Henderson     uint8_t version;
77497a22ebSRichard Henderson     char augmentation[1];
78497a22ebSRichard Henderson     uint8_t code_align;
79497a22ebSRichard Henderson     uint8_t data_align;
80497a22ebSRichard Henderson     uint8_t return_column;
81497a22ebSRichard Henderson } DebugFrameCIE;
82497a22ebSRichard Henderson 
83497a22ebSRichard Henderson typedef struct QEMU_PACKED {
84497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
85497a22ebSRichard Henderson     uint32_t cie_offset;
86edee2579SRichard Henderson     uintptr_t func_start;
87edee2579SRichard Henderson     uintptr_t func_len;
88497a22ebSRichard Henderson } DebugFrameFDEHeader;
89497a22ebSRichard Henderson 
902c90784aSRichard Henderson typedef struct QEMU_PACKED {
912c90784aSRichard Henderson     DebugFrameCIE cie;
922c90784aSRichard Henderson     DebugFrameFDEHeader fde;
932c90784aSRichard Henderson } DebugFrameHeader;
942c90784aSRichard Henderson 
95755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
962c90784aSRichard Henderson                                  const void *debug_frame,
972c90784aSRichard Henderson                                  size_t debug_frame_size)
98813da627SRichard Henderson     __attribute__((unused));
99813da627SRichard Henderson 
100139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */
1012a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
102a05b5b9bSRichard Henderson                        intptr_t arg2);
10378113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
104c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1052a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
106313bdea8SRichard Henderson static void tcg_out_addi_ptr(TCGContext *s, TCGReg, TCGReg, tcg_target_long);
107b55a8d9dSRichard Henderson static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg);
108cf7d6b8eSRichard Henderson static void tcg_out_goto_tb(TCGContext *s, int which);
1095e8892dbSMiroslav Rezanina static void tcg_out_op(TCGContext *s, TCGOpcode opc,
1105e8892dbSMiroslav Rezanina                        const TCGArg args[TCG_MAX_OP_ARGS],
1115e8892dbSMiroslav Rezanina                        const int const_args[TCG_MAX_OP_ARGS]);
112d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec
113e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
114e7632cfaSRichard Henderson                             TCGReg dst, TCGReg src);
115d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
116d6ecb4a9SRichard Henderson                              TCGReg dst, TCGReg base, intptr_t offset);
1174e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1184e186175SRichard Henderson                              TCGReg dst, int64_t arg);
1195e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1205e8892dbSMiroslav Rezanina                            unsigned vecl, unsigned vece,
1215e8892dbSMiroslav Rezanina                            const TCGArg args[TCG_MAX_OP_ARGS],
1225e8892dbSMiroslav Rezanina                            const int const_args[TCG_MAX_OP_ARGS]);
123d2fd745fSRichard Henderson #else
124e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
125e7632cfaSRichard Henderson                                    TCGReg dst, TCGReg src)
126e7632cfaSRichard Henderson {
127e7632cfaSRichard Henderson     g_assert_not_reached();
128e7632cfaSRichard Henderson }
129d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
130d6ecb4a9SRichard Henderson                                     TCGReg dst, TCGReg base, intptr_t offset)
131d6ecb4a9SRichard Henderson {
132d6ecb4a9SRichard Henderson     g_assert_not_reached();
133d6ecb4a9SRichard Henderson }
1344e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1354e186175SRichard Henderson                                     TCGReg dst, int64_t arg)
136e7632cfaSRichard Henderson {
137e7632cfaSRichard Henderson     g_assert_not_reached();
138e7632cfaSRichard Henderson }
1395e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1405e8892dbSMiroslav Rezanina                                   unsigned vecl, unsigned vece,
1415e8892dbSMiroslav Rezanina                                   const TCGArg args[TCG_MAX_OP_ARGS],
1425e8892dbSMiroslav Rezanina                                   const int const_args[TCG_MAX_OP_ARGS])
143d2fd745fSRichard Henderson {
144d2fd745fSRichard Henderson     g_assert_not_reached();
145d2fd745fSRichard Henderson }
146d2fd745fSRichard Henderson #endif
1472a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
148a05b5b9bSRichard Henderson                        intptr_t arg2);
14959d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
15059d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
1517b7d8b2dSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target,
152cee44b03SRichard Henderson                          const TCGHelperInfo *info);
1535e3d0c19SRichard Henderson static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot);
154a4fbbd77SRichard Henderson static bool tcg_target_const_match(int64_t val, TCGType type, int ct);
155659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
156aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s);
157659ef5cbSRichard Henderson #endif
158c896fe29Sbellard 
15942eb6dfcSRichard Henderson TCGContext tcg_init_ctx;
16042eb6dfcSRichard Henderson __thread TCGContext *tcg_ctx;
16142eb6dfcSRichard Henderson 
1625ff7258cSRichard Henderson TCGContext **tcg_ctxs;
1630e2d61cfSRichard Henderson unsigned int tcg_cur_ctxs;
1640e2d61cfSRichard Henderson unsigned int tcg_max_ctxs;
1651c2adb95SRichard Henderson TCGv_env cpu_env = 0;
166c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue;
167db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff;
168df2cce29SEmilio G. Cota 
169b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
170b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec;
171b91ccb31SRichard Henderson #endif
172b91ccb31SRichard Henderson 
173d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
174b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
175c896fe29Sbellard 
1761813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
1774196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
178c896fe29Sbellard {
179c896fe29Sbellard     *s->code_ptr++ = v;
180c896fe29Sbellard }
181c896fe29Sbellard 
1824196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
1834196dca6SPeter Maydell                                                       uint8_t v)
1845c53bb81SPeter Maydell {
1851813e175SRichard Henderson     *p = v;
1865c53bb81SPeter Maydell }
1871813e175SRichard Henderson #endif
1885c53bb81SPeter Maydell 
1891813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
1904196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
191c896fe29Sbellard {
1921813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
1931813e175SRichard Henderson         *s->code_ptr++ = v;
1941813e175SRichard Henderson     } else {
1951813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
1964387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
1971813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
1981813e175SRichard Henderson     }
199c896fe29Sbellard }
200c896fe29Sbellard 
2014196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2024196dca6SPeter Maydell                                                        uint16_t v)
2035c53bb81SPeter Maydell {
2041813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2051813e175SRichard Henderson         *p = v;
2061813e175SRichard Henderson     } else {
2075c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2085c53bb81SPeter Maydell     }
2091813e175SRichard Henderson }
2101813e175SRichard Henderson #endif
2115c53bb81SPeter Maydell 
2121813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
2134196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
214c896fe29Sbellard {
2151813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2161813e175SRichard Henderson         *s->code_ptr++ = v;
2171813e175SRichard Henderson     } else {
2181813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2194387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2201813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
2211813e175SRichard Henderson     }
222c896fe29Sbellard }
223c896fe29Sbellard 
2244196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
2254196dca6SPeter Maydell                                                        uint32_t v)
2265c53bb81SPeter Maydell {
2271813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2281813e175SRichard Henderson         *p = v;
2291813e175SRichard Henderson     } else {
2305c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2315c53bb81SPeter Maydell     }
2321813e175SRichard Henderson }
2331813e175SRichard Henderson #endif
2345c53bb81SPeter Maydell 
2351813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
2364196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
237ac26eb69SRichard Henderson {
2381813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2391813e175SRichard Henderson         *s->code_ptr++ = v;
2401813e175SRichard Henderson     } else {
2411813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2424387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2431813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
2441813e175SRichard Henderson     }
245ac26eb69SRichard Henderson }
246ac26eb69SRichard Henderson 
2474196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
2484196dca6SPeter Maydell                                                        uint64_t v)
2495c53bb81SPeter Maydell {
2501813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2511813e175SRichard Henderson         *p = v;
2521813e175SRichard Henderson     } else {
2535c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2545c53bb81SPeter Maydell     }
2551813e175SRichard Henderson }
2561813e175SRichard Henderson #endif
2575c53bb81SPeter Maydell 
258c896fe29Sbellard /* label relocation processing */
259c896fe29Sbellard 
2601813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
261bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
262c896fe29Sbellard {
2637ecd02a0SRichard Henderson     TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation));
264c896fe29Sbellard 
265c896fe29Sbellard     r->type = type;
266c896fe29Sbellard     r->ptr = code_ptr;
267c896fe29Sbellard     r->addend = addend;
2687ecd02a0SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
269c896fe29Sbellard }
270c896fe29Sbellard 
27192ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l)
272c896fe29Sbellard {
273eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
274c896fe29Sbellard     l->has_value = 1;
27592ab8e7dSRichard Henderson     l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr);
276c896fe29Sbellard }
277c896fe29Sbellard 
27842a268c2SRichard Henderson TCGLabel *gen_new_label(void)
279c896fe29Sbellard {
280b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
28151e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
282c896fe29Sbellard 
2837ecd02a0SRichard Henderson     memset(l, 0, sizeof(TCGLabel));
2847ecd02a0SRichard Henderson     l->id = s->nb_labels++;
2857ecd02a0SRichard Henderson     QSIMPLEQ_INIT(&l->relocs);
2867ecd02a0SRichard Henderson 
287bef16ab4SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
28842a268c2SRichard Henderson 
28942a268c2SRichard Henderson     return l;
290c896fe29Sbellard }
291c896fe29Sbellard 
2927ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s)
2937ecd02a0SRichard Henderson {
2947ecd02a0SRichard Henderson     TCGLabel *l;
2957ecd02a0SRichard Henderson 
2967ecd02a0SRichard Henderson     QSIMPLEQ_FOREACH(l, &s->labels, next) {
2977ecd02a0SRichard Henderson         TCGRelocation *r;
2987ecd02a0SRichard Henderson         uintptr_t value = l->u.value;
2997ecd02a0SRichard Henderson 
3007ecd02a0SRichard Henderson         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
3017ecd02a0SRichard Henderson             if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
3027ecd02a0SRichard Henderson                 return false;
3037ecd02a0SRichard Henderson             }
3047ecd02a0SRichard Henderson         }
3057ecd02a0SRichard Henderson     }
3067ecd02a0SRichard Henderson     return true;
3077ecd02a0SRichard Henderson }
3087ecd02a0SRichard Henderson 
3099f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3109f754620SRichard Henderson {
311f14bed3fSRichard Henderson     /*
312f14bed3fSRichard Henderson      * We will check for overflow at the end of the opcode loop in
313f14bed3fSRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
314f14bed3fSRichard Henderson      */
315b7e4afbdSRichard Henderson     s->gen_tb->jmp_reset_offset[which] = tcg_current_code_size(s);
3169f754620SRichard Henderson }
3179f754620SRichard Henderson 
318b52a2c03SRichard Henderson static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which)
319b52a2c03SRichard Henderson {
320b52a2c03SRichard Henderson     /*
321b52a2c03SRichard Henderson      * We will check for overflow at the end of the opcode loop in
322b52a2c03SRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
323b52a2c03SRichard Henderson      */
3249da6079bSRichard Henderson     s->gen_tb->jmp_insn_offset[which] = tcg_current_code_size(s);
325b52a2c03SRichard Henderson }
326b52a2c03SRichard Henderson 
327becc452aSRichard Henderson static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which)
328becc452aSRichard Henderson {
329becc452aSRichard Henderson     /*
330becc452aSRichard Henderson      * Return the read-execute version of the pointer, for the benefit
331becc452aSRichard Henderson      * of any pc-relative addressing mode.
332becc452aSRichard Henderson      */
3339da6079bSRichard Henderson     return (uintptr_t)tcg_splitwx_to_rx(&s->gen_tb->jmp_target_addr[which]);
334becc452aSRichard Henderson }
335becc452aSRichard Henderson 
336db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */
3378905770bSMarc-André Lureau static G_NORETURN
3388905770bSMarc-André Lureau void tcg_raise_tb_overflow(TCGContext *s)
339db6b7d0cSRichard Henderson {
340db6b7d0cSRichard Henderson     siglongjmp(s->jmp_trans, -2);
341db6b7d0cSRichard Henderson }
342db6b7d0cSRichard Henderson 
3434c22e840SRichard Henderson #define C_PFX1(P, A)                    P##A
3444c22e840SRichard Henderson #define C_PFX2(P, A, B)                 P##A##_##B
3454c22e840SRichard Henderson #define C_PFX3(P, A, B, C)              P##A##_##B##_##C
3464c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D)           P##A##_##B##_##C##_##D
3474c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E)        P##A##_##B##_##C##_##D##_##E
3484c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F)     P##A##_##B##_##C##_##D##_##E##_##F
3494c22e840SRichard Henderson 
3504c22e840SRichard Henderson /* Define an enumeration for the various combinations. */
3514c22e840SRichard Henderson 
3524c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1),
3534c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2),
3544c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3),
3554c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4),
3564c22e840SRichard Henderson 
3574c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1),
3584c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2),
3594c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3),
3604c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4),
3614c22e840SRichard Henderson 
3624c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2),
3634c22e840SRichard Henderson 
3644c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1),
3654c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2),
3664c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3),
3674c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4),
3684c22e840SRichard Henderson 
3694c22e840SRichard Henderson typedef enum {
3704c22e840SRichard Henderson #include "tcg-target-con-set.h"
3714c22e840SRichard Henderson } TCGConstraintSetIndex;
3724c22e840SRichard Henderson 
3734c22e840SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode);
3744c22e840SRichard Henderson 
3754c22e840SRichard Henderson #undef C_O0_I1
3764c22e840SRichard Henderson #undef C_O0_I2
3774c22e840SRichard Henderson #undef C_O0_I3
3784c22e840SRichard Henderson #undef C_O0_I4
3794c22e840SRichard Henderson #undef C_O1_I1
3804c22e840SRichard Henderson #undef C_O1_I2
3814c22e840SRichard Henderson #undef C_O1_I3
3824c22e840SRichard Henderson #undef C_O1_I4
3834c22e840SRichard Henderson #undef C_N1_I2
3844c22e840SRichard Henderson #undef C_O2_I1
3854c22e840SRichard Henderson #undef C_O2_I2
3864c22e840SRichard Henderson #undef C_O2_I3
3874c22e840SRichard Henderson #undef C_O2_I4
3884c22e840SRichard Henderson 
3894c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */
3904c22e840SRichard Henderson 
3914c22e840SRichard Henderson #define C_O0_I1(I1)                     { .args_ct_str = { #I1 } },
3924c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 { .args_ct_str = { #I1, #I2 } },
3934c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             { .args_ct_str = { #I1, #I2, #I3 } },
3944c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         { .args_ct_str = { #I1, #I2, #I3, #I4 } },
3954c22e840SRichard Henderson 
3964c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 { .args_ct_str = { #O1, #I1 } },
3974c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             { .args_ct_str = { #O1, #I1, #I2 } },
3984c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         { .args_ct_str = { #O1, #I1, #I2, #I3 } },
3994c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } },
4004c22e840SRichard Henderson 
4014c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             { .args_ct_str = { "&" #O1, #I1, #I2 } },
4024c22e840SRichard Henderson 
4034c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             { .args_ct_str = { #O1, #O2, #I1 } },
4044c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         { .args_ct_str = { #O1, #O2, #I1, #I2 } },
4054c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } },
4064c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } },
4074c22e840SRichard Henderson 
4084c22e840SRichard Henderson static const TCGTargetOpDef constraint_sets[] = {
4094c22e840SRichard Henderson #include "tcg-target-con-set.h"
4104c22e840SRichard Henderson };
4114c22e840SRichard Henderson 
4124c22e840SRichard Henderson 
4134c22e840SRichard Henderson #undef C_O0_I1
4144c22e840SRichard Henderson #undef C_O0_I2
4154c22e840SRichard Henderson #undef C_O0_I3
4164c22e840SRichard Henderson #undef C_O0_I4
4174c22e840SRichard Henderson #undef C_O1_I1
4184c22e840SRichard Henderson #undef C_O1_I2
4194c22e840SRichard Henderson #undef C_O1_I3
4204c22e840SRichard Henderson #undef C_O1_I4
4214c22e840SRichard Henderson #undef C_N1_I2
4224c22e840SRichard Henderson #undef C_O2_I1
4234c22e840SRichard Henderson #undef C_O2_I2
4244c22e840SRichard Henderson #undef C_O2_I3
4254c22e840SRichard Henderson #undef C_O2_I4
4264c22e840SRichard Henderson 
4274c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */
4284c22e840SRichard Henderson 
4294c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1)
4304c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2)
4314c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3)
4324c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4)
4334c22e840SRichard Henderson 
4344c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1)
4354c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2)
4364c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3)
4374c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4)
4384c22e840SRichard Henderson 
4394c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2)
4404c22e840SRichard Henderson 
4414c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1)
4424c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2)
4434c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3)
4444c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4)
4454c22e840SRichard Henderson 
446139c1837SPaolo Bonzini #include "tcg-target.c.inc"
447c896fe29Sbellard 
44838b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s)
44938b47b19SEmilio G. Cota {
45038b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
45138b47b19SEmilio G. Cota     s->plugin_tb = g_new0(struct qemu_plugin_tb, 1);
45238b47b19SEmilio G. Cota     s->plugin_tb->insns =
45338b47b19SEmilio G. Cota         g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn);
45438b47b19SEmilio G. Cota #endif
45538b47b19SEmilio G. Cota }
45638b47b19SEmilio G. Cota 
457e8feb96fSEmilio G. Cota /*
4583468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
4593468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
4603468b59eSEmilio G. Cota  * before initiating translation.
4613468b59eSEmilio G. Cota  *
4623468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
4633468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
4643468b59eSEmilio G. Cota  *
4653468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
4663468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
4673468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
4683468b59eSEmilio G. Cota  *
4693468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
4703468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
4713468b59eSEmilio G. Cota  */
4723468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
4733468b59eSEmilio G. Cota void tcg_register_thread(void)
4743468b59eSEmilio G. Cota {
4753468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
4763468b59eSEmilio G. Cota }
4773468b59eSEmilio G. Cota #else
4783468b59eSEmilio G. Cota void tcg_register_thread(void)
4793468b59eSEmilio G. Cota {
4803468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
4813468b59eSEmilio G. Cota     unsigned int i, n;
4823468b59eSEmilio G. Cota 
4833468b59eSEmilio G. Cota     *s = tcg_init_ctx;
4843468b59eSEmilio G. Cota 
4853468b59eSEmilio G. Cota     /* Relink mem_base.  */
4863468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
4873468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
4883468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
4893468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
4903468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
4913468b59eSEmilio G. Cota         }
4923468b59eSEmilio G. Cota     }
4933468b59eSEmilio G. Cota 
4943468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
4950e2d61cfSRichard Henderson     n = qatomic_fetch_inc(&tcg_cur_ctxs);
4960e2d61cfSRichard Henderson     g_assert(n < tcg_max_ctxs);
497d73415a3SStefan Hajnoczi     qatomic_set(&tcg_ctxs[n], s);
4983468b59eSEmilio G. Cota 
49938b47b19SEmilio G. Cota     if (n > 0) {
50038b47b19SEmilio G. Cota         alloc_tcg_plugin_context(s);
501bf042e8eSRichard Henderson         tcg_region_initial_alloc(s);
50238b47b19SEmilio G. Cota     }
50338b47b19SEmilio G. Cota 
5043468b59eSEmilio G. Cota     tcg_ctx = s;
5053468b59eSEmilio G. Cota }
5063468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
5073468b59eSEmilio G. Cota 
508c896fe29Sbellard /* pool based memory allocation */
509c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
510c896fe29Sbellard {
511c896fe29Sbellard     TCGPool *p;
512c896fe29Sbellard     int pool_size;
513c896fe29Sbellard 
514c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
515c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
5167267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
517c896fe29Sbellard         p->size = size;
5184055299eSKirill Batuzov         p->next = s->pool_first_large;
5194055299eSKirill Batuzov         s->pool_first_large = p;
5204055299eSKirill Batuzov         return p->data;
521c896fe29Sbellard     } else {
522c896fe29Sbellard         p = s->pool_current;
523c896fe29Sbellard         if (!p) {
524c896fe29Sbellard             p = s->pool_first;
525c896fe29Sbellard             if (!p)
526c896fe29Sbellard                 goto new_pool;
527c896fe29Sbellard         } else {
528c896fe29Sbellard             if (!p->next) {
529c896fe29Sbellard             new_pool:
530c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
5317267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
532c896fe29Sbellard                 p->size = pool_size;
533c896fe29Sbellard                 p->next = NULL;
534a813e36fSRichard Henderson                 if (s->pool_current) {
535c896fe29Sbellard                     s->pool_current->next = p;
536a813e36fSRichard Henderson                 } else {
537c896fe29Sbellard                     s->pool_first = p;
538a813e36fSRichard Henderson                 }
539c896fe29Sbellard             } else {
540c896fe29Sbellard                 p = p->next;
541c896fe29Sbellard             }
542c896fe29Sbellard         }
543c896fe29Sbellard     }
544c896fe29Sbellard     s->pool_current = p;
545c896fe29Sbellard     s->pool_cur = p->data + size;
546c896fe29Sbellard     s->pool_end = p->data + p->size;
547c896fe29Sbellard     return p->data;
548c896fe29Sbellard }
549c896fe29Sbellard 
550c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
551c896fe29Sbellard {
5524055299eSKirill Batuzov     TCGPool *p, *t;
5534055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
5544055299eSKirill Batuzov         t = p->next;
5554055299eSKirill Batuzov         g_free(p);
5564055299eSKirill Batuzov     }
5574055299eSKirill Batuzov     s->pool_first_large = NULL;
558c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
559c896fe29Sbellard     s->pool_current = NULL;
560c896fe29Sbellard }
561c896fe29Sbellard 
5622ef6175aSRichard Henderson #include "exec/helper-proto.h"
5632ef6175aSRichard Henderson 
56439004a71SRichard Henderson static TCGHelperInfo all_helpers[] = {
5652ef6175aSRichard Henderson #include "exec/helper-tcg.h"
566100b5e01SRichard Henderson };
567619205fdSEmilio G. Cota static GHashTable *helper_table;
568100b5e01SRichard Henderson 
56922f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
570c6ef8c7bSPhilippe Mathieu-Daudé static ffi_type *typecode_to_ffi(int argmask)
571c6ef8c7bSPhilippe Mathieu-Daudé {
572e9709e17SRichard Henderson     /*
573e9709e17SRichard Henderson      * libffi does not support __int128_t, so we have forced Int128
574e9709e17SRichard Henderson      * to use the structure definition instead of the builtin type.
575e9709e17SRichard Henderson      */
576e9709e17SRichard Henderson     static ffi_type *ffi_type_i128_elements[3] = {
577e9709e17SRichard Henderson         &ffi_type_uint64,
578e9709e17SRichard Henderson         &ffi_type_uint64,
579e9709e17SRichard Henderson         NULL
580e9709e17SRichard Henderson     };
581e9709e17SRichard Henderson     static ffi_type ffi_type_i128 = {
582e9709e17SRichard Henderson         .size = 16,
583e9709e17SRichard Henderson         .alignment = __alignof__(Int128),
584e9709e17SRichard Henderson         .type = FFI_TYPE_STRUCT,
585e9709e17SRichard Henderson         .elements = ffi_type_i128_elements,
586e9709e17SRichard Henderson     };
587e9709e17SRichard Henderson 
588c6ef8c7bSPhilippe Mathieu-Daudé     switch (argmask) {
589c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_void:
590c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_void;
591c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_i32:
592c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_uint32;
593c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_s32:
594c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_sint32;
595c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_i64:
596c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_uint64;
597c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_s64:
598c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_sint64;
599c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_ptr:
600c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_pointer;
601e9709e17SRichard Henderson     case dh_typecode_i128:
602e9709e17SRichard Henderson         return &ffi_type_i128;
603c6ef8c7bSPhilippe Mathieu-Daudé     }
604c6ef8c7bSPhilippe Mathieu-Daudé     g_assert_not_reached();
605c6ef8c7bSPhilippe Mathieu-Daudé }
6060c22e176SPhilippe Mathieu-Daudé 
6070c22e176SPhilippe Mathieu-Daudé static void init_ffi_layouts(void)
6080c22e176SPhilippe Mathieu-Daudé {
6090c22e176SPhilippe Mathieu-Daudé     /* g_direct_hash/equal for direct comparisons on uint32_t.  */
610f9c4bb80SRichard Henderson     GHashTable *ffi_table = g_hash_table_new(NULL, NULL);
611f9c4bb80SRichard Henderson 
6120c22e176SPhilippe Mathieu-Daudé     for (int i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
613f9c4bb80SRichard Henderson         TCGHelperInfo *info = &all_helpers[i];
614f9c4bb80SRichard Henderson         unsigned typemask = info->typemask;
6150c22e176SPhilippe Mathieu-Daudé         gpointer hash = (gpointer)(uintptr_t)typemask;
6160c22e176SPhilippe Mathieu-Daudé         struct {
6170c22e176SPhilippe Mathieu-Daudé             ffi_cif cif;
6180c22e176SPhilippe Mathieu-Daudé             ffi_type *args[];
6190c22e176SPhilippe Mathieu-Daudé         } *ca;
6200c22e176SPhilippe Mathieu-Daudé         ffi_status status;
6210c22e176SPhilippe Mathieu-Daudé         int nargs;
622f9c4bb80SRichard Henderson         ffi_cif *cif;
6230c22e176SPhilippe Mathieu-Daudé 
624f9c4bb80SRichard Henderson         cif = g_hash_table_lookup(ffi_table, hash);
625f9c4bb80SRichard Henderson         if (cif) {
626f9c4bb80SRichard Henderson             info->cif = cif;
6270c22e176SPhilippe Mathieu-Daudé             continue;
6280c22e176SPhilippe Mathieu-Daudé         }
6290c22e176SPhilippe Mathieu-Daudé 
6300c22e176SPhilippe Mathieu-Daudé         /* Ignoring the return type, find the last non-zero field. */
6310c22e176SPhilippe Mathieu-Daudé         nargs = 32 - clz32(typemask >> 3);
6320c22e176SPhilippe Mathieu-Daudé         nargs = DIV_ROUND_UP(nargs, 3);
633e9709e17SRichard Henderson         assert(nargs <= MAX_CALL_IARGS);
6340c22e176SPhilippe Mathieu-Daudé 
6350c22e176SPhilippe Mathieu-Daudé         ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *));
6360c22e176SPhilippe Mathieu-Daudé         ca->cif.rtype = typecode_to_ffi(typemask & 7);
6370c22e176SPhilippe Mathieu-Daudé         ca->cif.nargs = nargs;
6380c22e176SPhilippe Mathieu-Daudé 
6390c22e176SPhilippe Mathieu-Daudé         if (nargs != 0) {
6400c22e176SPhilippe Mathieu-Daudé             ca->cif.arg_types = ca->args;
6410c22e176SPhilippe Mathieu-Daudé             for (int j = 0; j < nargs; ++j) {
6420c22e176SPhilippe Mathieu-Daudé                 int typecode = extract32(typemask, (j + 1) * 3, 3);
6430c22e176SPhilippe Mathieu-Daudé                 ca->args[j] = typecode_to_ffi(typecode);
6440c22e176SPhilippe Mathieu-Daudé             }
6450c22e176SPhilippe Mathieu-Daudé         }
6460c22e176SPhilippe Mathieu-Daudé 
6470c22e176SPhilippe Mathieu-Daudé         status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs,
6480c22e176SPhilippe Mathieu-Daudé                               ca->cif.rtype, ca->cif.arg_types);
6490c22e176SPhilippe Mathieu-Daudé         assert(status == FFI_OK);
6500c22e176SPhilippe Mathieu-Daudé 
651f9c4bb80SRichard Henderson         cif = &ca->cif;
652f9c4bb80SRichard Henderson         info->cif = cif;
653f9c4bb80SRichard Henderson         g_hash_table_insert(ffi_table, hash, (gpointer)cif);
6540c22e176SPhilippe Mathieu-Daudé     }
655f9c4bb80SRichard Henderson 
656f9c4bb80SRichard Henderson     g_hash_table_destroy(ffi_table);
6570c22e176SPhilippe Mathieu-Daudé }
6580c22e176SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG_INTERPRETER */
65922f15579SRichard Henderson 
66039004a71SRichard Henderson typedef struct TCGCumulativeArgs {
66139004a71SRichard Henderson     int arg_idx;                /* tcg_gen_callN args[] */
66239004a71SRichard Henderson     int info_in_idx;            /* TCGHelperInfo in[] */
66339004a71SRichard Henderson     int arg_slot;               /* regs+stack slot */
66439004a71SRichard Henderson     int ref_slot;               /* stack slots for references */
66539004a71SRichard Henderson } TCGCumulativeArgs;
66639004a71SRichard Henderson 
66739004a71SRichard Henderson static void layout_arg_even(TCGCumulativeArgs *cum)
66839004a71SRichard Henderson {
66939004a71SRichard Henderson     cum->arg_slot += cum->arg_slot & 1;
67039004a71SRichard Henderson }
67139004a71SRichard Henderson 
67239004a71SRichard Henderson static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info,
67339004a71SRichard Henderson                          TCGCallArgumentKind kind)
67439004a71SRichard Henderson {
67539004a71SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
67639004a71SRichard Henderson 
67739004a71SRichard Henderson     *loc = (TCGCallArgumentLoc){
67839004a71SRichard Henderson         .kind = kind,
67939004a71SRichard Henderson         .arg_idx = cum->arg_idx,
68039004a71SRichard Henderson         .arg_slot = cum->arg_slot,
68139004a71SRichard Henderson     };
68239004a71SRichard Henderson     cum->info_in_idx++;
68339004a71SRichard Henderson     cum->arg_slot++;
68439004a71SRichard Henderson }
68539004a71SRichard Henderson 
68639004a71SRichard Henderson static void layout_arg_normal_n(TCGCumulativeArgs *cum,
68739004a71SRichard Henderson                                 TCGHelperInfo *info, int n)
68839004a71SRichard Henderson {
68939004a71SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
69039004a71SRichard Henderson 
69139004a71SRichard Henderson     for (int i = 0; i < n; ++i) {
69239004a71SRichard Henderson         /* Layout all using the same arg_idx, adjusting the subindex. */
69339004a71SRichard Henderson         loc[i] = (TCGCallArgumentLoc){
69439004a71SRichard Henderson             .kind = TCG_CALL_ARG_NORMAL,
69539004a71SRichard Henderson             .arg_idx = cum->arg_idx,
69639004a71SRichard Henderson             .tmp_subindex = i,
69739004a71SRichard Henderson             .arg_slot = cum->arg_slot + i,
69839004a71SRichard Henderson         };
69939004a71SRichard Henderson     }
70039004a71SRichard Henderson     cum->info_in_idx += n;
70139004a71SRichard Henderson     cum->arg_slot += n;
70239004a71SRichard Henderson }
70339004a71SRichard Henderson 
704313bdea8SRichard Henderson static void layout_arg_by_ref(TCGCumulativeArgs *cum, TCGHelperInfo *info)
705313bdea8SRichard Henderson {
706313bdea8SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
707313bdea8SRichard Henderson     int n = 128 / TCG_TARGET_REG_BITS;
708313bdea8SRichard Henderson 
709313bdea8SRichard Henderson     /* The first subindex carries the pointer. */
710313bdea8SRichard Henderson     layout_arg_1(cum, info, TCG_CALL_ARG_BY_REF);
711313bdea8SRichard Henderson 
712313bdea8SRichard Henderson     /*
713313bdea8SRichard Henderson      * The callee is allowed to clobber memory associated with
714313bdea8SRichard Henderson      * structure pass by-reference.  Therefore we must make copies.
715313bdea8SRichard Henderson      * Allocate space from "ref_slot", which will be adjusted to
716313bdea8SRichard Henderson      * follow the parameters on the stack.
717313bdea8SRichard Henderson      */
718313bdea8SRichard Henderson     loc[0].ref_slot = cum->ref_slot;
719313bdea8SRichard Henderson 
720313bdea8SRichard Henderson     /*
721313bdea8SRichard Henderson      * Subsequent words also go into the reference slot, but
722313bdea8SRichard Henderson      * do not accumulate into the regular arguments.
723313bdea8SRichard Henderson      */
724313bdea8SRichard Henderson     for (int i = 1; i < n; ++i) {
725313bdea8SRichard Henderson         loc[i] = (TCGCallArgumentLoc){
726313bdea8SRichard Henderson             .kind = TCG_CALL_ARG_BY_REF_N,
727313bdea8SRichard Henderson             .arg_idx = cum->arg_idx,
728313bdea8SRichard Henderson             .tmp_subindex = i,
729313bdea8SRichard Henderson             .ref_slot = cum->ref_slot + i,
730313bdea8SRichard Henderson         };
731313bdea8SRichard Henderson     }
732313bdea8SRichard Henderson     cum->info_in_idx += n;
733313bdea8SRichard Henderson     cum->ref_slot += n;
734313bdea8SRichard Henderson }
735313bdea8SRichard Henderson 
73639004a71SRichard Henderson static void init_call_layout(TCGHelperInfo *info)
73739004a71SRichard Henderson {
73839004a71SRichard Henderson     int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs);
73939004a71SRichard Henderson     int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long);
74039004a71SRichard Henderson     unsigned typemask = info->typemask;
74139004a71SRichard Henderson     unsigned typecode;
74239004a71SRichard Henderson     TCGCumulativeArgs cum = { };
74339004a71SRichard Henderson 
74439004a71SRichard Henderson     /*
74539004a71SRichard Henderson      * Parse and place any function return value.
74639004a71SRichard Henderson      */
74739004a71SRichard Henderson     typecode = typemask & 7;
74839004a71SRichard Henderson     switch (typecode) {
74939004a71SRichard Henderson     case dh_typecode_void:
75039004a71SRichard Henderson         info->nr_out = 0;
75139004a71SRichard Henderson         break;
75239004a71SRichard Henderson     case dh_typecode_i32:
75339004a71SRichard Henderson     case dh_typecode_s32:
75439004a71SRichard Henderson     case dh_typecode_ptr:
75539004a71SRichard Henderson         info->nr_out = 1;
75639004a71SRichard Henderson         info->out_kind = TCG_CALL_RET_NORMAL;
75739004a71SRichard Henderson         break;
75839004a71SRichard Henderson     case dh_typecode_i64:
75939004a71SRichard Henderson     case dh_typecode_s64:
76039004a71SRichard Henderson         info->nr_out = 64 / TCG_TARGET_REG_BITS;
76139004a71SRichard Henderson         info->out_kind = TCG_CALL_RET_NORMAL;
7625e3d0c19SRichard Henderson         /* Query the last register now to trigger any assert early. */
7635e3d0c19SRichard Henderson         tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1);
764466d3759SRichard Henderson         break;
765466d3759SRichard Henderson     case dh_typecode_i128:
766466d3759SRichard Henderson         info->nr_out = 128 / TCG_TARGET_REG_BITS;
7675427a9a7SRichard Henderson         info->out_kind = TCG_TARGET_CALL_RET_I128;
7685427a9a7SRichard Henderson         switch (TCG_TARGET_CALL_RET_I128) {
769466d3759SRichard Henderson         case TCG_CALL_RET_NORMAL:
7705e3d0c19SRichard Henderson             /* Query the last register now to trigger any assert early. */
7715e3d0c19SRichard Henderson             tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1);
772466d3759SRichard Henderson             break;
773c6556aa0SRichard Henderson         case TCG_CALL_RET_BY_VEC:
774c6556aa0SRichard Henderson             /* Query the single register now to trigger any assert early. */
775c6556aa0SRichard Henderson             tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0);
776c6556aa0SRichard Henderson             break;
777313bdea8SRichard Henderson         case TCG_CALL_RET_BY_REF:
778313bdea8SRichard Henderson             /*
779313bdea8SRichard Henderson              * Allocate the first argument to the output.
780313bdea8SRichard Henderson              * We don't need to store this anywhere, just make it
781313bdea8SRichard Henderson              * unavailable for use in the input loop below.
782313bdea8SRichard Henderson              */
783313bdea8SRichard Henderson             cum.arg_slot = 1;
784313bdea8SRichard Henderson             break;
785466d3759SRichard Henderson         default:
786466d3759SRichard Henderson             qemu_build_not_reached();
787466d3759SRichard Henderson         }
78839004a71SRichard Henderson         break;
78939004a71SRichard Henderson     default:
79039004a71SRichard Henderson         g_assert_not_reached();
79139004a71SRichard Henderson     }
79239004a71SRichard Henderson 
79339004a71SRichard Henderson     /*
79439004a71SRichard Henderson      * Parse and place function arguments.
79539004a71SRichard Henderson      */
79639004a71SRichard Henderson     for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) {
79739004a71SRichard Henderson         TCGCallArgumentKind kind;
79839004a71SRichard Henderson         TCGType type;
79939004a71SRichard Henderson 
80039004a71SRichard Henderson         typecode = typemask & 7;
80139004a71SRichard Henderson         switch (typecode) {
80239004a71SRichard Henderson         case dh_typecode_i32:
80339004a71SRichard Henderson         case dh_typecode_s32:
80439004a71SRichard Henderson             type = TCG_TYPE_I32;
80539004a71SRichard Henderson             break;
80639004a71SRichard Henderson         case dh_typecode_i64:
80739004a71SRichard Henderson         case dh_typecode_s64:
80839004a71SRichard Henderson             type = TCG_TYPE_I64;
80939004a71SRichard Henderson             break;
81039004a71SRichard Henderson         case dh_typecode_ptr:
81139004a71SRichard Henderson             type = TCG_TYPE_PTR;
81239004a71SRichard Henderson             break;
813466d3759SRichard Henderson         case dh_typecode_i128:
814466d3759SRichard Henderson             type = TCG_TYPE_I128;
815466d3759SRichard Henderson             break;
81639004a71SRichard Henderson         default:
81739004a71SRichard Henderson             g_assert_not_reached();
81839004a71SRichard Henderson         }
81939004a71SRichard Henderson 
82039004a71SRichard Henderson         switch (type) {
82139004a71SRichard Henderson         case TCG_TYPE_I32:
82239004a71SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I32) {
82339004a71SRichard Henderson             case TCG_CALL_ARG_EVEN:
82439004a71SRichard Henderson                 layout_arg_even(&cum);
82539004a71SRichard Henderson                 /* fall through */
82639004a71SRichard Henderson             case TCG_CALL_ARG_NORMAL:
82739004a71SRichard Henderson                 layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
82839004a71SRichard Henderson                 break;
82939004a71SRichard Henderson             case TCG_CALL_ARG_EXTEND:
83039004a71SRichard Henderson                 kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1);
83139004a71SRichard Henderson                 layout_arg_1(&cum, info, kind);
83239004a71SRichard Henderson                 break;
83339004a71SRichard Henderson             default:
83439004a71SRichard Henderson                 qemu_build_not_reached();
83539004a71SRichard Henderson             }
83639004a71SRichard Henderson             break;
83739004a71SRichard Henderson 
83839004a71SRichard Henderson         case TCG_TYPE_I64:
83939004a71SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I64) {
84039004a71SRichard Henderson             case TCG_CALL_ARG_EVEN:
84139004a71SRichard Henderson                 layout_arg_even(&cum);
84239004a71SRichard Henderson                 /* fall through */
84339004a71SRichard Henderson             case TCG_CALL_ARG_NORMAL:
84439004a71SRichard Henderson                 if (TCG_TARGET_REG_BITS == 32) {
84539004a71SRichard Henderson                     layout_arg_normal_n(&cum, info, 2);
84639004a71SRichard Henderson                 } else {
84739004a71SRichard Henderson                     layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
84839004a71SRichard Henderson                 }
84939004a71SRichard Henderson                 break;
85039004a71SRichard Henderson             default:
85139004a71SRichard Henderson                 qemu_build_not_reached();
85239004a71SRichard Henderson             }
85339004a71SRichard Henderson             break;
85439004a71SRichard Henderson 
855466d3759SRichard Henderson         case TCG_TYPE_I128:
8565427a9a7SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I128) {
857466d3759SRichard Henderson             case TCG_CALL_ARG_EVEN:
858466d3759SRichard Henderson                 layout_arg_even(&cum);
859466d3759SRichard Henderson                 /* fall through */
860466d3759SRichard Henderson             case TCG_CALL_ARG_NORMAL:
861466d3759SRichard Henderson                 layout_arg_normal_n(&cum, info, 128 / TCG_TARGET_REG_BITS);
862466d3759SRichard Henderson                 break;
863313bdea8SRichard Henderson             case TCG_CALL_ARG_BY_REF:
864313bdea8SRichard Henderson                 layout_arg_by_ref(&cum, info);
865313bdea8SRichard Henderson                 break;
866466d3759SRichard Henderson             default:
867466d3759SRichard Henderson                 qemu_build_not_reached();
868466d3759SRichard Henderson             }
869466d3759SRichard Henderson             break;
870466d3759SRichard Henderson 
87139004a71SRichard Henderson         default:
87239004a71SRichard Henderson             g_assert_not_reached();
87339004a71SRichard Henderson         }
87439004a71SRichard Henderson     }
87539004a71SRichard Henderson     info->nr_in = cum.info_in_idx;
87639004a71SRichard Henderson 
87739004a71SRichard Henderson     /* Validate that we didn't overrun the input array. */
87839004a71SRichard Henderson     assert(cum.info_in_idx <= ARRAY_SIZE(info->in));
87939004a71SRichard Henderson     /* Validate the backend has enough argument space. */
88039004a71SRichard Henderson     assert(cum.arg_slot <= max_reg_slots + max_stk_slots);
881313bdea8SRichard Henderson 
882313bdea8SRichard Henderson     /*
883313bdea8SRichard Henderson      * Relocate the "ref_slot" area to the end of the parameters.
884313bdea8SRichard Henderson      * Minimizing this stack offset helps code size for x86,
885313bdea8SRichard Henderson      * which has a signed 8-bit offset encoding.
886313bdea8SRichard Henderson      */
887313bdea8SRichard Henderson     if (cum.ref_slot != 0) {
888313bdea8SRichard Henderson         int ref_base = 0;
889313bdea8SRichard Henderson 
890313bdea8SRichard Henderson         if (cum.arg_slot > max_reg_slots) {
891313bdea8SRichard Henderson             int align = __alignof(Int128) / sizeof(tcg_target_long);
892313bdea8SRichard Henderson 
893313bdea8SRichard Henderson             ref_base = cum.arg_slot - max_reg_slots;
894313bdea8SRichard Henderson             if (align > 1) {
895313bdea8SRichard Henderson                 ref_base = ROUND_UP(ref_base, align);
896313bdea8SRichard Henderson             }
897313bdea8SRichard Henderson         }
898313bdea8SRichard Henderson         assert(ref_base + cum.ref_slot <= max_stk_slots);
899313bdea8SRichard Henderson 
900313bdea8SRichard Henderson         if (ref_base != 0) {
901313bdea8SRichard Henderson             for (int i = cum.info_in_idx - 1; i >= 0; --i) {
902313bdea8SRichard Henderson                 TCGCallArgumentLoc *loc = &info->in[i];
903313bdea8SRichard Henderson                 switch (loc->kind) {
904313bdea8SRichard Henderson                 case TCG_CALL_ARG_BY_REF:
905313bdea8SRichard Henderson                 case TCG_CALL_ARG_BY_REF_N:
906313bdea8SRichard Henderson                     loc->ref_slot += ref_base;
907313bdea8SRichard Henderson                     break;
908313bdea8SRichard Henderson                 default:
909313bdea8SRichard Henderson                     break;
910313bdea8SRichard Henderson                 }
911313bdea8SRichard Henderson             }
912313bdea8SRichard Henderson         }
913313bdea8SRichard Henderson     }
91439004a71SRichard Henderson }
91539004a71SRichard Henderson 
91691478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
917f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
9181c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
9191c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
92091478cefSRichard Henderson 
92143b972b7SRichard Henderson static void tcg_context_init(unsigned max_cpus)
922c896fe29Sbellard {
923a76aabd3SRichard Henderson     TCGContext *s = &tcg_init_ctx;
924100b5e01SRichard Henderson     int op, total_args, n, i;
925c896fe29Sbellard     TCGOpDef *def;
926c896fe29Sbellard     TCGArgConstraint *args_ct;
9271c2adb95SRichard Henderson     TCGTemp *ts;
928c896fe29Sbellard 
929c896fe29Sbellard     memset(s, 0, sizeof(*s));
930c896fe29Sbellard     s->nb_globals = 0;
931c896fe29Sbellard 
932c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
933c896fe29Sbellard        space */
934c896fe29Sbellard     total_args = 0;
935c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
936c896fe29Sbellard         def = &tcg_op_defs[op];
937c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
938c896fe29Sbellard         total_args += n;
939c896fe29Sbellard     }
940c896fe29Sbellard 
941bc2b17e6SRichard Henderson     args_ct = g_new0(TCGArgConstraint, total_args);
942c896fe29Sbellard 
943c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
944c896fe29Sbellard         def = &tcg_op_defs[op];
945c896fe29Sbellard         def->args_ct = args_ct;
946c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
947c896fe29Sbellard         args_ct += n;
948c896fe29Sbellard     }
949c896fe29Sbellard 
9505cd8f621SRichard Henderson     /* Register helpers.  */
95184fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
952619205fdSEmilio G. Cota     helper_table = g_hash_table_new(NULL, NULL);
95384fd9dd3SRichard Henderson 
954100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
95539004a71SRichard Henderson         init_call_layout(&all_helpers[i]);
95684fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
95772866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
958100b5e01SRichard Henderson     }
9595cd8f621SRichard Henderson 
96022f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
9610c22e176SPhilippe Mathieu-Daudé     init_ffi_layouts();
96222f15579SRichard Henderson #endif
96322f15579SRichard Henderson 
964c896fe29Sbellard     tcg_target_init(s);
965f69d277eSRichard Henderson     process_op_defs(s);
96691478cefSRichard Henderson 
96791478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
96891478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
96991478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
97091478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
97191478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
97291478cefSRichard Henderson             break;
97391478cefSRichard Henderson         }
97491478cefSRichard Henderson     }
97591478cefSRichard Henderson     for (i = 0; i < n; ++i) {
97691478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
97791478cefSRichard Henderson     }
97891478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
97991478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
98091478cefSRichard Henderson     }
981b1311c4aSEmilio G. Cota 
98238b47b19SEmilio G. Cota     alloc_tcg_plugin_context(s);
98338b47b19SEmilio G. Cota 
984b1311c4aSEmilio G. Cota     tcg_ctx = s;
9853468b59eSEmilio G. Cota     /*
9863468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
9873468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
9883468b59eSEmilio G. Cota      * reasoning behind this.
9893468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
9903468b59eSEmilio G. Cota      */
9913468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
992df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
9930e2d61cfSRichard Henderson     tcg_cur_ctxs = 1;
9940e2d61cfSRichard Henderson     tcg_max_ctxs = 1;
9953468b59eSEmilio G. Cota #else
9960e2d61cfSRichard Henderson     tcg_max_ctxs = max_cpus;
9970e2d61cfSRichard Henderson     tcg_ctxs = g_new0(TCGContext *, max_cpus);
9983468b59eSEmilio G. Cota #endif
9991c2adb95SRichard Henderson 
10001c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
10011c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
10021c2adb95SRichard Henderson     cpu_env = temp_tcgv_ptr(ts);
10039002ec79SRichard Henderson }
1004b03cce8eSbellard 
100543b972b7SRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus)
1006a76aabd3SRichard Henderson {
100743b972b7SRichard Henderson     tcg_context_init(max_cpus);
100843b972b7SRichard Henderson     tcg_region_init(tb_size, splitwx, max_cpus);
1009a76aabd3SRichard Henderson }
1010a76aabd3SRichard Henderson 
10116e3b2bfdSEmilio G. Cota /*
10126e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
10136e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
10146e3b2bfdSEmilio G. Cota  */
10156e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
10166e3b2bfdSEmilio G. Cota {
10176e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
10186e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
10196e3b2bfdSEmilio G. Cota     void *next;
10206e3b2bfdSEmilio G. Cota 
1021e8feb96fSEmilio G. Cota  retry:
10226e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
10236e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
10246e3b2bfdSEmilio G. Cota 
10256e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
1026e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
10276e3b2bfdSEmilio G. Cota             return NULL;
10286e3b2bfdSEmilio G. Cota         }
1029e8feb96fSEmilio G. Cota         goto retry;
1030e8feb96fSEmilio G. Cota     }
1031d73415a3SStefan Hajnoczi     qatomic_set(&s->code_gen_ptr, next);
103257a26946SRichard Henderson     s->data_gen_ptr = NULL;
10336e3b2bfdSEmilio G. Cota     return tb;
10346e3b2bfdSEmilio G. Cota }
10356e3b2bfdSEmilio G. Cota 
10369002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
10379002ec79SRichard Henderson {
1038b0a0794aSRichard Henderson     size_t prologue_size;
10398163b749SRichard Henderson 
1040b0a0794aSRichard Henderson     s->code_ptr = s->code_gen_ptr;
1041b0a0794aSRichard Henderson     s->code_buf = s->code_gen_ptr;
10425b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
1043b91ccb31SRichard Henderson 
1044b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1045b0a0794aSRichard Henderson     tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr);
1046b91ccb31SRichard Henderson #endif
10478163b749SRichard Henderson 
10485b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
10495b38ee31SRichard Henderson     s->pool_labels = NULL;
10505b38ee31SRichard Henderson #endif
10515b38ee31SRichard Henderson 
1052653b87ebSRoman Bolshakov     qemu_thread_jit_write();
10538163b749SRichard Henderson     /* Generate the prologue.  */
1054b03cce8eSbellard     tcg_target_qemu_prologue(s);
10555b38ee31SRichard Henderson 
10565b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
10575b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
10585b38ee31SRichard Henderson     {
10591768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
10601768987bSRichard Henderson         tcg_debug_assert(result == 0);
10615b38ee31SRichard Henderson     }
10625b38ee31SRichard Henderson #endif
10635b38ee31SRichard Henderson 
1064b0a0794aSRichard Henderson     prologue_size = tcg_current_code_size(s);
10655584e2dbSIlya Leoshkevich     perf_report_prologue(s->code_gen_ptr, prologue_size);
1066b0a0794aSRichard Henderson 
1067df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1068b0a0794aSRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
1069b0a0794aSRichard Henderson                         (uintptr_t)s->code_buf, prologue_size);
1070df5d2b16SRichard Henderson #endif
10718163b749SRichard Henderson 
1072d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
1073d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
1074c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
107578b54858SRichard Henderson         if (logfile) {
107678b54858SRichard Henderson             fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size);
10775b38ee31SRichard Henderson             if (s->data_gen_ptr) {
1078b0a0794aSRichard Henderson                 size_t code_size = s->data_gen_ptr - s->code_gen_ptr;
10795b38ee31SRichard Henderson                 size_t data_size = prologue_size - code_size;
10805b38ee31SRichard Henderson                 size_t i;
10815b38ee31SRichard Henderson 
108278b54858SRichard Henderson                 disas(logfile, s->code_gen_ptr, code_size);
10835b38ee31SRichard Henderson 
10845b38ee31SRichard Henderson                 for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
10855b38ee31SRichard Henderson                     if (sizeof(tcg_target_ulong) == 8) {
108678b54858SRichard Henderson                         fprintf(logfile,
108778b54858SRichard Henderson                                 "0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
10885b38ee31SRichard Henderson                                 (uintptr_t)s->data_gen_ptr + i,
10895b38ee31SRichard Henderson                                 *(uint64_t *)(s->data_gen_ptr + i));
10905b38ee31SRichard Henderson                     } else {
109178b54858SRichard Henderson                         fprintf(logfile,
109278b54858SRichard Henderson                                 "0x%08" PRIxPTR ":  .long  0x%08x\n",
10935b38ee31SRichard Henderson                                 (uintptr_t)s->data_gen_ptr + i,
10945b38ee31SRichard Henderson                                 *(uint32_t *)(s->data_gen_ptr + i));
10955b38ee31SRichard Henderson                     }
10965b38ee31SRichard Henderson                 }
10975b38ee31SRichard Henderson             } else {
109878b54858SRichard Henderson                 disas(logfile, s->code_gen_ptr, prologue_size);
10995b38ee31SRichard Henderson             }
110078b54858SRichard Henderson             fprintf(logfile, "\n");
1101fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
1102d6b64b2bSRichard Henderson         }
110378b54858SRichard Henderson     }
1104d6b64b2bSRichard Henderson #endif
1105cedbcb01SEmilio G. Cota 
11066eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
11076eea0434SRichard Henderson     /*
11086eea0434SRichard Henderson      * Assert that goto_ptr is implemented completely, setting an epilogue.
11096eea0434SRichard Henderson      * For tci, we use NULL as the signal to return from the interpreter,
11106eea0434SRichard Henderson      * so skip this check.
11116eea0434SRichard Henderson      */
11128b5c2b62SRichard Henderson     tcg_debug_assert(tcg_code_gen_epilogue != NULL);
11136eea0434SRichard Henderson #endif
1114d1c74ab3SRichard Henderson 
1115d1c74ab3SRichard Henderson     tcg_region_prologue_set(s);
1116c896fe29Sbellard }
1117c896fe29Sbellard 
1118c896fe29Sbellard void tcg_func_start(TCGContext *s)
1119c896fe29Sbellard {
1120c896fe29Sbellard     tcg_pool_reset(s);
1121c896fe29Sbellard     s->nb_temps = s->nb_globals;
11220ec9eabcSRichard Henderson 
11230ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
11240ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
11250ec9eabcSRichard Henderson 
1126c0522136SRichard Henderson     /* No constant temps have been previously allocated. */
1127c0522136SRichard Henderson     for (int i = 0; i < TCG_TYPE_COUNT; ++i) {
1128c0522136SRichard Henderson         if (s->const_table[i]) {
1129c0522136SRichard Henderson             g_hash_table_remove_all(s->const_table[i]);
1130c0522136SRichard Henderson         }
1131c0522136SRichard Henderson     }
1132c0522136SRichard Henderson 
1133abebf925SRichard Henderson     s->nb_ops = 0;
1134c896fe29Sbellard     s->nb_labels = 0;
1135c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1136c896fe29Sbellard 
11370a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
11380a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
11390a209d4bSRichard Henderson #endif
11400a209d4bSRichard Henderson 
114115fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
114215fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
1143bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
1144c896fe29Sbellard }
1145c896fe29Sbellard 
1146ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s)
11477ca4b752SRichard Henderson {
11487ca4b752SRichard Henderson     int n = s->nb_temps++;
1149ae30e866SRichard Henderson 
1150ae30e866SRichard Henderson     if (n >= TCG_MAX_TEMPS) {
1151db6b7d0cSRichard Henderson         tcg_raise_tb_overflow(s);
1152ae30e866SRichard Henderson     }
11537ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
11547ca4b752SRichard Henderson }
11557ca4b752SRichard Henderson 
1156ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s)
11577ca4b752SRichard Henderson {
1158fa477d25SRichard Henderson     TCGTemp *ts;
1159fa477d25SRichard Henderson 
11607ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
1161ae30e866SRichard Henderson     tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS);
11627ca4b752SRichard Henderson     s->nb_globals++;
1163fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1164ee17db83SRichard Henderson     ts->kind = TEMP_GLOBAL;
1165fa477d25SRichard Henderson 
1166fa477d25SRichard Henderson     return ts;
1167c896fe29Sbellard }
1168c896fe29Sbellard 
1169085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1170b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1171c896fe29Sbellard {
1172c896fe29Sbellard     TCGTemp *ts;
1173c896fe29Sbellard 
1174b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
1175c896fe29Sbellard         tcg_abort();
1176b3a62939SRichard Henderson     }
11777ca4b752SRichard Henderson 
11787ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1179c896fe29Sbellard     ts->base_type = type;
1180c896fe29Sbellard     ts->type = type;
1181ee17db83SRichard Henderson     ts->kind = TEMP_FIXED;
1182c896fe29Sbellard     ts->reg = reg;
1183c896fe29Sbellard     ts->name = name;
1184c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
11857ca4b752SRichard Henderson 
1186085272b3SRichard Henderson     return ts;
1187a7812ae4Spbrook }
1188a7812ae4Spbrook 
1189b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1190a7812ae4Spbrook {
1191b3a62939SRichard Henderson     s->frame_start = start;
1192b3a62939SRichard Henderson     s->frame_end = start + size;
1193085272b3SRichard Henderson     s->frame_temp
1194085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1195b3a62939SRichard Henderson }
1196a7812ae4Spbrook 
1197085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
1198e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
1199c896fe29Sbellard {
1200b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1201dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
12027ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1203aef85402SRichard Henderson     int indirect_reg = 0;
1204c896fe29Sbellard 
1205c0522136SRichard Henderson     switch (base_ts->kind) {
1206c0522136SRichard Henderson     case TEMP_FIXED:
1207c0522136SRichard Henderson         break;
1208c0522136SRichard Henderson     case TEMP_GLOBAL:
12095a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
12105a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1211b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
12125a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
12135a18407fSRichard Henderson                             ? 2 : 1);
12145a18407fSRichard Henderson         indirect_reg = 1;
1215c0522136SRichard Henderson         break;
1216c0522136SRichard Henderson     default:
1217c0522136SRichard Henderson         g_assert_not_reached();
1218b3915dbbSRichard Henderson     }
1219b3915dbbSRichard Henderson 
12207ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
12217ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1222c896fe29Sbellard         char buf[64];
12237ca4b752SRichard Henderson 
12247ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1225c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1226b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1227c896fe29Sbellard         ts->mem_allocated = 1;
1228b3a62939SRichard Henderson         ts->mem_base = base_ts;
1229aef85402SRichard Henderson         ts->mem_offset = offset;
1230c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1231c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1232c896fe29Sbellard         ts->name = strdup(buf);
1233c896fe29Sbellard 
12347ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
12357ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
12367ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1237b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
12387ca4b752SRichard Henderson         ts2->mem_allocated = 1;
12397ca4b752SRichard Henderson         ts2->mem_base = base_ts;
1240aef85402SRichard Henderson         ts2->mem_offset = offset + 4;
1241fac87bd2SRichard Henderson         ts2->temp_subindex = 1;
1242c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1243c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1244120c1084SRichard Henderson         ts2->name = strdup(buf);
12457ca4b752SRichard Henderson     } else {
1246c896fe29Sbellard         ts->base_type = type;
1247c896fe29Sbellard         ts->type = type;
1248b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1249c896fe29Sbellard         ts->mem_allocated = 1;
1250b3a62939SRichard Henderson         ts->mem_base = base_ts;
1251c896fe29Sbellard         ts->mem_offset = offset;
1252c896fe29Sbellard         ts->name = name;
1253c896fe29Sbellard     }
1254085272b3SRichard Henderson     return ts;
1255c896fe29Sbellard }
1256c896fe29Sbellard 
12575bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local)
1258c896fe29Sbellard {
1259b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1260f57c6915SRichard Henderson     TCGTempKind kind = temp_local ? TEMP_TB : TEMP_NORMAL;
1261c896fe29Sbellard     TCGTemp *ts;
1262641d5fbeSbellard     int idx, k;
1263c896fe29Sbellard 
12640ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
12650ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
12660ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
12670ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
12680ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
12690ec9eabcSRichard Henderson 
1270e8996ee0Sbellard         ts = &s->temps[idx];
1271e8996ee0Sbellard         ts->temp_allocated = 1;
12727ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
1273ee17db83SRichard Henderson         tcg_debug_assert(ts->kind == kind);
1274e8996ee0Sbellard     } else {
127543eef72fSRichard Henderson         int i, n;
127643eef72fSRichard Henderson 
127743eef72fSRichard Henderson         switch (type) {
127843eef72fSRichard Henderson         case TCG_TYPE_I32:
127943eef72fSRichard Henderson         case TCG_TYPE_V64:
128043eef72fSRichard Henderson         case TCG_TYPE_V128:
128143eef72fSRichard Henderson         case TCG_TYPE_V256:
128243eef72fSRichard Henderson             n = 1;
128343eef72fSRichard Henderson             break;
128443eef72fSRichard Henderson         case TCG_TYPE_I64:
128543eef72fSRichard Henderson             n = 64 / TCG_TARGET_REG_BITS;
128643eef72fSRichard Henderson             break;
128743eef72fSRichard Henderson         case TCG_TYPE_I128:
128843eef72fSRichard Henderson             n = 128 / TCG_TARGET_REG_BITS;
128943eef72fSRichard Henderson             break;
129043eef72fSRichard Henderson         default:
129143eef72fSRichard Henderson             g_assert_not_reached();
129243eef72fSRichard Henderson         }
129343eef72fSRichard Henderson 
12947ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
129543eef72fSRichard Henderson         ts->base_type = type;
129643eef72fSRichard Henderson         ts->temp_allocated = 1;
129743eef72fSRichard Henderson         ts->kind = kind;
129843eef72fSRichard Henderson 
129943eef72fSRichard Henderson         if (n == 1) {
130043eef72fSRichard Henderson             ts->type = type;
130143eef72fSRichard Henderson         } else {
130243eef72fSRichard Henderson             ts->type = TCG_TYPE_REG;
130343eef72fSRichard Henderson 
130443eef72fSRichard Henderson             for (i = 1; i < n; ++i) {
13057ca4b752SRichard Henderson                 TCGTemp *ts2 = tcg_temp_alloc(s);
13067ca4b752SRichard Henderson 
130743eef72fSRichard Henderson                 tcg_debug_assert(ts2 == ts + i);
130843eef72fSRichard Henderson                 ts2->base_type = type;
130943eef72fSRichard Henderson                 ts2->type = TCG_TYPE_REG;
13107ca4b752SRichard Henderson                 ts2->temp_allocated = 1;
131143eef72fSRichard Henderson                 ts2->temp_subindex = i;
1312ee17db83SRichard Henderson                 ts2->kind = kind;
131343eef72fSRichard Henderson             }
1314c896fe29Sbellard         }
1315e8996ee0Sbellard     }
131627bfd83cSPeter Maydell 
131727bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
131827bfd83cSPeter Maydell     s->temps_in_use++;
131927bfd83cSPeter Maydell #endif
1320085272b3SRichard Henderson     return ts;
1321c896fe29Sbellard }
1322c896fe29Sbellard 
1323d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1324d2fd745fSRichard Henderson {
1325d2fd745fSRichard Henderson     TCGTemp *t;
1326d2fd745fSRichard Henderson 
1327d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1328d2fd745fSRichard Henderson     switch (type) {
1329d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1330d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1331d2fd745fSRichard Henderson         break;
1332d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1333d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1334d2fd745fSRichard Henderson         break;
1335d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1336d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1337d2fd745fSRichard Henderson         break;
1338d2fd745fSRichard Henderson     default:
1339d2fd745fSRichard Henderson         g_assert_not_reached();
1340d2fd745fSRichard Henderson     }
1341d2fd745fSRichard Henderson #endif
1342d2fd745fSRichard Henderson 
1343d2fd745fSRichard Henderson     t = tcg_temp_new_internal(type, 0);
1344d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1345d2fd745fSRichard Henderson }
1346d2fd745fSRichard Henderson 
1347d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1348d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1349d2fd745fSRichard Henderson {
1350d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1351d2fd745fSRichard Henderson 
1352d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1353d2fd745fSRichard Henderson 
1354d2fd745fSRichard Henderson     t = tcg_temp_new_internal(t->base_type, 0);
1355d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1356d2fd745fSRichard Henderson }
1357d2fd745fSRichard Henderson 
13585bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1359c896fe29Sbellard {
1360b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1361085272b3SRichard Henderson     int k, idx;
1362c896fe29Sbellard 
1363c7482438SRichard Henderson     switch (ts->kind) {
1364c7482438SRichard Henderson     case TEMP_CONST:
1365c7482438SRichard Henderson         /*
1366c7482438SRichard Henderson          * In order to simplify users of tcg_constant_*,
1367c7482438SRichard Henderson          * silently ignore free.
1368c7482438SRichard Henderson          */
1369c0522136SRichard Henderson         return;
1370c7482438SRichard Henderson     case TEMP_NORMAL:
1371f57c6915SRichard Henderson     case TEMP_TB:
1372c7482438SRichard Henderson         break;
1373c7482438SRichard Henderson     default:
1374c7482438SRichard Henderson         g_assert_not_reached();
1375c0522136SRichard Henderson     }
1376c0522136SRichard Henderson 
1377eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
1378e8996ee0Sbellard     ts->temp_allocated = 0;
13790ec9eabcSRichard Henderson 
13800ef3d704SRichard Henderson #if defined(CONFIG_DEBUG_TCG)
13810ef3d704SRichard Henderson     assert(s->temps_in_use > 0);
13820ef3d704SRichard Henderson     s->temps_in_use--;
13830ef3d704SRichard Henderson #endif
13840ef3d704SRichard Henderson 
1385085272b3SRichard Henderson     idx = temp_idx(ts);
1386ee17db83SRichard Henderson     k = ts->base_type + (ts->kind == TEMP_NORMAL ? 0 : TCG_TYPE_COUNT);
13870ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
1388e8996ee0Sbellard }
1389e8996ee0Sbellard 
1390c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val)
1391c0522136SRichard Henderson {
1392c0522136SRichard Henderson     TCGContext *s = tcg_ctx;
1393c0522136SRichard Henderson     GHashTable *h = s->const_table[type];
1394c0522136SRichard Henderson     TCGTemp *ts;
1395c0522136SRichard Henderson 
1396c0522136SRichard Henderson     if (h == NULL) {
1397c0522136SRichard Henderson         h = g_hash_table_new(g_int64_hash, g_int64_equal);
1398c0522136SRichard Henderson         s->const_table[type] = h;
1399c0522136SRichard Henderson     }
1400c0522136SRichard Henderson 
1401c0522136SRichard Henderson     ts = g_hash_table_lookup(h, &val);
1402c0522136SRichard Henderson     if (ts == NULL) {
1403aef85402SRichard Henderson         int64_t *val_ptr;
1404aef85402SRichard Henderson 
1405c0522136SRichard Henderson         ts = tcg_temp_alloc(s);
1406c0522136SRichard Henderson 
1407c0522136SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
1408c0522136SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
1409c0522136SRichard Henderson 
1410aef85402SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
1411aef85402SRichard Henderson 
1412c0522136SRichard Henderson             ts->base_type = TCG_TYPE_I64;
1413c0522136SRichard Henderson             ts->type = TCG_TYPE_I32;
1414c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1415c0522136SRichard Henderson             ts->temp_allocated = 1;
1416c0522136SRichard Henderson 
1417c0522136SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
1418c0522136SRichard Henderson             ts2->type = TCG_TYPE_I32;
1419c0522136SRichard Henderson             ts2->kind = TEMP_CONST;
1420c0522136SRichard Henderson             ts2->temp_allocated = 1;
1421fac87bd2SRichard Henderson             ts2->temp_subindex = 1;
1422aef85402SRichard Henderson 
1423aef85402SRichard Henderson             /*
1424aef85402SRichard Henderson              * Retain the full value of the 64-bit constant in the low
1425aef85402SRichard Henderson              * part, so that the hash table works.  Actual uses will
1426aef85402SRichard Henderson              * truncate the value to the low part.
1427aef85402SRichard Henderson              */
1428aef85402SRichard Henderson             ts[HOST_BIG_ENDIAN].val = val;
1429aef85402SRichard Henderson             ts[!HOST_BIG_ENDIAN].val = val >> 32;
1430aef85402SRichard Henderson             val_ptr = &ts[HOST_BIG_ENDIAN].val;
1431c0522136SRichard Henderson         } else {
1432c0522136SRichard Henderson             ts->base_type = type;
1433c0522136SRichard Henderson             ts->type = type;
1434c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1435c0522136SRichard Henderson             ts->temp_allocated = 1;
1436c0522136SRichard Henderson             ts->val = val;
1437aef85402SRichard Henderson             val_ptr = &ts->val;
1438c0522136SRichard Henderson         }
1439aef85402SRichard Henderson         g_hash_table_insert(h, val_ptr, ts);
1440c0522136SRichard Henderson     }
1441c0522136SRichard Henderson 
1442c0522136SRichard Henderson     return ts;
1443c0522136SRichard Henderson }
1444c0522136SRichard Henderson 
1445c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val)
1446c0522136SRichard Henderson {
1447c0522136SRichard Henderson     val = dup_const(vece, val);
1448c0522136SRichard Henderson     return temp_tcgv_vec(tcg_constant_internal(type, val));
1449c0522136SRichard Henderson }
1450c0522136SRichard Henderson 
145188d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val)
145288d4005bSRichard Henderson {
145388d4005bSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
145488d4005bSRichard Henderson 
145588d4005bSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
145688d4005bSRichard Henderson     return tcg_constant_vec(t->base_type, vece, val);
145788d4005bSRichard Henderson }
145888d4005bSRichard Henderson 
1459a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
1460a7812ae4Spbrook {
1461a7812ae4Spbrook     TCGv_i32 t0;
1462a7812ae4Spbrook     t0 = tcg_temp_new_i32();
1463e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
1464e8996ee0Sbellard     return t0;
1465c896fe29Sbellard }
1466c896fe29Sbellard 
1467a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
1468c896fe29Sbellard {
1469a7812ae4Spbrook     TCGv_i64 t0;
1470a7812ae4Spbrook     t0 = tcg_temp_new_i64();
1471e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
1472e8996ee0Sbellard     return t0;
1473c896fe29Sbellard }
1474c896fe29Sbellard 
1475a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
1476bdffd4a9Saurel32 {
1477a7812ae4Spbrook     TCGv_i32 t0;
1478a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
1479bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
1480bdffd4a9Saurel32     return t0;
1481bdffd4a9Saurel32 }
1482bdffd4a9Saurel32 
1483a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
1484bdffd4a9Saurel32 {
1485a7812ae4Spbrook     TCGv_i64 t0;
1486a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
1487bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
1488bdffd4a9Saurel32     return t0;
1489bdffd4a9Saurel32 }
1490bdffd4a9Saurel32 
149127bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
149227bfd83cSPeter Maydell void tcg_clear_temp_count(void)
149327bfd83cSPeter Maydell {
1494b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
149527bfd83cSPeter Maydell     s->temps_in_use = 0;
149627bfd83cSPeter Maydell }
149727bfd83cSPeter Maydell 
149827bfd83cSPeter Maydell int tcg_check_temp_count(void)
149927bfd83cSPeter Maydell {
1500b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
150127bfd83cSPeter Maydell     if (s->temps_in_use) {
150227bfd83cSPeter Maydell         /* Clear the count so that we don't give another
150327bfd83cSPeter Maydell          * warning immediately next time around.
150427bfd83cSPeter Maydell          */
150527bfd83cSPeter Maydell         s->temps_in_use = 0;
150627bfd83cSPeter Maydell         return 1;
150727bfd83cSPeter Maydell     }
150827bfd83cSPeter Maydell     return 0;
150927bfd83cSPeter Maydell }
151027bfd83cSPeter Maydell #endif
151127bfd83cSPeter Maydell 
1512be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1513be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1514be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1515be0f34b5SRichard Henderson {
1516d2fd745fSRichard Henderson     const bool have_vec
1517d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1518d2fd745fSRichard Henderson 
1519be0f34b5SRichard Henderson     switch (op) {
1520be0f34b5SRichard Henderson     case INDEX_op_discard:
1521be0f34b5SRichard Henderson     case INDEX_op_set_label:
1522be0f34b5SRichard Henderson     case INDEX_op_call:
1523be0f34b5SRichard Henderson     case INDEX_op_br:
1524be0f34b5SRichard Henderson     case INDEX_op_mb:
1525be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1526be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1527be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1528f4e01e30SRichard Henderson     case INDEX_op_goto_ptr:
1529be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i32:
1530be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i32:
1531be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i64:
1532be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i64:
1533be0f34b5SRichard Henderson         return true;
1534be0f34b5SRichard Henderson 
153507ce0b05SRichard Henderson     case INDEX_op_qemu_st8_i32:
153607ce0b05SRichard Henderson         return TCG_TARGET_HAS_qemu_st8_i32;
153707ce0b05SRichard Henderson 
1538be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1539be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1540be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1541be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1542be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1543be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1544be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1545be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1546be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1547be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1548be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1549be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1550be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1551be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1552be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1553be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1554be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1555be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1556be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1557be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1558be0f34b5SRichard Henderson         return true;
1559be0f34b5SRichard Henderson 
1560be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1561be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1562be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1563be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1564be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1565be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1566be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1567be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1568be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1569be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1570be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1571be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1572be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1573be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1574be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1575be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1576be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1577be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1578be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1579be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1580fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
1581fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
1582be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1583be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1584be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1585be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1586be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1587be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1588be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1589be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1590be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1591be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1592be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1593be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1594be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1595be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1596be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1597be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1598be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1599be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1600be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1601be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1602be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1603be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1604be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1605be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1606be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1607be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1608be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1609be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1610be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1611be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1612be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1613be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1614be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1615be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1616be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1617be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1618be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1619be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1620be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1621be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1622be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1623be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1624be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1625be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1626be0f34b5SRichard Henderson 
1627be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1628be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1629be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1630be0f34b5SRichard Henderson 
1631be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1632be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1633be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1634be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1635be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1636be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1637be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1638be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1639be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1640be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1641be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1642be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1643be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1644be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1645be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1646be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1647be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1648be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1649be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1650be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1651be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1652be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1653be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1654be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1655be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1656be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1657be0f34b5SRichard Henderson 
1658be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1659be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1660be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1661be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1662be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1663be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1664be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1665be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1666be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1667be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
1668be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
1669be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
1670be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
1671be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
1672be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
1673be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
1674be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
1675be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
1676be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
1677be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
1678fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
1679fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
1680be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
1681be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrl_i64_i32;
1682be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
1683be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrh_i64_i32;
1684be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
1685be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
1686be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
1687be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
1688be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
1689be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
1690be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
1691be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
1692be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
1693be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
1694be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
1695be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
1696be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
1697be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
1698be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
1699be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
1700be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
1701be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
1702be0f34b5SRichard Henderson     case INDEX_op_not_i64:
1703be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
1704be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
1705be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
1706be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
1707be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
1708be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
1709be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
1710be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
1711be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
1712be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
1713be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
1714be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
1715be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
1716be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
1717be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
1718be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
1719be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
1720be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
1721be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
1722be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
1723be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
1724be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
1725be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
1726be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
1727be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
1728be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
1729be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
1730be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
1731be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
1732be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
1733be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
1734be0f34b5SRichard Henderson 
1735d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
1736d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
173737ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
1738d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
1739d2fd745fSRichard Henderson     case INDEX_op_st_vec:
1740d2fd745fSRichard Henderson     case INDEX_op_add_vec:
1741d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
1742d2fd745fSRichard Henderson     case INDEX_op_and_vec:
1743d2fd745fSRichard Henderson     case INDEX_op_or_vec:
1744d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
1745212be173SRichard Henderson     case INDEX_op_cmp_vec:
1746d2fd745fSRichard Henderson         return have_vec;
1747d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
1748d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
1749d2fd745fSRichard Henderson     case INDEX_op_not_vec:
1750d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
1751d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
1752d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
1753bcefc902SRichard Henderson     case INDEX_op_abs_vec:
1754bcefc902SRichard Henderson         return have_vec && TCG_TARGET_HAS_abs_vec;
1755d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
1756d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
1757d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
1758d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
1759ed523473SRichard Henderson     case INDEX_op_nand_vec:
1760ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_nand_vec;
1761ed523473SRichard Henderson     case INDEX_op_nor_vec:
1762ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_nor_vec;
1763ed523473SRichard Henderson     case INDEX_op_eqv_vec:
1764ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_eqv_vec;
17653774030aSRichard Henderson     case INDEX_op_mul_vec:
17663774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
1767d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
1768d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
1769d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
1770d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
1771d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
1772d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
1773d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
1774d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
1775d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
1776d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
1777d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
1778d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
1779b0f7e744SRichard Henderson     case INDEX_op_rotli_vec:
1780b0f7e744SRichard Henderson         return have_vec && TCG_TARGET_HAS_roti_vec;
178123850a74SRichard Henderson     case INDEX_op_rotls_vec:
178223850a74SRichard Henderson         return have_vec && TCG_TARGET_HAS_rots_vec;
17835d0ceda9SRichard Henderson     case INDEX_op_rotlv_vec:
17845d0ceda9SRichard Henderson     case INDEX_op_rotrv_vec:
17855d0ceda9SRichard Henderson         return have_vec && TCG_TARGET_HAS_rotv_vec;
17868afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
17878afaf050SRichard Henderson     case INDEX_op_usadd_vec:
17888afaf050SRichard Henderson     case INDEX_op_sssub_vec:
17898afaf050SRichard Henderson     case INDEX_op_ussub_vec:
17908afaf050SRichard Henderson         return have_vec && TCG_TARGET_HAS_sat_vec;
1791dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
1792dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
1793dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
1794dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
1795dd0a0fcdSRichard Henderson         return have_vec && TCG_TARGET_HAS_minmax_vec;
179638dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
179738dc1294SRichard Henderson         return have_vec && TCG_TARGET_HAS_bitsel_vec;
1798f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
1799f75da298SRichard Henderson         return have_vec && TCG_TARGET_HAS_cmpsel_vec;
1800d2fd745fSRichard Henderson 
1801db432672SRichard Henderson     default:
1802db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
1803db432672SRichard Henderson         return true;
1804be0f34b5SRichard Henderson     }
1805be0f34b5SRichard Henderson }
1806be0f34b5SRichard Henderson 
180739004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs);
180839004a71SRichard Henderson 
1809ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
1810c896fe29Sbellard {
18113e92aa34SRichard Henderson     const TCGHelperInfo *info;
181239004a71SRichard Henderson     TCGv_i64 extend_free[MAX_CALL_IARGS];
181339004a71SRichard Henderson     int n_extend = 0;
181475e8b9b7SRichard Henderson     TCGOp *op;
181539004a71SRichard Henderson     int i, n, pi = 0, total_args;
1816afb49896SRichard Henderson 
1817619205fdSEmilio G. Cota     info = g_hash_table_lookup(helper_table, (gpointer)func);
181839004a71SRichard Henderson     total_args = info->nr_out + info->nr_in + 2;
181939004a71SRichard Henderson     op = tcg_op_alloc(INDEX_op_call, total_args);
18202bece2c8SRichard Henderson 
182138b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
182217083f6fSEmilio Cota     /* Flag helpers that may affect guest state */
182317083f6fSEmilio Cota     if (tcg_ctx->plugin_insn &&
182417083f6fSEmilio Cota         !(info->flags & TCG_CALL_PLUGIN) &&
182517083f6fSEmilio Cota         !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) {
182638b47b19SEmilio G. Cota         tcg_ctx->plugin_insn->calls_helpers = true;
182738b47b19SEmilio G. Cota     }
182838b47b19SEmilio G. Cota #endif
182938b47b19SEmilio G. Cota 
183039004a71SRichard Henderson     TCGOP_CALLO(op) = n = info->nr_out;
183139004a71SRichard Henderson     switch (n) {
183239004a71SRichard Henderson     case 0:
183339004a71SRichard Henderson         tcg_debug_assert(ret == NULL);
183439004a71SRichard Henderson         break;
183539004a71SRichard Henderson     case 1:
183639004a71SRichard Henderson         tcg_debug_assert(ret != NULL);
183739004a71SRichard Henderson         op->args[pi++] = temp_arg(ret);
183839004a71SRichard Henderson         break;
183939004a71SRichard Henderson     case 2:
1840466d3759SRichard Henderson     case 4:
184139004a71SRichard Henderson         tcg_debug_assert(ret != NULL);
1842466d3759SRichard Henderson         tcg_debug_assert(ret->base_type == ret->type + ctz32(n));
184339004a71SRichard Henderson         tcg_debug_assert(ret->temp_subindex == 0);
1844466d3759SRichard Henderson         for (i = 0; i < n; ++i) {
1845466d3759SRichard Henderson             op->args[pi++] = temp_arg(ret + i);
1846466d3759SRichard Henderson         }
184739004a71SRichard Henderson         break;
184839004a71SRichard Henderson     default:
184939004a71SRichard Henderson         g_assert_not_reached();
185039004a71SRichard Henderson     }
18517319d83aSRichard Henderson 
185239004a71SRichard Henderson     TCGOP_CALLI(op) = n = info->nr_in;
185339004a71SRichard Henderson     for (i = 0; i < n; i++) {
185439004a71SRichard Henderson         const TCGCallArgumentLoc *loc = &info->in[i];
185539004a71SRichard Henderson         TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex;
185639004a71SRichard Henderson 
185739004a71SRichard Henderson         switch (loc->kind) {
185839004a71SRichard Henderson         case TCG_CALL_ARG_NORMAL:
1859313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF:
1860313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF_N:
186139004a71SRichard Henderson             op->args[pi++] = temp_arg(ts);
186239004a71SRichard Henderson             break;
186339004a71SRichard Henderson 
186439004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
186539004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
186639004a71SRichard Henderson             {
18672bece2c8SRichard Henderson                 TCGv_i64 temp = tcg_temp_new_i64();
186839004a71SRichard Henderson                 TCGv_i32 orig = temp_tcgv_i32(ts);
186939004a71SRichard Henderson 
187039004a71SRichard Henderson                 if (loc->kind == TCG_CALL_ARG_EXTEND_S) {
187118cf3d07SRichard Henderson                     tcg_gen_ext_i32_i64(temp, orig);
18722bece2c8SRichard Henderson                 } else {
187318cf3d07SRichard Henderson                     tcg_gen_extu_i32_i64(temp, orig);
18742bece2c8SRichard Henderson                 }
187539004a71SRichard Henderson                 op->args[pi++] = tcgv_i64_arg(temp);
187639004a71SRichard Henderson                 extend_free[n_extend++] = temp;
18772bece2c8SRichard Henderson             }
187839004a71SRichard Henderson             break;
18792bece2c8SRichard Henderson 
1880e2a9dd6bSRichard Henderson         default:
1881e2a9dd6bSRichard Henderson             g_assert_not_reached();
1882e2a9dd6bSRichard Henderson         }
1883c896fe29Sbellard     }
188475e8b9b7SRichard Henderson     op->args[pi++] = (uintptr_t)func;
18853e92aa34SRichard Henderson     op->args[pi++] = (uintptr_t)info;
188639004a71SRichard Henderson     tcg_debug_assert(pi == total_args);
1887a7812ae4Spbrook 
188839004a71SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
18892bece2c8SRichard Henderson 
189039004a71SRichard Henderson     tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free));
189139004a71SRichard Henderson     for (i = 0; i < n_extend; ++i) {
189239004a71SRichard Henderson         tcg_temp_free_i64(extend_free[i]);
1893eb8b0224SRichard Henderson     }
1894a7812ae4Spbrook }
1895c896fe29Sbellard 
18968fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
1897c896fe29Sbellard {
1898ac3b8891SRichard Henderson     int i, n;
1899ac3b8891SRichard Henderson 
1900ee17db83SRichard Henderson     for (i = 0, n = s->nb_temps; i < n; i++) {
1901ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
1902ee17db83SRichard Henderson         TCGTempVal val = TEMP_VAL_MEM;
1903ee17db83SRichard Henderson 
1904ee17db83SRichard Henderson         switch (ts->kind) {
1905c0522136SRichard Henderson         case TEMP_CONST:
1906c0522136SRichard Henderson             val = TEMP_VAL_CONST;
1907c0522136SRichard Henderson             break;
1908ee17db83SRichard Henderson         case TEMP_FIXED:
1909ee17db83SRichard Henderson             val = TEMP_VAL_REG;
1910ee17db83SRichard Henderson             break;
1911ee17db83SRichard Henderson         case TEMP_GLOBAL:
1912ee17db83SRichard Henderson             break;
1913ee17db83SRichard Henderson         case TEMP_NORMAL:
1914c7482438SRichard Henderson         case TEMP_EBB:
1915ee17db83SRichard Henderson             val = TEMP_VAL_DEAD;
1916ee17db83SRichard Henderson             /* fall through */
1917f57c6915SRichard Henderson         case TEMP_TB:
1918e8996ee0Sbellard             ts->mem_allocated = 0;
1919ee17db83SRichard Henderson             break;
1920ee17db83SRichard Henderson         default:
1921ee17db83SRichard Henderson             g_assert_not_reached();
1922ee17db83SRichard Henderson         }
1923ee17db83SRichard Henderson         ts->val_type = val;
1924e8996ee0Sbellard     }
1925f8b2f202SRichard Henderson 
1926f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
1927c896fe29Sbellard }
1928c896fe29Sbellard 
1929f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
1930f8b2f202SRichard Henderson                                  TCGTemp *ts)
1931c896fe29Sbellard {
19321807f4c4SRichard Henderson     int idx = temp_idx(ts);
1933ac56dd48Spbrook 
1934ee17db83SRichard Henderson     switch (ts->kind) {
1935ee17db83SRichard Henderson     case TEMP_FIXED:
1936ee17db83SRichard Henderson     case TEMP_GLOBAL:
1937ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
1938ee17db83SRichard Henderson         break;
1939f57c6915SRichard Henderson     case TEMP_TB:
1940641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
1941ee17db83SRichard Henderson         break;
1942c7482438SRichard Henderson     case TEMP_EBB:
1943c7482438SRichard Henderson         snprintf(buf, buf_size, "ebb%d", idx - s->nb_globals);
1944c7482438SRichard Henderson         break;
1945ee17db83SRichard Henderson     case TEMP_NORMAL:
1946ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
1947ee17db83SRichard Henderson         break;
1948c0522136SRichard Henderson     case TEMP_CONST:
1949c0522136SRichard Henderson         switch (ts->type) {
1950c0522136SRichard Henderson         case TCG_TYPE_I32:
1951c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val);
1952c0522136SRichard Henderson             break;
1953c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32
1954c0522136SRichard Henderson         case TCG_TYPE_I64:
1955c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%" PRIx64, ts->val);
1956c0522136SRichard Henderson             break;
1957c0522136SRichard Henderson #endif
1958c0522136SRichard Henderson         case TCG_TYPE_V64:
1959c0522136SRichard Henderson         case TCG_TYPE_V128:
1960c0522136SRichard Henderson         case TCG_TYPE_V256:
1961c0522136SRichard Henderson             snprintf(buf, buf_size, "v%d$0x%" PRIx64,
1962c0522136SRichard Henderson                      64 << (ts->type - TCG_TYPE_V64), ts->val);
1963c0522136SRichard Henderson             break;
1964c0522136SRichard Henderson         default:
1965c0522136SRichard Henderson             g_assert_not_reached();
1966c0522136SRichard Henderson         }
1967c0522136SRichard Henderson         break;
1968c896fe29Sbellard     }
1969c896fe29Sbellard     return buf;
1970c896fe29Sbellard }
1971c896fe29Sbellard 
197243439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
197343439139SRichard Henderson                              int buf_size, TCGArg arg)
1974f8b2f202SRichard Henderson {
197543439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
1976f8b2f202SRichard Henderson }
1977f8b2f202SRichard Henderson 
1978f48f3edeSblueswir1 static const char * const cond_name[] =
1979f48f3edeSblueswir1 {
19800aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
19810aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
1982f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
1983f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
1984f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
1985f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
1986f48f3edeSblueswir1     [TCG_COND_LE] = "le",
1987f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
1988f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
1989f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
1990f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
1991f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
1992f48f3edeSblueswir1 };
1993f48f3edeSblueswir1 
1994f713d6adSRichard Henderson static const char * const ldst_name[] =
1995f713d6adSRichard Henderson {
1996f713d6adSRichard Henderson     [MO_UB]   = "ub",
1997f713d6adSRichard Henderson     [MO_SB]   = "sb",
1998f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
1999f713d6adSRichard Henderson     [MO_LESW] = "lesw",
2000f713d6adSRichard Henderson     [MO_LEUL] = "leul",
2001f713d6adSRichard Henderson     [MO_LESL] = "lesl",
2002fc313c64SFrédéric Pétrot     [MO_LEUQ] = "leq",
2003f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
2004f713d6adSRichard Henderson     [MO_BESW] = "besw",
2005f713d6adSRichard Henderson     [MO_BEUL] = "beul",
2006f713d6adSRichard Henderson     [MO_BESL] = "besl",
2007fc313c64SFrédéric Pétrot     [MO_BEUQ] = "beq",
2008f713d6adSRichard Henderson };
2009f713d6adSRichard Henderson 
20101f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
201152bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY
20121f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
20131f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
20141f00b27fSSergey Sorokin #else
20151f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
20161f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
20171f00b27fSSergey Sorokin #endif
20181f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
20191f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
20201f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
20211f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
20221f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
20231f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
20241f00b27fSSergey Sorokin };
20251f00b27fSSergey Sorokin 
2026587195bdSRichard Henderson static const char bswap_flag_name[][6] = {
2027587195bdSRichard Henderson     [TCG_BSWAP_IZ] = "iz",
2028587195bdSRichard Henderson     [TCG_BSWAP_OZ] = "oz",
2029587195bdSRichard Henderson     [TCG_BSWAP_OS] = "os",
2030587195bdSRichard Henderson     [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz",
2031587195bdSRichard Henderson     [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os",
2032587195bdSRichard Henderson };
2033587195bdSRichard Henderson 
2034b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
2035b016486eSRichard Henderson {
2036b016486eSRichard Henderson     return (d & (d - 1)) == 0;
2037b016486eSRichard Henderson }
2038b016486eSRichard Henderson 
2039b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
2040b016486eSRichard Henderson {
2041b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
2042b016486eSRichard Henderson         return ctz32(d);
2043b016486eSRichard Henderson     } else {
2044b016486eSRichard Henderson         return ctz64(d);
2045b016486eSRichard Henderson     }
2046b016486eSRichard Henderson }
2047b016486eSRichard Henderson 
2048b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */
2049b7a83ff8SRichard Henderson #define ne_fprintf(...) \
2050b7a83ff8SRichard Henderson     ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; })
2051b7a83ff8SRichard Henderson 
2052b7a83ff8SRichard Henderson static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
2053c896fe29Sbellard {
2054c896fe29Sbellard     char buf[128];
2055c45cb8bbSRichard Henderson     TCGOp *op;
2056c896fe29Sbellard 
205715fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
2058c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
2059c45cb8bbSRichard Henderson         const TCGOpDef *def;
2060c45cb8bbSRichard Henderson         TCGOpcode c;
2061bdfb460eSRichard Henderson         int col = 0;
2062c45cb8bbSRichard Henderson 
2063c45cb8bbSRichard Henderson         c = op->opc;
2064c896fe29Sbellard         def = &tcg_op_defs[c];
2065c45cb8bbSRichard Henderson 
2066765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
2067b016486eSRichard Henderson             nb_oargs = 0;
2068b7a83ff8SRichard Henderson             col += ne_fprintf(f, "\n ----");
20699aef40edSRichard Henderson 
20709aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
20719aef40edSRichard Henderson                 target_ulong a;
20727e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
2073efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
20747e4597d7Sbellard #else
2075efee3746SRichard Henderson                 a = op->args[i];
20767e4597d7Sbellard #endif
2077b7a83ff8SRichard Henderson                 col += ne_fprintf(f, " " TARGET_FMT_lx, a);
2078eeacee4dSBlue Swirl             }
20797e4597d7Sbellard         } else if (c == INDEX_op_call) {
20803e92aa34SRichard Henderson             const TCGHelperInfo *info = tcg_call_info(op);
2081fa52e660SRichard Henderson             void *func = tcg_call_func(op);
20823e92aa34SRichard Henderson 
2083c896fe29Sbellard             /* variable number of arguments */
2084cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2085cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2086c896fe29Sbellard             nb_cargs = def->nb_cargs;
2087b03cce8eSbellard 
2088b7a83ff8SRichard Henderson             col += ne_fprintf(f, " %s ", def->name);
20893e92aa34SRichard Henderson 
20903e92aa34SRichard Henderson             /*
20913e92aa34SRichard Henderson              * Print the function name from TCGHelperInfo, if available.
20923e92aa34SRichard Henderson              * Note that plugins have a template function for the info,
20933e92aa34SRichard Henderson              * but the actual function pointer comes from the plugin.
20943e92aa34SRichard Henderson              */
20953e92aa34SRichard Henderson             if (func == info->func) {
2096b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s", info->name);
20973e92aa34SRichard Henderson             } else {
2098b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "plugin(%p)", func);
20993e92aa34SRichard Henderson             }
21003e92aa34SRichard Henderson 
2101b7a83ff8SRichard Henderson             col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs);
2102b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
2103b7a83ff8SRichard Henderson                 col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf),
2104efee3746SRichard Henderson                                                             op->args[i]));
2105b03cce8eSbellard             }
2106cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
2107efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
210839004a71SRichard Henderson                 const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
2109b7a83ff8SRichard Henderson                 col += ne_fprintf(f, ",%s", t);
2110e8996ee0Sbellard             }
2111b03cce8eSbellard         } else {
2112b7a83ff8SRichard Henderson             col += ne_fprintf(f, " %s ", def->name);
2113c45cb8bbSRichard Henderson 
2114c896fe29Sbellard             nb_oargs = def->nb_oargs;
2115c896fe29Sbellard             nb_iargs = def->nb_iargs;
2116c896fe29Sbellard             nb_cargs = def->nb_cargs;
2117c896fe29Sbellard 
2118d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
2119b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "v%d,e%d,", 64 << TCGOP_VECL(op),
2120d2fd745fSRichard Henderson                                   8 << TCGOP_VECE(op));
2121d2fd745fSRichard Henderson             }
2122d2fd745fSRichard Henderson 
2123c896fe29Sbellard             k = 0;
2124c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
2125b7a83ff8SRichard Henderson                 const char *sep =  k ? "," : "";
2126b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s%s", sep,
2127b7a83ff8SRichard Henderson                                   tcg_get_arg_str(s, buf, sizeof(buf),
2128efee3746SRichard Henderson                                                   op->args[k++]));
2129c896fe29Sbellard             }
2130c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
2131b7a83ff8SRichard Henderson                 const char *sep =  k ? "," : "";
2132b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s%s", sep,
2133b7a83ff8SRichard Henderson                                   tcg_get_arg_str(s, buf, sizeof(buf),
2134efee3746SRichard Henderson                                                   op->args[k++]));
2135c896fe29Sbellard             }
2136be210acbSRichard Henderson             switch (c) {
2137be210acbSRichard Henderson             case INDEX_op_brcond_i32:
2138ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
2139ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
2140be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
2141be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
2142ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
2143be210acbSRichard Henderson             case INDEX_op_setcond_i64:
2144ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
2145212be173SRichard Henderson             case INDEX_op_cmp_vec:
2146f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
2147efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
2148efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
2149b7a83ff8SRichard Henderson                     col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]);
2150eeacee4dSBlue Swirl                 } else {
2151b7a83ff8SRichard Henderson                     col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]);
2152eeacee4dSBlue Swirl                 }
2153f48f3edeSblueswir1                 i = 1;
2154be210acbSRichard Henderson                 break;
2155f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
2156f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
215707ce0b05SRichard Henderson             case INDEX_op_qemu_st8_i32:
2158f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
2159f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
216059227d5dSRichard Henderson                 {
21619002ffcbSRichard Henderson                     MemOpIdx oi = op->args[k++];
216214776ab5STony Nguyen                     MemOp op = get_memop(oi);
216359227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
216459227d5dSRichard Henderson 
216559c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
2166b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",$0x%x,%u", op, ix);
216759c4b7e8SRichard Henderson                     } else {
21681f00b27fSSergey Sorokin                         const char *s_al, *s_op;
21691f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
217059c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
2171b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",%s%s,%u", s_al, s_op, ix);
2172f713d6adSRichard Henderson                     }
2173f713d6adSRichard Henderson                     i = 1;
217459227d5dSRichard Henderson                 }
2175f713d6adSRichard Henderson                 break;
2176587195bdSRichard Henderson             case INDEX_op_bswap16_i32:
2177587195bdSRichard Henderson             case INDEX_op_bswap16_i64:
2178587195bdSRichard Henderson             case INDEX_op_bswap32_i32:
2179587195bdSRichard Henderson             case INDEX_op_bswap32_i64:
2180587195bdSRichard Henderson             case INDEX_op_bswap64_i64:
2181587195bdSRichard Henderson                 {
2182587195bdSRichard Henderson                     TCGArg flags = op->args[k];
2183587195bdSRichard Henderson                     const char *name = NULL;
2184587195bdSRichard Henderson 
2185587195bdSRichard Henderson                     if (flags < ARRAY_SIZE(bswap_flag_name)) {
2186587195bdSRichard Henderson                         name = bswap_flag_name[flags];
2187587195bdSRichard Henderson                     }
2188587195bdSRichard Henderson                     if (name) {
2189b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",%s", name);
2190587195bdSRichard Henderson                     } else {
2191b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags);
2192587195bdSRichard Henderson                     }
2193587195bdSRichard Henderson                     i = k = 1;
2194587195bdSRichard Henderson                 }
2195587195bdSRichard Henderson                 break;
2196be210acbSRichard Henderson             default:
2197f48f3edeSblueswir1                 i = 0;
2198be210acbSRichard Henderson                 break;
2199be210acbSRichard Henderson             }
220051e3972cSRichard Henderson             switch (c) {
220151e3972cSRichard Henderson             case INDEX_op_set_label:
220251e3972cSRichard Henderson             case INDEX_op_br:
220351e3972cSRichard Henderson             case INDEX_op_brcond_i32:
220451e3972cSRichard Henderson             case INDEX_op_brcond_i64:
220551e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2206b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s$L%d", k ? "," : "",
2207efee3746SRichard Henderson                                   arg_label(op->args[k])->id);
220851e3972cSRichard Henderson                 i++, k++;
220951e3972cSRichard Henderson                 break;
221051e3972cSRichard Henderson             default:
221151e3972cSRichard Henderson                 break;
2212eeacee4dSBlue Swirl             }
221351e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
2214b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "",
2215b7a83ff8SRichard Henderson                                   op->args[k]);
2216bdfb460eSRichard Henderson             }
2217bdfb460eSRichard Henderson         }
2218bdfb460eSRichard Henderson 
22191894f69aSRichard Henderson         if (have_prefs || op->life) {
22201894f69aSRichard Henderson             for (; col < 40; ++col) {
2221b7a83ff8SRichard Henderson                 putc(' ', f);
2222bdfb460eSRichard Henderson             }
22231894f69aSRichard Henderson         }
22241894f69aSRichard Henderson 
22251894f69aSRichard Henderson         if (op->life) {
22261894f69aSRichard Henderson             unsigned life = op->life;
2227bdfb460eSRichard Henderson 
2228bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
2229b7a83ff8SRichard Henderson                 ne_fprintf(f, "  sync:");
2230bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
2231bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
2232b7a83ff8SRichard Henderson                         ne_fprintf(f, " %d", i);
2233bdfb460eSRichard Henderson                     }
2234bdfb460eSRichard Henderson                 }
2235bdfb460eSRichard Henderson             }
2236bdfb460eSRichard Henderson             life /= DEAD_ARG;
2237bdfb460eSRichard Henderson             if (life) {
2238b7a83ff8SRichard Henderson                 ne_fprintf(f, "  dead:");
2239bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
2240bdfb460eSRichard Henderson                     if (life & 1) {
2241b7a83ff8SRichard Henderson                         ne_fprintf(f, " %d", i);
2242bdfb460eSRichard Henderson                     }
2243bdfb460eSRichard Henderson                 }
2244c896fe29Sbellard             }
2245b03cce8eSbellard         }
22461894f69aSRichard Henderson 
22471894f69aSRichard Henderson         if (have_prefs) {
22481894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
224931fd884bSRichard Henderson                 TCGRegSet set = output_pref(op, i);
22501894f69aSRichard Henderson 
22511894f69aSRichard Henderson                 if (i == 0) {
2252b7a83ff8SRichard Henderson                     ne_fprintf(f, "  pref=");
22531894f69aSRichard Henderson                 } else {
2254b7a83ff8SRichard Henderson                     ne_fprintf(f, ",");
22551894f69aSRichard Henderson                 }
22561894f69aSRichard Henderson                 if (set == 0) {
2257b7a83ff8SRichard Henderson                     ne_fprintf(f, "none");
22581894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
2259b7a83ff8SRichard Henderson                     ne_fprintf(f, "all");
22601894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
22611894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
22621894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
2263b7a83ff8SRichard Henderson                     ne_fprintf(f, "%s", tcg_target_reg_names[reg]);
22641894f69aSRichard Henderson #endif
22651894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
2266b7a83ff8SRichard Henderson                     ne_fprintf(f, "0x%x", (uint32_t)set);
22671894f69aSRichard Henderson                 } else {
2268b7a83ff8SRichard Henderson                     ne_fprintf(f, "0x%" PRIx64, (uint64_t)set);
22691894f69aSRichard Henderson                 }
22701894f69aSRichard Henderson             }
22711894f69aSRichard Henderson         }
22721894f69aSRichard Henderson 
2273b7a83ff8SRichard Henderson         putc('\n', f);
2274c896fe29Sbellard     }
2275c896fe29Sbellard }
2276c896fe29Sbellard 
2277c896fe29Sbellard /* we give more priority to constraints with less registers */
2278c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2279c896fe29Sbellard {
228074a11790SRichard Henderson     const TCGArgConstraint *arg_ct = &def->args_ct[k];
228129f5e925SRichard Henderson     int n = ctpop64(arg_ct->regs);
2282c896fe29Sbellard 
228329f5e925SRichard Henderson     /*
228429f5e925SRichard Henderson      * Sort constraints of a single register first, which includes output
228529f5e925SRichard Henderson      * aliases (which must exactly match the input already allocated).
228629f5e925SRichard Henderson      */
228729f5e925SRichard Henderson     if (n == 1 || arg_ct->oalias) {
228829f5e925SRichard Henderson         return INT_MAX;
2289c896fe29Sbellard     }
229029f5e925SRichard Henderson 
229129f5e925SRichard Henderson     /*
229229f5e925SRichard Henderson      * Sort register pairs next, first then second immediately after.
229329f5e925SRichard Henderson      * Arbitrarily sort multiple pairs by the index of the first reg;
229429f5e925SRichard Henderson      * there shouldn't be many pairs.
229529f5e925SRichard Henderson      */
229629f5e925SRichard Henderson     switch (arg_ct->pair) {
229729f5e925SRichard Henderson     case 1:
229829f5e925SRichard Henderson     case 3:
229929f5e925SRichard Henderson         return (k + 1) * 2;
230029f5e925SRichard Henderson     case 2:
230129f5e925SRichard Henderson         return (arg_ct->pair_index + 1) * 2 - 1;
230229f5e925SRichard Henderson     }
230329f5e925SRichard Henderson 
230429f5e925SRichard Henderson     /* Finally, sort by decreasing register count. */
230529f5e925SRichard Henderson     assert(n > 1);
230629f5e925SRichard Henderson     return -n;
2307c896fe29Sbellard }
2308c896fe29Sbellard 
2309c896fe29Sbellard /* sort from highest priority to lowest */
2310c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2311c896fe29Sbellard {
231266792f90SRichard Henderson     int i, j;
231366792f90SRichard Henderson     TCGArgConstraint *a = def->args_ct;
2314c896fe29Sbellard 
231566792f90SRichard Henderson     for (i = 0; i < n; i++) {
231666792f90SRichard Henderson         a[start + i].sort_index = start + i;
231766792f90SRichard Henderson     }
231866792f90SRichard Henderson     if (n <= 1) {
2319c896fe29Sbellard         return;
232066792f90SRichard Henderson     }
2321c896fe29Sbellard     for (i = 0; i < n - 1; i++) {
2322c896fe29Sbellard         for (j = i + 1; j < n; j++) {
232366792f90SRichard Henderson             int p1 = get_constraint_priority(def, a[start + i].sort_index);
232466792f90SRichard Henderson             int p2 = get_constraint_priority(def, a[start + j].sort_index);
2325c896fe29Sbellard             if (p1 < p2) {
232666792f90SRichard Henderson                 int tmp = a[start + i].sort_index;
232766792f90SRichard Henderson                 a[start + i].sort_index = a[start + j].sort_index;
232866792f90SRichard Henderson                 a[start + j].sort_index = tmp;
2329c896fe29Sbellard             }
2330c896fe29Sbellard         }
2331c896fe29Sbellard     }
2332c896fe29Sbellard }
2333c896fe29Sbellard 
2334f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2335c896fe29Sbellard {
2336a9751609SRichard Henderson     TCGOpcode op;
2337c896fe29Sbellard 
2338f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
2339f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
2340f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
234129f5e925SRichard Henderson         bool saw_alias_pair = false;
234229f5e925SRichard Henderson         int i, o, i2, o2, nb_args;
2343f69d277eSRichard Henderson 
2344f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
2345f69d277eSRichard Henderson             continue;
2346f69d277eSRichard Henderson         }
2347f69d277eSRichard Henderson 
2348c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
2349f69d277eSRichard Henderson         if (nb_args == 0) {
2350f69d277eSRichard Henderson             continue;
2351f69d277eSRichard Henderson         }
2352f69d277eSRichard Henderson 
23534c22e840SRichard Henderson         /*
23544c22e840SRichard Henderson          * Macro magic should make it impossible, but double-check that
23554c22e840SRichard Henderson          * the array index is in range.  Since the signness of an enum
23564c22e840SRichard Henderson          * is implementation defined, force the result to unsigned.
23574c22e840SRichard Henderson          */
23584c22e840SRichard Henderson         unsigned con_set = tcg_target_op_def(op);
23594c22e840SRichard Henderson         tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets));
23604c22e840SRichard Henderson         tdefs = &constraint_sets[con_set];
2361f69d277eSRichard Henderson 
2362c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2363f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
23648940ea0dSPhilippe Mathieu-Daudé             bool input_p = i >= def->nb_oargs;
23658940ea0dSPhilippe Mathieu-Daudé 
2366f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2367eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2368f69d277eSRichard Henderson 
236917280ff4SRichard Henderson             switch (*ct_str) {
237017280ff4SRichard Henderson             case '0' ... '9':
23718940ea0dSPhilippe Mathieu-Daudé                 o = *ct_str - '0';
23728940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(input_p);
23738940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(o < def->nb_oargs);
23748940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(def->args_ct[o].regs != 0);
23758940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(!def->args_ct[o].oalias);
23768940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i] = def->args_ct[o];
2377bc2b17e6SRichard Henderson                 /* The output sets oalias.  */
23788940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[o].oalias = 1;
23798940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[o].alias_index = i;
2380bc2b17e6SRichard Henderson                 /* The input sets ialias. */
23818940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i].ialias = 1;
23828940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i].alias_index = o;
238329f5e925SRichard Henderson                 if (def->args_ct[i].pair) {
238429f5e925SRichard Henderson                     saw_alias_pair = true;
238529f5e925SRichard Henderson                 }
23868940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(ct_str[1] == '\0');
23878940ea0dSPhilippe Mathieu-Daudé                 continue;
23888940ea0dSPhilippe Mathieu-Daudé 
238982790a87SRichard Henderson             case '&':
23908940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(!input_p);
2391bc2b17e6SRichard Henderson                 def->args_ct[i].newreg = true;
239282790a87SRichard Henderson                 ct_str++;
239382790a87SRichard Henderson                 break;
239429f5e925SRichard Henderson 
239529f5e925SRichard Henderson             case 'p': /* plus */
239629f5e925SRichard Henderson                 /* Allocate to the register after the previous. */
239729f5e925SRichard Henderson                 tcg_debug_assert(i > (input_p ? def->nb_oargs : 0));
239829f5e925SRichard Henderson                 o = i - 1;
239929f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].pair);
240029f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].ct);
240129f5e925SRichard Henderson                 def->args_ct[i] = (TCGArgConstraint){
240229f5e925SRichard Henderson                     .pair = 2,
240329f5e925SRichard Henderson                     .pair_index = o,
240429f5e925SRichard Henderson                     .regs = def->args_ct[o].regs << 1,
240529f5e925SRichard Henderson                 };
240629f5e925SRichard Henderson                 def->args_ct[o].pair = 1;
240729f5e925SRichard Henderson                 def->args_ct[o].pair_index = i;
240829f5e925SRichard Henderson                 tcg_debug_assert(ct_str[1] == '\0');
240929f5e925SRichard Henderson                 continue;
241029f5e925SRichard Henderson 
241129f5e925SRichard Henderson             case 'm': /* minus */
241229f5e925SRichard Henderson                 /* Allocate to the register before the previous. */
241329f5e925SRichard Henderson                 tcg_debug_assert(i > (input_p ? def->nb_oargs : 0));
241429f5e925SRichard Henderson                 o = i - 1;
241529f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].pair);
241629f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].ct);
241729f5e925SRichard Henderson                 def->args_ct[i] = (TCGArgConstraint){
241829f5e925SRichard Henderson                     .pair = 1,
241929f5e925SRichard Henderson                     .pair_index = o,
242029f5e925SRichard Henderson                     .regs = def->args_ct[o].regs >> 1,
242129f5e925SRichard Henderson                 };
242229f5e925SRichard Henderson                 def->args_ct[o].pair = 2;
242329f5e925SRichard Henderson                 def->args_ct[o].pair_index = i;
242429f5e925SRichard Henderson                 tcg_debug_assert(ct_str[1] == '\0');
242529f5e925SRichard Henderson                 continue;
24268940ea0dSPhilippe Mathieu-Daudé             }
24278940ea0dSPhilippe Mathieu-Daudé 
24288940ea0dSPhilippe Mathieu-Daudé             do {
24298940ea0dSPhilippe Mathieu-Daudé                 switch (*ct_str) {
2430c896fe29Sbellard                 case 'i':
2431c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2432c896fe29Sbellard                     break;
2433358b4923SRichard Henderson 
2434358b4923SRichard Henderson                 /* Include all of the target-specific constraints. */
2435358b4923SRichard Henderson 
2436358b4923SRichard Henderson #undef CONST
2437358b4923SRichard Henderson #define CONST(CASE, MASK) \
24388940ea0dSPhilippe Mathieu-Daudé     case CASE: def->args_ct[i].ct |= MASK; break;
2439358b4923SRichard Henderson #define REGS(CASE, MASK) \
24408940ea0dSPhilippe Mathieu-Daudé     case CASE: def->args_ct[i].regs |= MASK; break;
2441358b4923SRichard Henderson 
2442358b4923SRichard Henderson #include "tcg-target-con-str.h"
2443358b4923SRichard Henderson 
2444358b4923SRichard Henderson #undef REGS
2445358b4923SRichard Henderson #undef CONST
2446c896fe29Sbellard                 default:
24478940ea0dSPhilippe Mathieu-Daudé                 case '0' ... '9':
24488940ea0dSPhilippe Mathieu-Daudé                 case '&':
244929f5e925SRichard Henderson                 case 'p':
245029f5e925SRichard Henderson                 case 'm':
2451358b4923SRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2452358b4923SRichard Henderson                     g_assert_not_reached();
2453358b4923SRichard Henderson                 }
24548940ea0dSPhilippe Mathieu-Daudé             } while (*++ct_str != '\0');
2455c896fe29Sbellard         }
2456c896fe29Sbellard 
2457c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2458eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2459c68aaa18SStefan Weil 
246029f5e925SRichard Henderson         /*
246129f5e925SRichard Henderson          * Fix up output pairs that are aliased with inputs.
246229f5e925SRichard Henderson          * When we created the alias, we copied pair from the output.
246329f5e925SRichard Henderson          * There are three cases:
246429f5e925SRichard Henderson          *    (1a) Pairs of inputs alias pairs of outputs.
246529f5e925SRichard Henderson          *    (1b) One input aliases the first of a pair of outputs.
246629f5e925SRichard Henderson          *    (2)  One input aliases the second of a pair of outputs.
246729f5e925SRichard Henderson          *
246829f5e925SRichard Henderson          * Case 1a is handled by making sure that the pair_index'es are
246929f5e925SRichard Henderson          * properly updated so that they appear the same as a pair of inputs.
247029f5e925SRichard Henderson          *
247129f5e925SRichard Henderson          * Case 1b is handled by setting the pair_index of the input to
247229f5e925SRichard Henderson          * itself, simply so it doesn't point to an unrelated argument.
247329f5e925SRichard Henderson          * Since we don't encounter the "second" during the input allocation
247429f5e925SRichard Henderson          * phase, nothing happens with the second half of the input pair.
247529f5e925SRichard Henderson          *
247629f5e925SRichard Henderson          * Case 2 is handled by setting the second input to pair=3, the
247729f5e925SRichard Henderson          * first output to pair=3, and the pair_index'es to match.
247829f5e925SRichard Henderson          */
247929f5e925SRichard Henderson         if (saw_alias_pair) {
248029f5e925SRichard Henderson             for (i = def->nb_oargs; i < nb_args; i++) {
248129f5e925SRichard Henderson                 /*
248229f5e925SRichard Henderson                  * Since [0-9pm] must be alone in the constraint string,
248329f5e925SRichard Henderson                  * the only way they can both be set is if the pair comes
248429f5e925SRichard Henderson                  * from the output alias.
248529f5e925SRichard Henderson                  */
248629f5e925SRichard Henderson                 if (!def->args_ct[i].ialias) {
248729f5e925SRichard Henderson                     continue;
248829f5e925SRichard Henderson                 }
248929f5e925SRichard Henderson                 switch (def->args_ct[i].pair) {
249029f5e925SRichard Henderson                 case 0:
249129f5e925SRichard Henderson                     break;
249229f5e925SRichard Henderson                 case 1:
249329f5e925SRichard Henderson                     o = def->args_ct[i].alias_index;
249429f5e925SRichard Henderson                     o2 = def->args_ct[o].pair_index;
249529f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o].pair == 1);
249629f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o2].pair == 2);
249729f5e925SRichard Henderson                     if (def->args_ct[o2].oalias) {
249829f5e925SRichard Henderson                         /* Case 1a */
249929f5e925SRichard Henderson                         i2 = def->args_ct[o2].alias_index;
250029f5e925SRichard Henderson                         tcg_debug_assert(def->args_ct[i2].pair == 2);
250129f5e925SRichard Henderson                         def->args_ct[i2].pair_index = i;
250229f5e925SRichard Henderson                         def->args_ct[i].pair_index = i2;
250329f5e925SRichard Henderson                     } else {
250429f5e925SRichard Henderson                         /* Case 1b */
250529f5e925SRichard Henderson                         def->args_ct[i].pair_index = i;
250629f5e925SRichard Henderson                     }
250729f5e925SRichard Henderson                     break;
250829f5e925SRichard Henderson                 case 2:
250929f5e925SRichard Henderson                     o = def->args_ct[i].alias_index;
251029f5e925SRichard Henderson                     o2 = def->args_ct[o].pair_index;
251129f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o].pair == 2);
251229f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o2].pair == 1);
251329f5e925SRichard Henderson                     if (def->args_ct[o2].oalias) {
251429f5e925SRichard Henderson                         /* Case 1a */
251529f5e925SRichard Henderson                         i2 = def->args_ct[o2].alias_index;
251629f5e925SRichard Henderson                         tcg_debug_assert(def->args_ct[i2].pair == 1);
251729f5e925SRichard Henderson                         def->args_ct[i2].pair_index = i;
251829f5e925SRichard Henderson                         def->args_ct[i].pair_index = i2;
251929f5e925SRichard Henderson                     } else {
252029f5e925SRichard Henderson                         /* Case 2 */
252129f5e925SRichard Henderson                         def->args_ct[i].pair = 3;
252229f5e925SRichard Henderson                         def->args_ct[o2].pair = 3;
252329f5e925SRichard Henderson                         def->args_ct[i].pair_index = o2;
252429f5e925SRichard Henderson                         def->args_ct[o2].pair_index = i;
252529f5e925SRichard Henderson                     }
252629f5e925SRichard Henderson                     break;
252729f5e925SRichard Henderson                 default:
252829f5e925SRichard Henderson                     g_assert_not_reached();
252929f5e925SRichard Henderson                 }
253029f5e925SRichard Henderson             }
253129f5e925SRichard Henderson         }
253229f5e925SRichard Henderson 
2533c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
2534c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
2535c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
2536c896fe29Sbellard     }
2537c896fe29Sbellard }
2538c896fe29Sbellard 
25390c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
25400c627cdcSRichard Henderson {
2541d88a117eSRichard Henderson     TCGLabel *label;
2542d88a117eSRichard Henderson 
2543d88a117eSRichard Henderson     switch (op->opc) {
2544d88a117eSRichard Henderson     case INDEX_op_br:
2545d88a117eSRichard Henderson         label = arg_label(op->args[0]);
2546d88a117eSRichard Henderson         label->refs--;
2547d88a117eSRichard Henderson         break;
2548d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
2549d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
2550d88a117eSRichard Henderson         label = arg_label(op->args[3]);
2551d88a117eSRichard Henderson         label->refs--;
2552d88a117eSRichard Henderson         break;
2553d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
2554d88a117eSRichard Henderson         label = arg_label(op->args[5]);
2555d88a117eSRichard Henderson         label->refs--;
2556d88a117eSRichard Henderson         break;
2557d88a117eSRichard Henderson     default:
2558d88a117eSRichard Henderson         break;
2559d88a117eSRichard Henderson     }
2560d88a117eSRichard Henderson 
256115fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
256215fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
2563abebf925SRichard Henderson     s->nb_ops--;
25640c627cdcSRichard Henderson 
25650c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
2566d73415a3SStefan Hajnoczi     qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
25670c627cdcSRichard Henderson #endif
25680c627cdcSRichard Henderson }
25690c627cdcSRichard Henderson 
2570a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op)
2571a80cdd31SRichard Henderson {
2572a80cdd31SRichard Henderson     TCGContext *s = tcg_ctx;
2573a80cdd31SRichard Henderson 
2574a80cdd31SRichard Henderson     while (true) {
2575a80cdd31SRichard Henderson         TCGOp *last = tcg_last_op();
2576a80cdd31SRichard Henderson         if (last == op) {
2577a80cdd31SRichard Henderson             return;
2578a80cdd31SRichard Henderson         }
2579a80cdd31SRichard Henderson         tcg_op_remove(s, last);
2580a80cdd31SRichard Henderson     }
2581a80cdd31SRichard Henderson }
2582a80cdd31SRichard Henderson 
2583d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs)
258415fa08f8SRichard Henderson {
258515fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
2586cb10bc63SRichard Henderson     TCGOp *op = NULL;
258715fa08f8SRichard Henderson 
2588cb10bc63SRichard Henderson     if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) {
2589cb10bc63SRichard Henderson         QTAILQ_FOREACH(op, &s->free_ops, link) {
2590cb10bc63SRichard Henderson             if (nargs <= op->nargs) {
259115fa08f8SRichard Henderson                 QTAILQ_REMOVE(&s->free_ops, op, link);
2592cb10bc63SRichard Henderson                 nargs = op->nargs;
2593cb10bc63SRichard Henderson                 goto found;
259415fa08f8SRichard Henderson             }
2595cb10bc63SRichard Henderson         }
2596cb10bc63SRichard Henderson     }
2597cb10bc63SRichard Henderson 
2598cb10bc63SRichard Henderson     /* Most opcodes have 3 or 4 operands: reduce fragmentation. */
2599cb10bc63SRichard Henderson     nargs = MAX(4, nargs);
2600cb10bc63SRichard Henderson     op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs);
2601cb10bc63SRichard Henderson 
2602cb10bc63SRichard Henderson  found:
260315fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
260415fa08f8SRichard Henderson     op->opc = opc;
2605cb10bc63SRichard Henderson     op->nargs = nargs;
260615fa08f8SRichard Henderson 
2607cb10bc63SRichard Henderson     /* Check for bitfield overflow. */
2608cb10bc63SRichard Henderson     tcg_debug_assert(op->nargs == nargs);
2609cb10bc63SRichard Henderson 
2610cb10bc63SRichard Henderson     s->nb_ops++;
261115fa08f8SRichard Henderson     return op;
261215fa08f8SRichard Henderson }
261315fa08f8SRichard Henderson 
2614d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs)
261515fa08f8SRichard Henderson {
2616d4478943SPhilippe Mathieu-Daudé     TCGOp *op = tcg_op_alloc(opc, nargs);
261715fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
261815fa08f8SRichard Henderson     return op;
261915fa08f8SRichard Henderson }
262015fa08f8SRichard Henderson 
2621d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op,
2622d4478943SPhilippe Mathieu-Daudé                             TCGOpcode opc, unsigned nargs)
26235a18407fSRichard Henderson {
2624d4478943SPhilippe Mathieu-Daudé     TCGOp *new_op = tcg_op_alloc(opc, nargs);
262515fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
26265a18407fSRichard Henderson     return new_op;
26275a18407fSRichard Henderson }
26285a18407fSRichard Henderson 
2629d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op,
2630d4478943SPhilippe Mathieu-Daudé                            TCGOpcode opc, unsigned nargs)
26315a18407fSRichard Henderson {
2632d4478943SPhilippe Mathieu-Daudé     TCGOp *new_op = tcg_op_alloc(opc, nargs);
263315fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
26345a18407fSRichard Henderson     return new_op;
26355a18407fSRichard Henderson }
26365a18407fSRichard Henderson 
2637b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
26389bbee4c0SRichard Henderson static void __attribute__((noinline))
26399bbee4c0SRichard Henderson reachable_code_pass(TCGContext *s)
2640b4fc67c7SRichard Henderson {
26414d89d0bbSRichard Henderson     TCGOp *op, *op_next, *op_prev;
2642b4fc67c7SRichard Henderson     bool dead = false;
2643b4fc67c7SRichard Henderson 
2644b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
2645b4fc67c7SRichard Henderson         bool remove = dead;
2646b4fc67c7SRichard Henderson         TCGLabel *label;
2647b4fc67c7SRichard Henderson 
2648b4fc67c7SRichard Henderson         switch (op->opc) {
2649b4fc67c7SRichard Henderson         case INDEX_op_set_label:
2650b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
26514d89d0bbSRichard Henderson 
26524d89d0bbSRichard Henderson             /*
26534d89d0bbSRichard Henderson              * Optimization can fold conditional branches to unconditional.
26544d89d0bbSRichard Henderson              * If we find a label which is preceded by an unconditional
26554d89d0bbSRichard Henderson              * branch to next, remove the branch.  We couldn't do this when
26564d89d0bbSRichard Henderson              * processing the branch because any dead code between the branch
26574d89d0bbSRichard Henderson              * and label had not yet been removed.
26584d89d0bbSRichard Henderson              */
26594d89d0bbSRichard Henderson             op_prev = QTAILQ_PREV(op, link);
26604d89d0bbSRichard Henderson             if (op_prev->opc == INDEX_op_br &&
26614d89d0bbSRichard Henderson                 label == arg_label(op_prev->args[0])) {
26624d89d0bbSRichard Henderson                 tcg_op_remove(s, op_prev);
26634d89d0bbSRichard Henderson                 /* Fall through means insns become live again.  */
26644d89d0bbSRichard Henderson                 dead = false;
26654d89d0bbSRichard Henderson             }
26664d89d0bbSRichard Henderson 
2667b4fc67c7SRichard Henderson             if (label->refs == 0) {
2668b4fc67c7SRichard Henderson                 /*
2669b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
2670b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
2671b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
2672b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
2673b4fc67c7SRichard Henderson                  * little to be gained by iterating.
2674b4fc67c7SRichard Henderson                  */
2675b4fc67c7SRichard Henderson                 remove = true;
2676b4fc67c7SRichard Henderson             } else {
2677b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
2678b4fc67c7SRichard Henderson                 dead = false;
2679b4fc67c7SRichard Henderson                 remove = false;
2680b4fc67c7SRichard Henderson             }
2681b4fc67c7SRichard Henderson             break;
2682b4fc67c7SRichard Henderson 
2683b4fc67c7SRichard Henderson         case INDEX_op_br:
2684b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
2685b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
2686b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
2687b4fc67c7SRichard Henderson             dead = true;
2688b4fc67c7SRichard Henderson             break;
2689b4fc67c7SRichard Henderson 
2690b4fc67c7SRichard Henderson         case INDEX_op_call:
2691b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
269290163900SRichard Henderson             if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) {
2693b4fc67c7SRichard Henderson                 dead = true;
2694b4fc67c7SRichard Henderson             }
2695b4fc67c7SRichard Henderson             break;
2696b4fc67c7SRichard Henderson 
2697b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
2698b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
2699b4fc67c7SRichard Henderson             remove = false;
2700b4fc67c7SRichard Henderson             break;
2701b4fc67c7SRichard Henderson 
2702b4fc67c7SRichard Henderson         default:
2703b4fc67c7SRichard Henderson             break;
2704b4fc67c7SRichard Henderson         }
2705b4fc67c7SRichard Henderson 
2706b4fc67c7SRichard Henderson         if (remove) {
2707b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
2708b4fc67c7SRichard Henderson         }
2709b4fc67c7SRichard Henderson     }
2710b4fc67c7SRichard Henderson }
2711b4fc67c7SRichard Henderson 
2712c70fbf0aSRichard Henderson #define TS_DEAD  1
2713c70fbf0aSRichard Henderson #define TS_MEM   2
2714c70fbf0aSRichard Henderson 
27155a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
27165a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
27175a18407fSRichard Henderson 
271825f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
271925f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
272025f49c5fSRichard Henderson {
272125f49c5fSRichard Henderson     return ts->state_ptr;
272225f49c5fSRichard Henderson }
272325f49c5fSRichard Henderson 
272425f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
272525f49c5fSRichard Henderson  * maximal regset for its type.
272625f49c5fSRichard Henderson  */
272725f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
272825f49c5fSRichard Henderson {
272925f49c5fSRichard Henderson     *la_temp_pref(ts)
273025f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
273125f49c5fSRichard Henderson }
273225f49c5fSRichard Henderson 
27339c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
27349c43b68dSAurelien Jarno    should be in memory. */
27352616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
2736c896fe29Sbellard {
2737b83eabeaSRichard Henderson     int i;
2738b83eabeaSRichard Henderson 
2739b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2740b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
274125f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2742b83eabeaSRichard Henderson     }
2743b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2744b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
274525f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2746b83eabeaSRichard Henderson     }
2747c896fe29Sbellard }
2748c896fe29Sbellard 
27499c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
27509c43b68dSAurelien Jarno    and local temps should be in memory. */
27512616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
2752641d5fbeSbellard {
2753b83eabeaSRichard Henderson     int i;
2754641d5fbeSbellard 
2755ee17db83SRichard Henderson     for (i = 0; i < nt; ++i) {
2756ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2757ee17db83SRichard Henderson         int state;
2758ee17db83SRichard Henderson 
2759ee17db83SRichard Henderson         switch (ts->kind) {
2760ee17db83SRichard Henderson         case TEMP_FIXED:
2761ee17db83SRichard Henderson         case TEMP_GLOBAL:
2762f57c6915SRichard Henderson         case TEMP_TB:
2763ee17db83SRichard Henderson             state = TS_DEAD | TS_MEM;
2764ee17db83SRichard Henderson             break;
2765ee17db83SRichard Henderson         case TEMP_NORMAL:
2766c7482438SRichard Henderson         case TEMP_EBB:
2767c0522136SRichard Henderson         case TEMP_CONST:
2768ee17db83SRichard Henderson             state = TS_DEAD;
2769ee17db83SRichard Henderson             break;
2770ee17db83SRichard Henderson         default:
2771ee17db83SRichard Henderson             g_assert_not_reached();
2772c70fbf0aSRichard Henderson         }
2773ee17db83SRichard Henderson         ts->state = state;
2774ee17db83SRichard Henderson         la_reset_pref(ts);
2775641d5fbeSbellard     }
2776641d5fbeSbellard }
2777641d5fbeSbellard 
2778f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
2779f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
2780f65a061cSRichard Henderson {
2781f65a061cSRichard Henderson     int i;
2782f65a061cSRichard Henderson 
2783f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
278425f49c5fSRichard Henderson         int state = s->temps[i].state;
278525f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
278625f49c5fSRichard Henderson         if (state == TS_DEAD) {
278725f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
278825f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
278925f49c5fSRichard Henderson         }
2790f65a061cSRichard Henderson     }
2791f65a061cSRichard Henderson }
2792f65a061cSRichard Henderson 
2793b4cb76e6SRichard Henderson /*
2794c7482438SRichard Henderson  * liveness analysis: conditional branch: all temps are dead unless
2795c7482438SRichard Henderson  * explicitly live-across-conditional-branch, globals and local temps
2796c7482438SRichard Henderson  * should be synced.
2797b4cb76e6SRichard Henderson  */
2798b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
2799b4cb76e6SRichard Henderson {
2800b4cb76e6SRichard Henderson     la_global_sync(s, ng);
2801b4cb76e6SRichard Henderson 
2802b4cb76e6SRichard Henderson     for (int i = ng; i < nt; ++i) {
2803c0522136SRichard Henderson         TCGTemp *ts = &s->temps[i];
2804c0522136SRichard Henderson         int state;
2805c0522136SRichard Henderson 
2806c0522136SRichard Henderson         switch (ts->kind) {
2807f57c6915SRichard Henderson         case TEMP_TB:
2808c0522136SRichard Henderson             state = ts->state;
2809c0522136SRichard Henderson             ts->state = state | TS_MEM;
2810b4cb76e6SRichard Henderson             if (state != TS_DEAD) {
2811b4cb76e6SRichard Henderson                 continue;
2812b4cb76e6SRichard Henderson             }
2813c0522136SRichard Henderson             break;
2814c0522136SRichard Henderson         case TEMP_NORMAL:
2815b4cb76e6SRichard Henderson             s->temps[i].state = TS_DEAD;
2816c0522136SRichard Henderson             break;
2817c7482438SRichard Henderson         case TEMP_EBB:
2818c0522136SRichard Henderson         case TEMP_CONST:
2819c0522136SRichard Henderson             continue;
2820c0522136SRichard Henderson         default:
2821c0522136SRichard Henderson             g_assert_not_reached();
2822b4cb76e6SRichard Henderson         }
2823b4cb76e6SRichard Henderson         la_reset_pref(&s->temps[i]);
2824b4cb76e6SRichard Henderson     }
2825b4cb76e6SRichard Henderson }
2826b4cb76e6SRichard Henderson 
2827f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
2828f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
2829f65a061cSRichard Henderson {
2830f65a061cSRichard Henderson     int i;
2831f65a061cSRichard Henderson 
2832f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
2833f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
283425f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
283525f49c5fSRichard Henderson     }
283625f49c5fSRichard Henderson }
283725f49c5fSRichard Henderson 
283825f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
283925f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
284025f49c5fSRichard Henderson {
284125f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
284225f49c5fSRichard Henderson     int i;
284325f49c5fSRichard Henderson 
284425f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
284525f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
284625f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
284725f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
284825f49c5fSRichard Henderson             TCGRegSet set = *pset;
284925f49c5fSRichard Henderson 
285025f49c5fSRichard Henderson             set &= mask;
285125f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
285225f49c5fSRichard Henderson             if (set == 0) {
285325f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
285425f49c5fSRichard Henderson             }
285525f49c5fSRichard Henderson             *pset = set;
285625f49c5fSRichard Henderson         }
2857f65a061cSRichard Henderson     }
2858f65a061cSRichard Henderson }
2859f65a061cSRichard Henderson 
2860*874b8574SRichard Henderson /*
2861*874b8574SRichard Henderson  * Liveness analysis: Verify the lifetime of TEMP_TB, and reduce
2862*874b8574SRichard Henderson  * to TEMP_EBB, if possible.
2863*874b8574SRichard Henderson  */
2864*874b8574SRichard Henderson static void __attribute__((noinline))
2865*874b8574SRichard Henderson liveness_pass_0(TCGContext *s)
2866*874b8574SRichard Henderson {
2867*874b8574SRichard Henderson     void * const multiple_ebb = (void *)(uintptr_t)-1;
2868*874b8574SRichard Henderson     int nb_temps = s->nb_temps;
2869*874b8574SRichard Henderson     TCGOp *op, *ebb;
2870*874b8574SRichard Henderson 
2871*874b8574SRichard Henderson     for (int i = s->nb_globals; i < nb_temps; ++i) {
2872*874b8574SRichard Henderson         s->temps[i].state_ptr = NULL;
2873*874b8574SRichard Henderson     }
2874*874b8574SRichard Henderson 
2875*874b8574SRichard Henderson     /*
2876*874b8574SRichard Henderson      * Represent each EBB by the op at which it begins.  In the case of
2877*874b8574SRichard Henderson      * the first EBB, this is the first op, otherwise it is a label.
2878*874b8574SRichard Henderson      * Collect the uses of each TEMP_TB: NULL for unused, EBB for use
2879*874b8574SRichard Henderson      * within a single EBB, else MULTIPLE_EBB.
2880*874b8574SRichard Henderson      */
2881*874b8574SRichard Henderson     ebb = QTAILQ_FIRST(&s->ops);
2882*874b8574SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
2883*874b8574SRichard Henderson         const TCGOpDef *def;
2884*874b8574SRichard Henderson         int nb_oargs, nb_iargs;
2885*874b8574SRichard Henderson 
2886*874b8574SRichard Henderson         switch (op->opc) {
2887*874b8574SRichard Henderson         case INDEX_op_set_label:
2888*874b8574SRichard Henderson             ebb = op;
2889*874b8574SRichard Henderson             continue;
2890*874b8574SRichard Henderson         case INDEX_op_discard:
2891*874b8574SRichard Henderson             continue;
2892*874b8574SRichard Henderson         case INDEX_op_call:
2893*874b8574SRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2894*874b8574SRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2895*874b8574SRichard Henderson             break;
2896*874b8574SRichard Henderson         default:
2897*874b8574SRichard Henderson             def = &tcg_op_defs[op->opc];
2898*874b8574SRichard Henderson             nb_oargs = def->nb_oargs;
2899*874b8574SRichard Henderson             nb_iargs = def->nb_iargs;
2900*874b8574SRichard Henderson             break;
2901*874b8574SRichard Henderson         }
2902*874b8574SRichard Henderson 
2903*874b8574SRichard Henderson         for (int i = 0; i < nb_oargs + nb_iargs; ++i) {
2904*874b8574SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
2905*874b8574SRichard Henderson 
2906*874b8574SRichard Henderson             if (ts->kind != TEMP_TB) {
2907*874b8574SRichard Henderson                 continue;
2908*874b8574SRichard Henderson             }
2909*874b8574SRichard Henderson             if (ts->state_ptr == NULL) {
2910*874b8574SRichard Henderson                 ts->state_ptr = ebb;
2911*874b8574SRichard Henderson             } else if (ts->state_ptr != ebb) {
2912*874b8574SRichard Henderson                 ts->state_ptr = multiple_ebb;
2913*874b8574SRichard Henderson             }
2914*874b8574SRichard Henderson         }
2915*874b8574SRichard Henderson     }
2916*874b8574SRichard Henderson 
2917*874b8574SRichard Henderson     /*
2918*874b8574SRichard Henderson      * For TEMP_TB that turned out not to be used beyond one EBB,
2919*874b8574SRichard Henderson      * reduce the liveness to TEMP_EBB.
2920*874b8574SRichard Henderson      */
2921*874b8574SRichard Henderson     for (int i = s->nb_globals; i < nb_temps; ++i) {
2922*874b8574SRichard Henderson         TCGTemp *ts = &s->temps[i];
2923*874b8574SRichard Henderson         if (ts->kind == TEMP_TB && ts->state_ptr != multiple_ebb) {
2924*874b8574SRichard Henderson             ts->kind = TEMP_EBB;
2925*874b8574SRichard Henderson         }
2926*874b8574SRichard Henderson     }
2927*874b8574SRichard Henderson }
2928*874b8574SRichard Henderson 
2929a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
2930c896fe29Sbellard    given input arguments is dead. Instructions updating dead
2931c896fe29Sbellard    temporaries are removed. */
29329bbee4c0SRichard Henderson static void __attribute__((noinline))
29339bbee4c0SRichard Henderson liveness_pass_1(TCGContext *s)
2934c896fe29Sbellard {
2935c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
29362616c808SRichard Henderson     int nb_temps = s->nb_temps;
293715fa08f8SRichard Henderson     TCGOp *op, *op_prev;
293825f49c5fSRichard Henderson     TCGRegSet *prefs;
293925f49c5fSRichard Henderson     int i;
294025f49c5fSRichard Henderson 
294125f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
294225f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
294325f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
294425f49c5fSRichard Henderson     }
2945c896fe29Sbellard 
2946ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
29472616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
2948c896fe29Sbellard 
2949eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
295025f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
2951c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
2952c45cb8bbSRichard Henderson         bool have_opc_new2;
2953a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
295425f49c5fSRichard Henderson         TCGTemp *ts;
2955c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2956c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2957c45cb8bbSRichard Henderson 
2958c45cb8bbSRichard Henderson         switch (opc) {
2959c896fe29Sbellard         case INDEX_op_call:
2960c6e113f5Sbellard             {
296139004a71SRichard Henderson                 const TCGHelperInfo *info = tcg_call_info(op);
296239004a71SRichard Henderson                 int call_flags = tcg_call_flags(op);
2963c6e113f5Sbellard 
2964cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
2965cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
2966c6e113f5Sbellard 
2967c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
296878505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
2969c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
297025f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
297125f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
2972c6e113f5Sbellard                             goto do_not_remove_call;
2973c6e113f5Sbellard                         }
29749c43b68dSAurelien Jarno                     }
2975c45cb8bbSRichard Henderson                     goto do_remove;
2976152c35aaSRichard Henderson                 }
2977c6e113f5Sbellard             do_not_remove_call:
2978c896fe29Sbellard 
297925f49c5fSRichard Henderson                 /* Output args are dead.  */
2980c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
298125f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
298225f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
2983a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
29846b64b624SAurelien Jarno                     }
298525f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
2986a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
29879c43b68dSAurelien Jarno                     }
298825f49c5fSRichard Henderson                     ts->state = TS_DEAD;
298925f49c5fSRichard Henderson                     la_reset_pref(ts);
2990c896fe29Sbellard                 }
2991c896fe29Sbellard 
299231fd884bSRichard Henderson                 /* Not used -- it will be tcg_target_call_oarg_reg().  */
299331fd884bSRichard Henderson                 memset(op->output_pref, 0, sizeof(op->output_pref));
299431fd884bSRichard Henderson 
299578505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
299678505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
2997f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
2998c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
2999f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
3000b9c18f56Saurel32                 }
3001c896fe29Sbellard 
300225f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
3003866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
300425f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
300539004a71SRichard Henderson                     if (ts->state & TS_DEAD) {
3006a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
3007c896fe29Sbellard                     }
3008c896fe29Sbellard                 }
300925f49c5fSRichard Henderson 
301025f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
301125f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
301225f49c5fSRichard Henderson 
301339004a71SRichard Henderson                 /*
301439004a71SRichard Henderson                  * Input arguments are live for preceding opcodes.
301539004a71SRichard Henderson                  *
301639004a71SRichard Henderson                  * For those arguments that die, and will be allocated in
301739004a71SRichard Henderson                  * registers, clear the register set for that arg, to be
301839004a71SRichard Henderson                  * filled in below.  For args that will be on the stack,
301939004a71SRichard Henderson                  * reset to any available reg.  Process arguments in reverse
302039004a71SRichard Henderson                  * order so that if a temp is used more than once, the stack
302139004a71SRichard Henderson                  * reset to max happens before the register reset to 0.
302225f49c5fSRichard Henderson                  */
302339004a71SRichard Henderson                 for (i = nb_iargs - 1; i >= 0; i--) {
302439004a71SRichard Henderson                     const TCGCallArgumentLoc *loc = &info->in[i];
302539004a71SRichard Henderson                     ts = arg_temp(op->args[nb_oargs + i]);
302639004a71SRichard Henderson 
302739004a71SRichard Henderson                     if (ts->state & TS_DEAD) {
302839004a71SRichard Henderson                         switch (loc->kind) {
302939004a71SRichard Henderson                         case TCG_CALL_ARG_NORMAL:
303039004a71SRichard Henderson                         case TCG_CALL_ARG_EXTEND_U:
303139004a71SRichard Henderson                         case TCG_CALL_ARG_EXTEND_S:
303239004a71SRichard Henderson                             if (REG_P(loc)) {
303339004a71SRichard Henderson                                 *la_temp_pref(ts) = 0;
303439004a71SRichard Henderson                                 break;
303539004a71SRichard Henderson                             }
303639004a71SRichard Henderson                             /* fall through */
303739004a71SRichard Henderson                         default:
303839004a71SRichard Henderson                             *la_temp_pref(ts) =
303939004a71SRichard Henderson                                 tcg_target_available_regs[ts->type];
304039004a71SRichard Henderson                             break;
304139004a71SRichard Henderson                         }
304225f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
304325f49c5fSRichard Henderson                     }
304425f49c5fSRichard Henderson                 }
304525f49c5fSRichard Henderson 
304639004a71SRichard Henderson                 /*
304739004a71SRichard Henderson                  * For each input argument, add its input register to prefs.
304839004a71SRichard Henderson                  * If a temp is used once, this produces a single set bit;
304939004a71SRichard Henderson                  * if a temp is used multiple times, this produces a set.
305039004a71SRichard Henderson                  */
305139004a71SRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
305239004a71SRichard Henderson                     const TCGCallArgumentLoc *loc = &info->in[i];
305339004a71SRichard Henderson                     ts = arg_temp(op->args[nb_oargs + i]);
305439004a71SRichard Henderson 
305539004a71SRichard Henderson                     switch (loc->kind) {
305639004a71SRichard Henderson                     case TCG_CALL_ARG_NORMAL:
305739004a71SRichard Henderson                     case TCG_CALL_ARG_EXTEND_U:
305839004a71SRichard Henderson                     case TCG_CALL_ARG_EXTEND_S:
305939004a71SRichard Henderson                         if (REG_P(loc)) {
306025f49c5fSRichard Henderson                             tcg_regset_set_reg(*la_temp_pref(ts),
306139004a71SRichard Henderson                                 tcg_target_call_iarg_regs[loc->arg_slot]);
306239004a71SRichard Henderson                         }
306339004a71SRichard Henderson                         break;
306439004a71SRichard Henderson                     default:
306539004a71SRichard Henderson                         break;
3066c70fbf0aSRichard Henderson                     }
3067c19f47bfSAurelien Jarno                 }
3068c6e113f5Sbellard             }
3069c896fe29Sbellard             break;
3070765b842aSRichard Henderson         case INDEX_op_insn_start:
3071c896fe29Sbellard             break;
30725ff9d6a4Sbellard         case INDEX_op_discard:
30735ff9d6a4Sbellard             /* mark the temporary as dead */
307425f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
307525f49c5fSRichard Henderson             ts->state = TS_DEAD;
307625f49c5fSRichard Henderson             la_reset_pref(ts);
30775ff9d6a4Sbellard             break;
30781305c451SRichard Henderson 
30791305c451SRichard Henderson         case INDEX_op_add2_i32:
3080c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
3081f1fae40cSRichard Henderson             goto do_addsub2;
30821305c451SRichard Henderson         case INDEX_op_sub2_i32:
3083c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
3084f1fae40cSRichard Henderson             goto do_addsub2;
3085f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
3086c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
3087f1fae40cSRichard Henderson             goto do_addsub2;
3088f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
3089c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
3090f1fae40cSRichard Henderson         do_addsub2:
30911305c451SRichard Henderson             nb_iargs = 4;
30921305c451SRichard Henderson             nb_oargs = 2;
30931305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
30941305c451SRichard Henderson                the low part.  The result can be optimized to a simple
30951305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
30961305c451SRichard Henderson                cpu mode is set to 32 bit.  */
3097b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
3098b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
30991305c451SRichard Henderson                     goto do_remove;
31001305c451SRichard Henderson                 }
3101c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
3102c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
3103c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
3104efee3746SRichard Henderson                 op->args[1] = op->args[2];
3105efee3746SRichard Henderson                 op->args[2] = op->args[4];
31061305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
31071305c451SRichard Henderson                 nb_iargs = 2;
31081305c451SRichard Henderson                 nb_oargs = 1;
31091305c451SRichard Henderson             }
31101305c451SRichard Henderson             goto do_not_remove;
31111305c451SRichard Henderson 
31121414968aSRichard Henderson         case INDEX_op_mulu2_i32:
3113c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
3114c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
3115c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
311603271524SRichard Henderson             goto do_mul2;
3117f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
3118c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
3119c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
3120c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
3121f1fae40cSRichard Henderson             goto do_mul2;
3122f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
3123c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
3124c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
3125c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
312603271524SRichard Henderson             goto do_mul2;
3127f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
3128c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
3129c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
3130c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
313103271524SRichard Henderson             goto do_mul2;
3132f1fae40cSRichard Henderson         do_mul2:
31331414968aSRichard Henderson             nb_iargs = 2;
31341414968aSRichard Henderson             nb_oargs = 2;
3135b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
3136b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
313703271524SRichard Henderson                     /* Both parts of the operation are dead.  */
31381414968aSRichard Henderson                     goto do_remove;
31391414968aSRichard Henderson                 }
314003271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
3141c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
3142efee3746SRichard Henderson                 op->args[1] = op->args[2];
3143efee3746SRichard Henderson                 op->args[2] = op->args[3];
3144b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
314503271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
3146c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
3147efee3746SRichard Henderson                 op->args[0] = op->args[1];
3148efee3746SRichard Henderson                 op->args[1] = op->args[2];
3149efee3746SRichard Henderson                 op->args[2] = op->args[3];
315003271524SRichard Henderson             } else {
315103271524SRichard Henderson                 goto do_not_remove;
315203271524SRichard Henderson             }
315303271524SRichard Henderson             /* Mark the single-word operation live.  */
31541414968aSRichard Henderson             nb_oargs = 1;
31551414968aSRichard Henderson             goto do_not_remove;
31561414968aSRichard Henderson 
3157c896fe29Sbellard         default:
31581305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
3159c896fe29Sbellard             nb_iargs = def->nb_iargs;
3160c896fe29Sbellard             nb_oargs = def->nb_oargs;
3161c896fe29Sbellard 
3162c896fe29Sbellard             /* Test if the operation can be removed because all
31635ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
31645ff9d6a4Sbellard                implies side effects */
31655ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
3166c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
3167b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
3168c896fe29Sbellard                         goto do_not_remove;
3169c896fe29Sbellard                     }
31709c43b68dSAurelien Jarno                 }
3171152c35aaSRichard Henderson                 goto do_remove;
3172152c35aaSRichard Henderson             }
3173152c35aaSRichard Henderson             goto do_not_remove;
3174152c35aaSRichard Henderson 
31751305c451SRichard Henderson         do_remove:
31760c627cdcSRichard Henderson             tcg_op_remove(s, op);
3177152c35aaSRichard Henderson             break;
3178152c35aaSRichard Henderson 
3179c896fe29Sbellard         do_not_remove:
3180c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
318125f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
318225f49c5fSRichard Henderson 
318325f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
318431fd884bSRichard Henderson                 if (i < ARRAY_SIZE(op->output_pref)) {
318525f49c5fSRichard Henderson                     op->output_pref[i] = *la_temp_pref(ts);
318631fd884bSRichard Henderson                 }
318725f49c5fSRichard Henderson 
318825f49c5fSRichard Henderson                 /* Output args are dead.  */
318925f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
3190a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
31916b64b624SAurelien Jarno                 }
319225f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
3193a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
31949c43b68dSAurelien Jarno                 }
319525f49c5fSRichard Henderson                 ts->state = TS_DEAD;
319625f49c5fSRichard Henderson                 la_reset_pref(ts);
3197c896fe29Sbellard             }
3198c896fe29Sbellard 
319925f49c5fSRichard Henderson             /* If end of basic block, update.  */
3200ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
3201ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
3202b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_COND_BRANCH) {
3203b4cb76e6SRichard Henderson                 la_bb_sync(s, nb_globals, nb_temps);
3204ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
32052616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
32063d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
3207f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
320825f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
320925f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
321025f49c5fSRichard Henderson                 }
3211c896fe29Sbellard             }
3212c896fe29Sbellard 
321325f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
3214866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
321525f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
321625f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
3217a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
3218c896fe29Sbellard                 }
3219c19f47bfSAurelien Jarno             }
322025f49c5fSRichard Henderson 
322125f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
3222c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
322325f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
322425f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
322525f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
322625f49c5fSRichard Henderson                        all regs for the type.  */
322725f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
322825f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
322925f49c5fSRichard Henderson                 }
323025f49c5fSRichard Henderson             }
323125f49c5fSRichard Henderson 
323225f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
323325f49c5fSRichard Henderson             switch (opc) {
323425f49c5fSRichard Henderson             case INDEX_op_mov_i32:
323525f49c5fSRichard Henderson             case INDEX_op_mov_i64:
323625f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
323725f49c5fSRichard Henderson                    have proper constraints.  That said, special case
323825f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
323925f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
324025f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
324125f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
324225f49c5fSRichard Henderson                 }
324325f49c5fSRichard Henderson                 break;
324425f49c5fSRichard Henderson 
324525f49c5fSRichard Henderson             default:
324625f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
324725f49c5fSRichard Henderson                     const TCGArgConstraint *ct = &def->args_ct[i];
324825f49c5fSRichard Henderson                     TCGRegSet set, *pset;
324925f49c5fSRichard Henderson 
325025f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
325125f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
325225f49c5fSRichard Henderson                     set = *pset;
325325f49c5fSRichard Henderson 
32549be0d080SRichard Henderson                     set &= ct->regs;
3255bc2b17e6SRichard Henderson                     if (ct->ialias) {
325631fd884bSRichard Henderson                         set &= output_pref(op, ct->alias_index);
325725f49c5fSRichard Henderson                     }
325825f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
325925f49c5fSRichard Henderson                     if (set == 0) {
32609be0d080SRichard Henderson                         set = ct->regs;
326125f49c5fSRichard Henderson                     }
326225f49c5fSRichard Henderson                     *pset = set;
326325f49c5fSRichard Henderson                 }
326425f49c5fSRichard Henderson                 break;
3265c896fe29Sbellard             }
3266c896fe29Sbellard             break;
3267c896fe29Sbellard         }
3268bee158cbSRichard Henderson         op->life = arg_life;
3269c896fe29Sbellard     }
32701ff0a2c5SEvgeny Voevodin }
3271c896fe29Sbellard 
32725a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
32739bbee4c0SRichard Henderson static bool __attribute__((noinline))
32749bbee4c0SRichard Henderson liveness_pass_2(TCGContext *s)
32755a18407fSRichard Henderson {
32765a18407fSRichard Henderson     int nb_globals = s->nb_globals;
327715fa08f8SRichard Henderson     int nb_temps, i;
32785a18407fSRichard Henderson     bool changes = false;
327915fa08f8SRichard Henderson     TCGOp *op, *op_next;
32805a18407fSRichard Henderson 
32815a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
32825a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
32835a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
32845a18407fSRichard Henderson         if (its->indirect_reg) {
32855a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
32865a18407fSRichard Henderson             dts->type = its->type;
32875a18407fSRichard Henderson             dts->base_type = its->base_type;
3288e1e64652SRichard Henderson             dts->temp_subindex = its->temp_subindex;
3289c7482438SRichard Henderson             dts->kind = TEMP_EBB;
3290b83eabeaSRichard Henderson             its->state_ptr = dts;
3291b83eabeaSRichard Henderson         } else {
3292b83eabeaSRichard Henderson             its->state_ptr = NULL;
32935a18407fSRichard Henderson         }
3294b83eabeaSRichard Henderson         /* All globals begin dead.  */
3295b83eabeaSRichard Henderson         its->state = TS_DEAD;
32965a18407fSRichard Henderson     }
3297b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
3298b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
3299b83eabeaSRichard Henderson         its->state_ptr = NULL;
3300b83eabeaSRichard Henderson         its->state = TS_DEAD;
3301b83eabeaSRichard Henderson     }
33025a18407fSRichard Henderson 
330315fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
33045a18407fSRichard Henderson         TCGOpcode opc = op->opc;
33055a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
33065a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
33075a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
3308b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
33095a18407fSRichard Henderson 
33105a18407fSRichard Henderson         if (opc == INDEX_op_call) {
3311cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
3312cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
331390163900SRichard Henderson             call_flags = tcg_call_flags(op);
33145a18407fSRichard Henderson         } else {
33155a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
33165a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
33175a18407fSRichard Henderson 
33185a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
3319b4cb76e6SRichard Henderson             if (def->flags & TCG_OPF_COND_BRANCH) {
3320b4cb76e6SRichard Henderson                 /* Like reading globals: sync_globals */
3321b4cb76e6SRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
3322b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
33235a18407fSRichard Henderson                 /* Like writing globals: save_globals */
33245a18407fSRichard Henderson                 call_flags = 0;
33255a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
33265a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
33275a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
33285a18407fSRichard Henderson             } else {
33295a18407fSRichard Henderson                 /* No effect on globals.  */
33305a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
33315a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
33325a18407fSRichard Henderson             }
33335a18407fSRichard Henderson         }
33345a18407fSRichard Henderson 
33355a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
33365a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3337b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3338b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
3339b83eabeaSRichard Henderson             if (dir_ts && arg_ts->state == TS_DEAD) {
3340b83eabeaSRichard Henderson                 TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
33415a18407fSRichard Henderson                                   ? INDEX_op_ld_i32
33425a18407fSRichard Henderson                                   : INDEX_op_ld_i64);
3343d4478943SPhilippe Mathieu-Daudé                 TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3);
33445a18407fSRichard Henderson 
3345b83eabeaSRichard Henderson                 lop->args[0] = temp_arg(dir_ts);
3346b83eabeaSRichard Henderson                 lop->args[1] = temp_arg(arg_ts->mem_base);
3347b83eabeaSRichard Henderson                 lop->args[2] = arg_ts->mem_offset;
33485a18407fSRichard Henderson 
33495a18407fSRichard Henderson                 /* Loaded, but synced with memory.  */
3350b83eabeaSRichard Henderson                 arg_ts->state = TS_MEM;
33515a18407fSRichard Henderson             }
33525a18407fSRichard Henderson         }
33535a18407fSRichard Henderson 
33545a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
33555a18407fSRichard Henderson            No action is required except keeping temp_state up to date
33565a18407fSRichard Henderson            so that we reload when needed.  */
33575a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3358b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3359b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
3360b83eabeaSRichard Henderson             if (dir_ts) {
3361b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
33625a18407fSRichard Henderson                 changes = true;
33635a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3364b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
33655a18407fSRichard Henderson                 }
33665a18407fSRichard Henderson             }
33675a18407fSRichard Henderson         }
33685a18407fSRichard Henderson 
33695a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
33705a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
33715a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
33725a18407fSRichard Henderson             /* Nothing to do */
33735a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
33745a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
33755a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
33765a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
3377b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3378b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3379b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
33805a18407fSRichard Henderson             }
33815a18407fSRichard Henderson         } else {
33825a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
33835a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
33845a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
3385b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3386b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3387b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
33885a18407fSRichard Henderson             }
33895a18407fSRichard Henderson         }
33905a18407fSRichard Henderson 
33915a18407fSRichard Henderson         /* Outputs become available.  */
339261f15c48SRichard Henderson         if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) {
339361f15c48SRichard Henderson             arg_ts = arg_temp(op->args[0]);
339461f15c48SRichard Henderson             dir_ts = arg_ts->state_ptr;
339561f15c48SRichard Henderson             if (dir_ts) {
339661f15c48SRichard Henderson                 op->args[0] = temp_arg(dir_ts);
339761f15c48SRichard Henderson                 changes = true;
339861f15c48SRichard Henderson 
339961f15c48SRichard Henderson                 /* The output is now live and modified.  */
340061f15c48SRichard Henderson                 arg_ts->state = 0;
340161f15c48SRichard Henderson 
340261f15c48SRichard Henderson                 if (NEED_SYNC_ARG(0)) {
340361f15c48SRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
340461f15c48SRichard Henderson                                       ? INDEX_op_st_i32
340561f15c48SRichard Henderson                                       : INDEX_op_st_i64);
3406d4478943SPhilippe Mathieu-Daudé                     TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
340761f15c48SRichard Henderson                     TCGTemp *out_ts = dir_ts;
340861f15c48SRichard Henderson 
340961f15c48SRichard Henderson                     if (IS_DEAD_ARG(0)) {
341061f15c48SRichard Henderson                         out_ts = arg_temp(op->args[1]);
341161f15c48SRichard Henderson                         arg_ts->state = TS_DEAD;
341261f15c48SRichard Henderson                         tcg_op_remove(s, op);
341361f15c48SRichard Henderson                     } else {
341461f15c48SRichard Henderson                         arg_ts->state = TS_MEM;
341561f15c48SRichard Henderson                     }
341661f15c48SRichard Henderson 
341761f15c48SRichard Henderson                     sop->args[0] = temp_arg(out_ts);
341861f15c48SRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
341961f15c48SRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
342061f15c48SRichard Henderson                 } else {
342161f15c48SRichard Henderson                     tcg_debug_assert(!IS_DEAD_ARG(0));
342261f15c48SRichard Henderson                 }
342361f15c48SRichard Henderson             }
342461f15c48SRichard Henderson         } else {
34255a18407fSRichard Henderson             for (i = 0; i < nb_oargs; i++) {
3426b83eabeaSRichard Henderson                 arg_ts = arg_temp(op->args[i]);
3427b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3428b83eabeaSRichard Henderson                 if (!dir_ts) {
34295a18407fSRichard Henderson                     continue;
34305a18407fSRichard Henderson                 }
3431b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
34325a18407fSRichard Henderson                 changes = true;
34335a18407fSRichard Henderson 
34345a18407fSRichard Henderson                 /* The output is now live and modified.  */
3435b83eabeaSRichard Henderson                 arg_ts->state = 0;
34365a18407fSRichard Henderson 
34375a18407fSRichard Henderson                 /* Sync outputs upon their last write.  */
34385a18407fSRichard Henderson                 if (NEED_SYNC_ARG(i)) {
3439b83eabeaSRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
34405a18407fSRichard Henderson                                       ? INDEX_op_st_i32
34415a18407fSRichard Henderson                                       : INDEX_op_st_i64);
3442d4478943SPhilippe Mathieu-Daudé                     TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
34435a18407fSRichard Henderson 
3444b83eabeaSRichard Henderson                     sop->args[0] = temp_arg(dir_ts);
3445b83eabeaSRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
3446b83eabeaSRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
34475a18407fSRichard Henderson 
3448b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
34495a18407fSRichard Henderson                 }
34505a18407fSRichard Henderson                 /* Drop outputs that are dead.  */
34515a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3452b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
34535a18407fSRichard Henderson                 }
34545a18407fSRichard Henderson             }
34555a18407fSRichard Henderson         }
345661f15c48SRichard Henderson     }
34575a18407fSRichard Henderson 
34585a18407fSRichard Henderson     return changes;
34595a18407fSRichard Henderson }
34605a18407fSRichard Henderson 
34612272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
3462c896fe29Sbellard {
346331c96417SRichard Henderson     intptr_t off;
3464273eb50cSRichard Henderson     int size, align;
3465c1c09194SRichard Henderson 
3466273eb50cSRichard Henderson     /* When allocating an object, look at the full type. */
3467273eb50cSRichard Henderson     size = tcg_type_size(ts->base_type);
3468273eb50cSRichard Henderson     switch (ts->base_type) {
3469c1c09194SRichard Henderson     case TCG_TYPE_I32:
347031c96417SRichard Henderson         align = 4;
3471c1c09194SRichard Henderson         break;
3472c1c09194SRichard Henderson     case TCG_TYPE_I64:
3473c1c09194SRichard Henderson     case TCG_TYPE_V64:
347431c96417SRichard Henderson         align = 8;
3475c1c09194SRichard Henderson         break;
347643eef72fSRichard Henderson     case TCG_TYPE_I128:
3477c1c09194SRichard Henderson     case TCG_TYPE_V128:
3478c1c09194SRichard Henderson     case TCG_TYPE_V256:
347943eef72fSRichard Henderson         /*
348043eef72fSRichard Henderson          * Note that we do not require aligned storage for V256,
348143eef72fSRichard Henderson          * and that we provide alignment for I128 to match V128,
348243eef72fSRichard Henderson          * even if that's above what the host ABI requires.
348343eef72fSRichard Henderson          */
348431c96417SRichard Henderson         align = 16;
3485c1c09194SRichard Henderson         break;
3486c1c09194SRichard Henderson     default:
3487c1c09194SRichard Henderson         g_assert_not_reached();
3488b591dc59SBlue Swirl     }
3489c1c09194SRichard Henderson 
3490b9537d59SRichard Henderson     /*
3491b9537d59SRichard Henderson      * Assume the stack is sufficiently aligned.
3492b9537d59SRichard Henderson      * This affects e.g. ARM NEON, where we have 8 byte stack alignment
3493b9537d59SRichard Henderson      * and do not require 16 byte vector alignment.  This seems slightly
3494b9537d59SRichard Henderson      * easier than fully parameterizing the above switch statement.
3495b9537d59SRichard Henderson      */
3496b9537d59SRichard Henderson     align = MIN(TCG_TARGET_STACK_ALIGN, align);
3497c1c09194SRichard Henderson     off = ROUND_UP(s->current_frame_offset, align);
3498732d5897SRichard Henderson 
3499732d5897SRichard Henderson     /* If we've exhausted the stack frame, restart with a smaller TB. */
3500732d5897SRichard Henderson     if (off + size > s->frame_end) {
3501732d5897SRichard Henderson         tcg_raise_tb_overflow(s);
3502732d5897SRichard Henderson     }
3503c1c09194SRichard Henderson     s->current_frame_offset = off + size;
35049defd1bdSRichard Henderson #if defined(__sparc__)
3505273eb50cSRichard Henderson     off += TCG_TARGET_STACK_BIAS;
35069defd1bdSRichard Henderson #endif
3507273eb50cSRichard Henderson 
3508273eb50cSRichard Henderson     /* If the object was subdivided, assign memory to all the parts. */
3509273eb50cSRichard Henderson     if (ts->base_type != ts->type) {
3510273eb50cSRichard Henderson         int part_size = tcg_type_size(ts->type);
3511273eb50cSRichard Henderson         int part_count = size / part_size;
3512273eb50cSRichard Henderson 
3513273eb50cSRichard Henderson         /*
3514273eb50cSRichard Henderson          * Each part is allocated sequentially in tcg_temp_new_internal.
3515273eb50cSRichard Henderson          * Jump back to the first part by subtracting the current index.
3516273eb50cSRichard Henderson          */
3517273eb50cSRichard Henderson         ts -= ts->temp_subindex;
3518273eb50cSRichard Henderson         for (int i = 0; i < part_count; ++i) {
3519273eb50cSRichard Henderson             ts[i].mem_offset = off + i * part_size;
3520273eb50cSRichard Henderson             ts[i].mem_base = s->frame_temp;
3521273eb50cSRichard Henderson             ts[i].mem_allocated = 1;
3522273eb50cSRichard Henderson         }
3523273eb50cSRichard Henderson     } else {
3524273eb50cSRichard Henderson         ts->mem_offset = off;
3525b3a62939SRichard Henderson         ts->mem_base = s->frame_temp;
3526c896fe29Sbellard         ts->mem_allocated = 1;
3527c896fe29Sbellard     }
3528273eb50cSRichard Henderson }
3529c896fe29Sbellard 
3530098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */
3531098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg)
3532098859f1SRichard Henderson {
3533098859f1SRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
3534098859f1SRichard Henderson         TCGReg old = ts->reg;
3535098859f1SRichard Henderson         tcg_debug_assert(s->reg_to_temp[old] == ts);
3536098859f1SRichard Henderson         if (old == reg) {
3537098859f1SRichard Henderson             return;
3538098859f1SRichard Henderson         }
3539098859f1SRichard Henderson         s->reg_to_temp[old] = NULL;
3540098859f1SRichard Henderson     }
3541098859f1SRichard Henderson     tcg_debug_assert(s->reg_to_temp[reg] == NULL);
3542098859f1SRichard Henderson     s->reg_to_temp[reg] = ts;
3543098859f1SRichard Henderson     ts->val_type = TEMP_VAL_REG;
3544098859f1SRichard Henderson     ts->reg = reg;
3545098859f1SRichard Henderson }
3546098859f1SRichard Henderson 
3547098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */
3548098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type)
3549098859f1SRichard Henderson {
3550098859f1SRichard Henderson     tcg_debug_assert(type != TEMP_VAL_REG);
3551098859f1SRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
3552098859f1SRichard Henderson         TCGReg reg = ts->reg;
3553098859f1SRichard Henderson         tcg_debug_assert(s->reg_to_temp[reg] == ts);
3554098859f1SRichard Henderson         s->reg_to_temp[reg] = NULL;
3555098859f1SRichard Henderson     }
3556098859f1SRichard Henderson     ts->val_type = type;
3557098859f1SRichard Henderson }
3558098859f1SRichard Henderson 
3559b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
3560b3915dbbSRichard Henderson 
356159d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
356259d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
356359d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
3564c896fe29Sbellard {
3565c0522136SRichard Henderson     TCGTempVal new_type;
3566c0522136SRichard Henderson 
3567c0522136SRichard Henderson     switch (ts->kind) {
3568c0522136SRichard Henderson     case TEMP_FIXED:
356959d7c14eSRichard Henderson         return;
3570c0522136SRichard Henderson     case TEMP_GLOBAL:
3571f57c6915SRichard Henderson     case TEMP_TB:
3572c0522136SRichard Henderson         new_type = TEMP_VAL_MEM;
3573c0522136SRichard Henderson         break;
3574c0522136SRichard Henderson     case TEMP_NORMAL:
3575c7482438SRichard Henderson     case TEMP_EBB:
3576c0522136SRichard Henderson         new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD;
3577c0522136SRichard Henderson         break;
3578c0522136SRichard Henderson     case TEMP_CONST:
3579c0522136SRichard Henderson         new_type = TEMP_VAL_CONST;
3580c0522136SRichard Henderson         break;
3581c0522136SRichard Henderson     default:
3582c0522136SRichard Henderson         g_assert_not_reached();
358359d7c14eSRichard Henderson     }
3584098859f1SRichard Henderson     set_temp_val_nonreg(s, ts, new_type);
358559d7c14eSRichard Henderson }
3586c896fe29Sbellard 
358759d7c14eSRichard Henderson /* Mark a temporary as dead.  */
358859d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
358959d7c14eSRichard Henderson {
359059d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
359159d7c14eSRichard Henderson }
359259d7c14eSRichard Henderson 
359359d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
359459d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
359559d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
359659d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
359798b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
359898b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
359959d7c14eSRichard Henderson {
3600c0522136SRichard Henderson     if (!temp_readonly(ts) && !ts->mem_coherent) {
36017f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
36022272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
360359d7c14eSRichard Henderson         }
360459d7c14eSRichard Henderson         switch (ts->val_type) {
360559d7c14eSRichard Henderson         case TEMP_VAL_CONST:
360659d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
360759d7c14eSRichard Henderson                require it later in a register, so attempt to store the
360859d7c14eSRichard Henderson                constant to memory directly.  */
360959d7c14eSRichard Henderson             if (free_or_dead
361059d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
361159d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
361259d7c14eSRichard Henderson                 break;
361359d7c14eSRichard Henderson             }
361459d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
361598b4e186SRichard Henderson                       allocated_regs, preferred_regs);
361659d7c14eSRichard Henderson             /* fallthrough */
361759d7c14eSRichard Henderson 
361859d7c14eSRichard Henderson         case TEMP_VAL_REG:
361959d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
362059d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
362159d7c14eSRichard Henderson             break;
362259d7c14eSRichard Henderson 
362359d7c14eSRichard Henderson         case TEMP_VAL_MEM:
362459d7c14eSRichard Henderson             break;
362559d7c14eSRichard Henderson 
362659d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
362759d7c14eSRichard Henderson         default:
362859d7c14eSRichard Henderson             tcg_abort();
3629c896fe29Sbellard         }
36307f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
36317f6ceedfSAurelien Jarno     }
363259d7c14eSRichard Henderson     if (free_or_dead) {
363359d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
363459d7c14eSRichard Henderson     }
363559d7c14eSRichard Henderson }
36367f6ceedfSAurelien Jarno 
36377f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
3638b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
36397f6ceedfSAurelien Jarno {
3640f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
3641f8b2f202SRichard Henderson     if (ts != NULL) {
364298b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
3643c896fe29Sbellard     }
3644c896fe29Sbellard }
3645c896fe29Sbellard 
3646b016486eSRichard Henderson /**
3647b016486eSRichard Henderson  * tcg_reg_alloc:
3648b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
3649b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
3650b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
3651b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
3652b016486eSRichard Henderson  *
3653b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
3654b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
3655b016486eSRichard Henderson  */
3656b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
3657b016486eSRichard Henderson                             TCGRegSet allocated_regs,
3658b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
3659c896fe29Sbellard {
3660b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
3661b016486eSRichard Henderson     TCGRegSet reg_ct[2];
366291478cefSRichard Henderson     const int *order;
3663c896fe29Sbellard 
3664b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
3665b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
3666b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
3667b016486eSRichard Henderson 
3668b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
3669b016486eSRichard Henderson        or if the preference made no difference.  */
3670b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
3671b016486eSRichard Henderson 
367291478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
3673c896fe29Sbellard 
3674b016486eSRichard Henderson     /* Try free registers, preferences first.  */
3675b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3676b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3677b016486eSRichard Henderson 
3678b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3679b016486eSRichard Henderson             /* One register in the set.  */
3680b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3681b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
3682c896fe29Sbellard                 return reg;
3683c896fe29Sbellard             }
3684b016486eSRichard Henderson         } else {
368591478cefSRichard Henderson             for (i = 0; i < n; i++) {
3686b016486eSRichard Henderson                 TCGReg reg = order[i];
3687b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
3688b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
3689b016486eSRichard Henderson                     return reg;
3690b016486eSRichard Henderson                 }
3691b016486eSRichard Henderson             }
3692b016486eSRichard Henderson         }
3693b016486eSRichard Henderson     }
3694b016486eSRichard Henderson 
3695b016486eSRichard Henderson     /* We must spill something.  */
3696b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3697b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3698b016486eSRichard Henderson 
3699b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3700b016486eSRichard Henderson             /* One register in the set.  */
3701b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3702b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
3703c896fe29Sbellard             return reg;
3704b016486eSRichard Henderson         } else {
3705b016486eSRichard Henderson             for (i = 0; i < n; i++) {
3706b016486eSRichard Henderson                 TCGReg reg = order[i];
3707b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
3708b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
3709b016486eSRichard Henderson                     return reg;
3710b016486eSRichard Henderson                 }
3711b016486eSRichard Henderson             }
3712c896fe29Sbellard         }
3713c896fe29Sbellard     }
3714c896fe29Sbellard 
3715c896fe29Sbellard     tcg_abort();
3716c896fe29Sbellard }
3717c896fe29Sbellard 
371829f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs,
371929f5e925SRichard Henderson                                  TCGRegSet allocated_regs,
372029f5e925SRichard Henderson                                  TCGRegSet preferred_regs, bool rev)
372129f5e925SRichard Henderson {
372229f5e925SRichard Henderson     int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
372329f5e925SRichard Henderson     TCGRegSet reg_ct[2];
372429f5e925SRichard Henderson     const int *order;
372529f5e925SRichard Henderson 
372629f5e925SRichard Henderson     /* Ensure that if I is not in allocated_regs, I+1 is not either. */
372729f5e925SRichard Henderson     reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1));
372829f5e925SRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
372929f5e925SRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
373029f5e925SRichard Henderson 
373129f5e925SRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
373229f5e925SRichard Henderson 
373329f5e925SRichard Henderson     /*
373429f5e925SRichard Henderson      * Skip the preferred_regs option if it cannot be satisfied,
373529f5e925SRichard Henderson      * or if the preference made no difference.
373629f5e925SRichard Henderson      */
373729f5e925SRichard Henderson     k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
373829f5e925SRichard Henderson 
373929f5e925SRichard Henderson     /*
374029f5e925SRichard Henderson      * Minimize the number of flushes by looking for 2 free registers first,
374129f5e925SRichard Henderson      * then a single flush, then two flushes.
374229f5e925SRichard Henderson      */
374329f5e925SRichard Henderson     for (fmin = 2; fmin >= 0; fmin--) {
374429f5e925SRichard Henderson         for (j = k; j < 2; j++) {
374529f5e925SRichard Henderson             TCGRegSet set = reg_ct[j];
374629f5e925SRichard Henderson 
374729f5e925SRichard Henderson             for (i = 0; i < n; i++) {
374829f5e925SRichard Henderson                 TCGReg reg = order[i];
374929f5e925SRichard Henderson 
375029f5e925SRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
375129f5e925SRichard Henderson                     int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1];
375229f5e925SRichard Henderson                     if (f >= fmin) {
375329f5e925SRichard Henderson                         tcg_reg_free(s, reg, allocated_regs);
375429f5e925SRichard Henderson                         tcg_reg_free(s, reg + 1, allocated_regs);
375529f5e925SRichard Henderson                         return reg;
375629f5e925SRichard Henderson                     }
375729f5e925SRichard Henderson                 }
375829f5e925SRichard Henderson             }
375929f5e925SRichard Henderson         }
376029f5e925SRichard Henderson     }
376129f5e925SRichard Henderson     tcg_abort();
376229f5e925SRichard Henderson }
376329f5e925SRichard Henderson 
376440ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
376540ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
376640ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
3767b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
376840ae5c62SRichard Henderson {
376940ae5c62SRichard Henderson     TCGReg reg;
377040ae5c62SRichard Henderson 
377140ae5c62SRichard Henderson     switch (ts->val_type) {
377240ae5c62SRichard Henderson     case TEMP_VAL_REG:
377340ae5c62SRichard Henderson         return;
377440ae5c62SRichard Henderson     case TEMP_VAL_CONST:
3775b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3776b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
37770a6a8bc8SRichard Henderson         if (ts->type <= TCG_TYPE_I64) {
377840ae5c62SRichard Henderson             tcg_out_movi(s, ts->type, reg, ts->val);
37790a6a8bc8SRichard Henderson         } else {
37804e186175SRichard Henderson             uint64_t val = ts->val;
37814e186175SRichard Henderson             MemOp vece = MO_64;
37824e186175SRichard Henderson 
37834e186175SRichard Henderson             /*
37844e186175SRichard Henderson              * Find the minimal vector element that matches the constant.
37854e186175SRichard Henderson              * The targets will, in general, have to do this search anyway,
37864e186175SRichard Henderson              * do this generically.
37874e186175SRichard Henderson              */
37884e186175SRichard Henderson             if (val == dup_const(MO_8, val)) {
37894e186175SRichard Henderson                 vece = MO_8;
37904e186175SRichard Henderson             } else if (val == dup_const(MO_16, val)) {
37914e186175SRichard Henderson                 vece = MO_16;
37920b4286ddSRichard Henderson             } else if (val == dup_const(MO_32, val)) {
37934e186175SRichard Henderson                 vece = MO_32;
37944e186175SRichard Henderson             }
37954e186175SRichard Henderson 
37964e186175SRichard Henderson             tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val);
37970a6a8bc8SRichard Henderson         }
379840ae5c62SRichard Henderson         ts->mem_coherent = 0;
379940ae5c62SRichard Henderson         break;
380040ae5c62SRichard Henderson     case TEMP_VAL_MEM:
3801b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3802b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
380340ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
380440ae5c62SRichard Henderson         ts->mem_coherent = 1;
380540ae5c62SRichard Henderson         break;
380640ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
380740ae5c62SRichard Henderson     default:
380840ae5c62SRichard Henderson         tcg_abort();
380940ae5c62SRichard Henderson     }
3810098859f1SRichard Henderson     set_temp_val_reg(s, ts, reg);
381140ae5c62SRichard Henderson }
381240ae5c62SRichard Henderson 
381359d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
3814e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
381559d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
38161ad80729SAurelien Jarno {
38172c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
3818eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
3819e01fa97dSRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts));
38201ad80729SAurelien Jarno }
38211ad80729SAurelien Jarno 
38229814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
3823641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
3824641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
3825641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
3826641d5fbeSbellard {
3827ac3b8891SRichard Henderson     int i, n;
3828641d5fbeSbellard 
3829ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
3830b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
3831641d5fbeSbellard     }
3832e5097dc8Sbellard }
3833e5097dc8Sbellard 
38343d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
38353d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
38363d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
38373d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
38383d5c5f87SAurelien Jarno {
3839ac3b8891SRichard Henderson     int i, n;
38403d5c5f87SAurelien Jarno 
3841ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
384212b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
384312b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
3844ee17db83SRichard Henderson                          || ts->kind == TEMP_FIXED
384512b9b11aSRichard Henderson                          || ts->mem_coherent);
38463d5c5f87SAurelien Jarno     }
38473d5c5f87SAurelien Jarno }
38483d5c5f87SAurelien Jarno 
3849e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
3850e8996ee0Sbellard    all globals are stored at their canonical location. */
3851e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
3852e5097dc8Sbellard {
3853e5097dc8Sbellard     int i;
3854e5097dc8Sbellard 
3855c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
3856b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
3857c0522136SRichard Henderson 
3858c0522136SRichard Henderson         switch (ts->kind) {
3859f57c6915SRichard Henderson         case TEMP_TB:
3860b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
3861c0522136SRichard Henderson             break;
3862c0522136SRichard Henderson         case TEMP_NORMAL:
3863c7482438SRichard Henderson         case TEMP_EBB:
38642c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
3865eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
3866eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3867c0522136SRichard Henderson             break;
3868c0522136SRichard Henderson         case TEMP_CONST:
3869c0522136SRichard Henderson             /* Similarly, we should have freed any allocated register. */
3870c0522136SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_CONST);
3871c0522136SRichard Henderson             break;
3872c0522136SRichard Henderson         default:
3873c0522136SRichard Henderson             g_assert_not_reached();
3874c896fe29Sbellard         }
3875641d5fbeSbellard     }
3876e8996ee0Sbellard 
3877e8996ee0Sbellard     save_globals(s, allocated_regs);
3878c896fe29Sbellard }
3879c896fe29Sbellard 
3880bab1671fSRichard Henderson /*
3881c7482438SRichard Henderson  * At a conditional branch, we assume all temporaries are dead unless
3882c7482438SRichard Henderson  * explicitly live-across-conditional-branch; all globals and local
3883c7482438SRichard Henderson  * temps are synced to their location.
3884b4cb76e6SRichard Henderson  */
3885b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
3886b4cb76e6SRichard Henderson {
3887b4cb76e6SRichard Henderson     sync_globals(s, allocated_regs);
3888b4cb76e6SRichard Henderson 
3889b4cb76e6SRichard Henderson     for (int i = s->nb_globals; i < s->nb_temps; i++) {
3890b4cb76e6SRichard Henderson         TCGTemp *ts = &s->temps[i];
3891b4cb76e6SRichard Henderson         /*
3892b4cb76e6SRichard Henderson          * The liveness analysis already ensures that temps are dead.
3893b4cb76e6SRichard Henderson          * Keep tcg_debug_asserts for safety.
3894b4cb76e6SRichard Henderson          */
3895c0522136SRichard Henderson         switch (ts->kind) {
3896f57c6915SRichard Henderson         case TEMP_TB:
3897b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
3898c0522136SRichard Henderson             break;
3899c0522136SRichard Henderson         case TEMP_NORMAL:
3900b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3901c0522136SRichard Henderson             break;
3902c7482438SRichard Henderson         case TEMP_EBB:
3903c0522136SRichard Henderson         case TEMP_CONST:
3904c0522136SRichard Henderson             break;
3905c0522136SRichard Henderson         default:
3906c0522136SRichard Henderson             g_assert_not_reached();
3907b4cb76e6SRichard Henderson         }
3908b4cb76e6SRichard Henderson     }
3909b4cb76e6SRichard Henderson }
3910b4cb76e6SRichard Henderson 
3911b4cb76e6SRichard Henderson /*
3912c58f4c97SRichard Henderson  * Specialized code generation for INDEX_op_mov_* with a constant.
3913bab1671fSRichard Henderson  */
39140fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
3915ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
3916ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
3917e8996ee0Sbellard {
3918d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3919e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
392059d7c14eSRichard Henderson 
392159d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
3922098859f1SRichard Henderson     set_temp_val_nonreg(s, ots, TEMP_VAL_CONST);
3923e8996ee0Sbellard     ots->val = val;
392459d7c14eSRichard Henderson     ots->mem_coherent = 0;
3925ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
3926ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
392759d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
3928f8bf00f1SRichard Henderson         temp_dead(s, ots);
39294c4e1ab2SAurelien Jarno     }
3930e8996ee0Sbellard }
3931e8996ee0Sbellard 
3932bab1671fSRichard Henderson /*
3933bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
3934bab1671fSRichard Henderson  */
3935dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
3936c896fe29Sbellard {
3937dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
393869e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
3939c896fe29Sbellard     TCGTemp *ts, *ots;
3940450445d5SRichard Henderson     TCGType otype, itype;
3941098859f1SRichard Henderson     TCGReg oreg, ireg;
3942c896fe29Sbellard 
3943d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
394431fd884bSRichard Henderson     preferred_regs = output_pref(op, 0);
394543439139SRichard Henderson     ots = arg_temp(op->args[0]);
394643439139SRichard Henderson     ts = arg_temp(op->args[1]);
3947450445d5SRichard Henderson 
3948d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3949e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
3950d63e3b6eSRichard Henderson 
3951450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
3952450445d5SRichard Henderson     otype = ots->type;
3953450445d5SRichard Henderson     itype = ts->type;
3954c896fe29Sbellard 
39550fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
39560fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
39570fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
39580fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
39590fe4fca4SPaolo Bonzini             temp_dead(s, ts);
39600fe4fca4SPaolo Bonzini         }
396169e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
39620fe4fca4SPaolo Bonzini         return;
39630fe4fca4SPaolo Bonzini     }
39640fe4fca4SPaolo Bonzini 
39650fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
39660fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
39670fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
39680fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
39690fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
397069e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
397169e3706dSRichard Henderson                   allocated_regs, preferred_regs);
3972c29c1d7eSAurelien Jarno     }
39730fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
3974098859f1SRichard Henderson     ireg = ts->reg;
3975098859f1SRichard Henderson 
3976d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
3977c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
3978c29c1d7eSAurelien Jarno            liveness analysis disabled). */
3979eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
3980c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
39812272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
3982c29c1d7eSAurelien Jarno         }
3983098859f1SRichard Henderson         tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset);
3984c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
3985f8bf00f1SRichard Henderson             temp_dead(s, ts);
3986c29c1d7eSAurelien Jarno         }
3987f8bf00f1SRichard Henderson         temp_dead(s, ots);
3988098859f1SRichard Henderson         return;
3989098859f1SRichard Henderson     }
3990098859f1SRichard Henderson 
3991ee17db83SRichard Henderson     if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) {
3992098859f1SRichard Henderson         /*
3993098859f1SRichard Henderson          * The mov can be suppressed.  Kill input first, so that it
3994098859f1SRichard Henderson          * is unlinked from reg_to_temp, then set the output to the
3995098859f1SRichard Henderson          * reg that we saved from the input.
3996098859f1SRichard Henderson          */
3997f8bf00f1SRichard Henderson         temp_dead(s, ts);
3998098859f1SRichard Henderson         oreg = ireg;
3999c29c1d7eSAurelien Jarno     } else {
4000098859f1SRichard Henderson         if (ots->val_type == TEMP_VAL_REG) {
4001098859f1SRichard Henderson             oreg = ots->reg;
4002098859f1SRichard Henderson         } else {
4003098859f1SRichard Henderson             /* Make sure to not spill the input register during allocation. */
4004098859f1SRichard Henderson             oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
4005098859f1SRichard Henderson                                  allocated_regs | ((TCGRegSet)1 << ireg),
4006098859f1SRichard Henderson                                  preferred_regs, ots->indirect_base);
4007c29c1d7eSAurelien Jarno         }
4008098859f1SRichard Henderson         if (!tcg_out_mov(s, otype, oreg, ireg)) {
4009240c08d0SRichard Henderson             /*
4010240c08d0SRichard Henderson              * Cross register class move not supported.
4011240c08d0SRichard Henderson              * Store the source register into the destination slot
4012240c08d0SRichard Henderson              * and leave the destination temp as TEMP_VAL_MEM.
4013240c08d0SRichard Henderson              */
4014e01fa97dSRichard Henderson             assert(!temp_readonly(ots));
4015240c08d0SRichard Henderson             if (!ts->mem_allocated) {
4016240c08d0SRichard Henderson                 temp_allocate_frame(s, ots);
4017240c08d0SRichard Henderson             }
4018098859f1SRichard Henderson             tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset);
4019098859f1SRichard Henderson             set_temp_val_nonreg(s, ts, TEMP_VAL_MEM);
4020240c08d0SRichard Henderson             ots->mem_coherent = 1;
4021240c08d0SRichard Henderson             return;
402278113e83SRichard Henderson         }
4023c29c1d7eSAurelien Jarno     }
4024098859f1SRichard Henderson     set_temp_val_reg(s, ots, oreg);
4025c896fe29Sbellard     ots->mem_coherent = 0;
4026098859f1SRichard Henderson 
4027ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
402898b4e186SRichard Henderson         temp_sync(s, ots, allocated_regs, 0, 0);
4029c29c1d7eSAurelien Jarno     }
4030ec7a869dSAurelien Jarno }
4031c896fe29Sbellard 
4032bab1671fSRichard Henderson /*
4033bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
4034bab1671fSRichard Henderson  */
4035bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
4036bab1671fSRichard Henderson {
4037bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
4038bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
4039bab1671fSRichard Henderson     TCGTemp *its, *ots;
4040bab1671fSRichard Henderson     TCGType itype, vtype;
4041bab1671fSRichard Henderson     unsigned vece;
404231c96417SRichard Henderson     int lowpart_ofs;
4043bab1671fSRichard Henderson     bool ok;
4044bab1671fSRichard Henderson 
4045bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
4046bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
4047bab1671fSRichard Henderson 
4048bab1671fSRichard Henderson     /* ENV should not be modified.  */
4049e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4050bab1671fSRichard Henderson 
4051bab1671fSRichard Henderson     itype = its->type;
4052bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
4053bab1671fSRichard Henderson     vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
4054bab1671fSRichard Henderson 
4055bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
4056bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
4057bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
4058bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
4059bab1671fSRichard Henderson             temp_dead(s, its);
4060bab1671fSRichard Henderson         }
406131fd884bSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0));
4062bab1671fSRichard Henderson         return;
4063bab1671fSRichard Henderson     }
4064bab1671fSRichard Henderson 
40659be0d080SRichard Henderson     dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
40669be0d080SRichard Henderson     dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs;
4067bab1671fSRichard Henderson 
4068bab1671fSRichard Henderson     /* Allocate the output register now.  */
4069bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
4070bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
4071098859f1SRichard Henderson         TCGReg oreg;
4072bab1671fSRichard Henderson 
4073bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
4074bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
4075bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
4076bab1671fSRichard Henderson         }
4077098859f1SRichard Henderson         oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
407831fd884bSRichard Henderson                              output_pref(op, 0), ots->indirect_base);
4079098859f1SRichard Henderson         set_temp_val_reg(s, ots, oreg);
4080bab1671fSRichard Henderson     }
4081bab1671fSRichard Henderson 
4082bab1671fSRichard Henderson     switch (its->val_type) {
4083bab1671fSRichard Henderson     case TEMP_VAL_REG:
4084bab1671fSRichard Henderson         /*
4085bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
4086bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
4087bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
4088bab1671fSRichard Henderson          */
4089bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
4090bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
4091bab1671fSRichard Henderson                 goto done;
4092bab1671fSRichard Henderson             }
4093bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
4094bab1671fSRichard Henderson         }
4095bab1671fSRichard Henderson         if (!its->mem_coherent) {
4096bab1671fSRichard Henderson             /*
4097bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
4098bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
4099bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
4100bab1671fSRichard Henderson              */
4101bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
4102bab1671fSRichard Henderson                 break;
4103bab1671fSRichard Henderson             }
4104bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
4105bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
4106bab1671fSRichard Henderson         }
4107bab1671fSRichard Henderson         /* fall through */
4108bab1671fSRichard Henderson 
4109bab1671fSRichard Henderson     case TEMP_VAL_MEM:
411031c96417SRichard Henderson         lowpart_ofs = 0;
411131c96417SRichard Henderson         if (HOST_BIG_ENDIAN) {
411231c96417SRichard Henderson             lowpart_ofs = tcg_type_size(itype) - (1 << vece);
411331c96417SRichard Henderson         }
4114d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
411531c96417SRichard Henderson                              its->mem_offset + lowpart_ofs)) {
4116d6ecb4a9SRichard Henderson             goto done;
4117d6ecb4a9SRichard Henderson         }
4118098859f1SRichard Henderson         /* Load the input into the destination vector register. */
4119bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
4120bab1671fSRichard Henderson         break;
4121bab1671fSRichard Henderson 
4122bab1671fSRichard Henderson     default:
4123bab1671fSRichard Henderson         g_assert_not_reached();
4124bab1671fSRichard Henderson     }
4125bab1671fSRichard Henderson 
4126bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
4127bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
4128bab1671fSRichard Henderson     tcg_debug_assert(ok);
4129bab1671fSRichard Henderson 
4130bab1671fSRichard Henderson  done:
413136f5539cSRichard Henderson     ots->mem_coherent = 0;
4132bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
4133bab1671fSRichard Henderson         temp_dead(s, its);
4134bab1671fSRichard Henderson     }
4135bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
4136bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
4137bab1671fSRichard Henderson     }
4138bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
4139bab1671fSRichard Henderson         temp_dead(s, ots);
4140bab1671fSRichard Henderson     }
4141bab1671fSRichard Henderson }
4142bab1671fSRichard Henderson 
4143dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
4144c896fe29Sbellard {
4145dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
4146dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
414782790a87SRichard Henderson     TCGRegSet i_allocated_regs;
414882790a87SRichard Henderson     TCGRegSet o_allocated_regs;
4149b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
4150b6638662SRichard Henderson     TCGReg reg;
4151c896fe29Sbellard     TCGArg arg;
4152c896fe29Sbellard     const TCGArgConstraint *arg_ct;
4153c896fe29Sbellard     TCGTemp *ts;
4154c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
4155c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
4156c896fe29Sbellard 
4157c896fe29Sbellard     nb_oargs = def->nb_oargs;
4158c896fe29Sbellard     nb_iargs = def->nb_iargs;
4159c896fe29Sbellard 
4160c896fe29Sbellard     /* copy constants */
4161c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
4162dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
4163c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
4164c896fe29Sbellard 
4165d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
4166d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
416782790a87SRichard Henderson 
4168c896fe29Sbellard     /* satisfy input constraints */
4169c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
417029f5e925SRichard Henderson         TCGRegSet i_preferred_regs, i_required_regs;
417129f5e925SRichard Henderson         bool allocate_new_reg, copyto_new_reg;
417229f5e925SRichard Henderson         TCGTemp *ts2;
417329f5e925SRichard Henderson         int i1, i2;
4174d62816f2SRichard Henderson 
417566792f90SRichard Henderson         i = def->args_ct[nb_oargs + k].sort_index;
4176dd186292SRichard Henderson         arg = op->args[i];
4177c896fe29Sbellard         arg_ct = &def->args_ct[i];
417843439139SRichard Henderson         ts = arg_temp(arg);
417940ae5c62SRichard Henderson 
418040ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
4181a4fbbd77SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct->ct)) {
4182c896fe29Sbellard             /* constant is OK for instruction */
4183c896fe29Sbellard             const_args[i] = 1;
4184c896fe29Sbellard             new_args[i] = ts->val;
4185d62816f2SRichard Henderson             continue;
4186c896fe29Sbellard         }
418740ae5c62SRichard Henderson 
41881c1824dcSRichard Henderson         reg = ts->reg;
41891c1824dcSRichard Henderson         i_preferred_regs = 0;
419029f5e925SRichard Henderson         i_required_regs = arg_ct->regs;
41911c1824dcSRichard Henderson         allocate_new_reg = false;
419229f5e925SRichard Henderson         copyto_new_reg = false;
41931c1824dcSRichard Henderson 
419429f5e925SRichard Henderson         switch (arg_ct->pair) {
419529f5e925SRichard Henderson         case 0: /* not paired */
4196bc2b17e6SRichard Henderson             if (arg_ct->ialias) {
419731fd884bSRichard Henderson                 i_preferred_regs = output_pref(op, arg_ct->alias_index);
4198c0522136SRichard Henderson 
4199c0522136SRichard Henderson                 /*
4200c0522136SRichard Henderson                  * If the input is readonly, then it cannot also be an
4201c0522136SRichard Henderson                  * output and aliased to itself.  If the input is not
4202c0522136SRichard Henderson                  * dead after the instruction, we must allocate a new
4203c0522136SRichard Henderson                  * register and move it.
4204c0522136SRichard Henderson                  */
4205c0522136SRichard Henderson                 if (temp_readonly(ts) || !IS_DEAD_ARG(i)) {
42061c1824dcSRichard Henderson                     allocate_new_reg = true;
42071c1824dcSRichard Henderson                 } else if (ts->val_type == TEMP_VAL_REG) {
4208c0522136SRichard Henderson                     /*
42091c1824dcSRichard Henderson                      * Check if the current register has already been
42101c1824dcSRichard Henderson                      * allocated for another input.
4211c0522136SRichard Henderson                      */
421229f5e925SRichard Henderson                     allocate_new_reg =
421329f5e925SRichard Henderson                         tcg_regset_test_reg(i_allocated_regs, reg);
42147e1df267SAurelien Jarno                 }
42157e1df267SAurelien Jarno             }
42161c1824dcSRichard Henderson             if (!allocate_new_reg) {
421729f5e925SRichard Henderson                 temp_load(s, ts, i_required_regs, i_allocated_regs,
421829f5e925SRichard Henderson                           i_preferred_regs);
4219c896fe29Sbellard                 reg = ts->reg;
422029f5e925SRichard Henderson                 allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg);
42211c1824dcSRichard Henderson             }
42221c1824dcSRichard Henderson             if (allocate_new_reg) {
4223c0522136SRichard Henderson                 /*
4224c0522136SRichard Henderson                  * Allocate a new register matching the constraint
4225c0522136SRichard Henderson                  * and move the temporary register into it.
4226c0522136SRichard Henderson                  */
4227d62816f2SRichard Henderson                 temp_load(s, ts, tcg_target_available_regs[ts->type],
4228d62816f2SRichard Henderson                           i_allocated_regs, 0);
422929f5e925SRichard Henderson                 reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs,
42301c1824dcSRichard Henderson                                     i_preferred_regs, ts->indirect_base);
423129f5e925SRichard Henderson                 copyto_new_reg = true;
423229f5e925SRichard Henderson             }
423329f5e925SRichard Henderson             break;
423429f5e925SRichard Henderson 
423529f5e925SRichard Henderson         case 1:
423629f5e925SRichard Henderson             /* First of an input pair; if i1 == i2, the second is an output. */
423729f5e925SRichard Henderson             i1 = i;
423829f5e925SRichard Henderson             i2 = arg_ct->pair_index;
423929f5e925SRichard Henderson             ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL;
424029f5e925SRichard Henderson 
424129f5e925SRichard Henderson             /*
424229f5e925SRichard Henderson              * It is easier to default to allocating a new pair
424329f5e925SRichard Henderson              * and to identify a few cases where it's not required.
424429f5e925SRichard Henderson              */
424529f5e925SRichard Henderson             if (arg_ct->ialias) {
424631fd884bSRichard Henderson                 i_preferred_regs = output_pref(op, arg_ct->alias_index);
424729f5e925SRichard Henderson                 if (IS_DEAD_ARG(i1) &&
424829f5e925SRichard Henderson                     IS_DEAD_ARG(i2) &&
424929f5e925SRichard Henderson                     !temp_readonly(ts) &&
425029f5e925SRichard Henderson                     ts->val_type == TEMP_VAL_REG &&
425129f5e925SRichard Henderson                     ts->reg < TCG_TARGET_NB_REGS - 1 &&
425229f5e925SRichard Henderson                     tcg_regset_test_reg(i_required_regs, reg) &&
425329f5e925SRichard Henderson                     !tcg_regset_test_reg(i_allocated_regs, reg) &&
425429f5e925SRichard Henderson                     !tcg_regset_test_reg(i_allocated_regs, reg + 1) &&
425529f5e925SRichard Henderson                     (ts2
425629f5e925SRichard Henderson                      ? ts2->val_type == TEMP_VAL_REG &&
425729f5e925SRichard Henderson                        ts2->reg == reg + 1 &&
425829f5e925SRichard Henderson                        !temp_readonly(ts2)
425929f5e925SRichard Henderson                      : s->reg_to_temp[reg + 1] == NULL)) {
426029f5e925SRichard Henderson                     break;
426129f5e925SRichard Henderson                 }
426229f5e925SRichard Henderson             } else {
426329f5e925SRichard Henderson                 /* Without aliasing, the pair must also be an input. */
426429f5e925SRichard Henderson                 tcg_debug_assert(ts2);
426529f5e925SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG &&
426629f5e925SRichard Henderson                     ts2->val_type == TEMP_VAL_REG &&
426729f5e925SRichard Henderson                     ts2->reg == reg + 1 &&
426829f5e925SRichard Henderson                     tcg_regset_test_reg(i_required_regs, reg)) {
426929f5e925SRichard Henderson                     break;
427029f5e925SRichard Henderson                 }
427129f5e925SRichard Henderson             }
427229f5e925SRichard Henderson             reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs,
427329f5e925SRichard Henderson                                      0, ts->indirect_base);
427429f5e925SRichard Henderson             goto do_pair;
427529f5e925SRichard Henderson 
427629f5e925SRichard Henderson         case 2: /* pair second */
427729f5e925SRichard Henderson             reg = new_args[arg_ct->pair_index] + 1;
427829f5e925SRichard Henderson             goto do_pair;
427929f5e925SRichard Henderson 
428029f5e925SRichard Henderson         case 3: /* ialias with second output, no first input */
428129f5e925SRichard Henderson             tcg_debug_assert(arg_ct->ialias);
428231fd884bSRichard Henderson             i_preferred_regs = output_pref(op, arg_ct->alias_index);
428329f5e925SRichard Henderson 
428429f5e925SRichard Henderson             if (IS_DEAD_ARG(i) &&
428529f5e925SRichard Henderson                 !temp_readonly(ts) &&
428629f5e925SRichard Henderson                 ts->val_type == TEMP_VAL_REG &&
428729f5e925SRichard Henderson                 reg > 0 &&
428829f5e925SRichard Henderson                 s->reg_to_temp[reg - 1] == NULL &&
428929f5e925SRichard Henderson                 tcg_regset_test_reg(i_required_regs, reg) &&
429029f5e925SRichard Henderson                 !tcg_regset_test_reg(i_allocated_regs, reg) &&
429129f5e925SRichard Henderson                 !tcg_regset_test_reg(i_allocated_regs, reg - 1)) {
429229f5e925SRichard Henderson                 tcg_regset_set_reg(i_allocated_regs, reg - 1);
429329f5e925SRichard Henderson                 break;
429429f5e925SRichard Henderson             }
429529f5e925SRichard Henderson             reg = tcg_reg_alloc_pair(s, i_required_regs >> 1,
429629f5e925SRichard Henderson                                      i_allocated_regs, 0,
429729f5e925SRichard Henderson                                      ts->indirect_base);
429829f5e925SRichard Henderson             tcg_regset_set_reg(i_allocated_regs, reg);
429929f5e925SRichard Henderson             reg += 1;
430029f5e925SRichard Henderson             goto do_pair;
430129f5e925SRichard Henderson 
430229f5e925SRichard Henderson         do_pair:
430329f5e925SRichard Henderson             /*
430429f5e925SRichard Henderson              * If an aliased input is not dead after the instruction,
430529f5e925SRichard Henderson              * we must allocate a new register and move it.
430629f5e925SRichard Henderson              */
430729f5e925SRichard Henderson             if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) {
430829f5e925SRichard Henderson                 TCGRegSet t_allocated_regs = i_allocated_regs;
430929f5e925SRichard Henderson 
431029f5e925SRichard Henderson                 /*
431129f5e925SRichard Henderson                  * Because of the alias, and the continued life, make sure
431229f5e925SRichard Henderson                  * that the temp is somewhere *other* than the reg pair,
431329f5e925SRichard Henderson                  * and we get a copy in reg.
431429f5e925SRichard Henderson                  */
431529f5e925SRichard Henderson                 tcg_regset_set_reg(t_allocated_regs, reg);
431629f5e925SRichard Henderson                 tcg_regset_set_reg(t_allocated_regs, reg + 1);
431729f5e925SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) {
431829f5e925SRichard Henderson                     /* If ts was already in reg, copy it somewhere else. */
431929f5e925SRichard Henderson                     TCGReg nr;
432029f5e925SRichard Henderson                     bool ok;
432129f5e925SRichard Henderson 
432229f5e925SRichard Henderson                     tcg_debug_assert(ts->kind != TEMP_FIXED);
432329f5e925SRichard Henderson                     nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
432429f5e925SRichard Henderson                                        t_allocated_regs, 0, ts->indirect_base);
432529f5e925SRichard Henderson                     ok = tcg_out_mov(s, ts->type, nr, reg);
432629f5e925SRichard Henderson                     tcg_debug_assert(ok);
432729f5e925SRichard Henderson 
432829f5e925SRichard Henderson                     set_temp_val_reg(s, ts, nr);
432929f5e925SRichard Henderson                 } else {
433029f5e925SRichard Henderson                     temp_load(s, ts, tcg_target_available_regs[ts->type],
433129f5e925SRichard Henderson                               t_allocated_regs, 0);
433229f5e925SRichard Henderson                     copyto_new_reg = true;
433329f5e925SRichard Henderson                 }
433429f5e925SRichard Henderson             } else {
433529f5e925SRichard Henderson                 /* Preferably allocate to reg, otherwise copy. */
433629f5e925SRichard Henderson                 i_required_regs = (TCGRegSet)1 << reg;
433729f5e925SRichard Henderson                 temp_load(s, ts, i_required_regs, i_allocated_regs,
433829f5e925SRichard Henderson                           i_preferred_regs);
433929f5e925SRichard Henderson                 copyto_new_reg = ts->reg != reg;
434029f5e925SRichard Henderson             }
434129f5e925SRichard Henderson             break;
434229f5e925SRichard Henderson 
434329f5e925SRichard Henderson         default:
434429f5e925SRichard Henderson             g_assert_not_reached();
434529f5e925SRichard Henderson         }
434629f5e925SRichard Henderson 
434729f5e925SRichard Henderson         if (copyto_new_reg) {
434878113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4349240c08d0SRichard Henderson                 /*
4350240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
4351240c08d0SRichard Henderson                  * temp back to its slot and load from there.
4352240c08d0SRichard Henderson                  */
4353240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
4354240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
4355240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
435678113e83SRichard Henderson             }
4357c896fe29Sbellard         }
4358c896fe29Sbellard         new_args[i] = reg;
4359c896fe29Sbellard         const_args[i] = 0;
436082790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
4361c896fe29Sbellard     }
4362c896fe29Sbellard 
4363c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
4364866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
4365866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
436643439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4367c896fe29Sbellard         }
4368c896fe29Sbellard     }
4369c896fe29Sbellard 
4370b4cb76e6SRichard Henderson     if (def->flags & TCG_OPF_COND_BRANCH) {
4371b4cb76e6SRichard Henderson         tcg_reg_alloc_cbranch(s, i_allocated_regs);
4372b4cb76e6SRichard Henderson     } else if (def->flags & TCG_OPF_BB_END) {
437382790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
4374a52ad07eSAurelien Jarno     } else {
4375c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
4376b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
4377c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4378c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
437982790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
4380c896fe29Sbellard                 }
4381c896fe29Sbellard             }
43823d5c5f87SAurelien Jarno         }
43833d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
43843d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
43853d5c5f87SAurelien Jarno                an exception. */
438682790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
4387c896fe29Sbellard         }
4388c896fe29Sbellard 
4389c896fe29Sbellard         /* satisfy the output constraints */
4390c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
439166792f90SRichard Henderson             i = def->args_ct[k].sort_index;
4392dd186292SRichard Henderson             arg = op->args[i];
4393c896fe29Sbellard             arg_ct = &def->args_ct[i];
439443439139SRichard Henderson             ts = arg_temp(arg);
4395d63e3b6eSRichard Henderson 
4396d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
4397e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
4398d63e3b6eSRichard Henderson 
439929f5e925SRichard Henderson             switch (arg_ct->pair) {
440029f5e925SRichard Henderson             case 0: /* not paired */
4401bc2b17e6SRichard Henderson                 if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
44025ff9d6a4Sbellard                     reg = new_args[arg_ct->alias_index];
4403bc2b17e6SRichard Henderson                 } else if (arg_ct->newreg) {
44049be0d080SRichard Henderson                     reg = tcg_reg_alloc(s, arg_ct->regs,
440582790a87SRichard Henderson                                         i_allocated_regs | o_allocated_regs,
440631fd884bSRichard Henderson                                         output_pref(op, k), ts->indirect_base);
4407c896fe29Sbellard                 } else {
44089be0d080SRichard Henderson                     reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
440931fd884bSRichard Henderson                                         output_pref(op, k), ts->indirect_base);
4410c896fe29Sbellard                 }
441129f5e925SRichard Henderson                 break;
441229f5e925SRichard Henderson 
441329f5e925SRichard Henderson             case 1: /* first of pair */
441429f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
441529f5e925SRichard Henderson                 if (arg_ct->oalias) {
441629f5e925SRichard Henderson                     reg = new_args[arg_ct->alias_index];
441729f5e925SRichard Henderson                     break;
441829f5e925SRichard Henderson                 }
441929f5e925SRichard Henderson                 reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs,
442031fd884bSRichard Henderson                                          output_pref(op, k), ts->indirect_base);
442129f5e925SRichard Henderson                 break;
442229f5e925SRichard Henderson 
442329f5e925SRichard Henderson             case 2: /* second of pair */
442429f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
442529f5e925SRichard Henderson                 if (arg_ct->oalias) {
442629f5e925SRichard Henderson                     reg = new_args[arg_ct->alias_index];
442729f5e925SRichard Henderson                 } else {
442829f5e925SRichard Henderson                     reg = new_args[arg_ct->pair_index] + 1;
442929f5e925SRichard Henderson                 }
443029f5e925SRichard Henderson                 break;
443129f5e925SRichard Henderson 
443229f5e925SRichard Henderson             case 3: /* first of pair, aliasing with a second input */
443329f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
443429f5e925SRichard Henderson                 reg = new_args[arg_ct->pair_index] - 1;
443529f5e925SRichard Henderson                 break;
443629f5e925SRichard Henderson 
443729f5e925SRichard Henderson             default:
443829f5e925SRichard Henderson                 g_assert_not_reached();
443929f5e925SRichard Henderson             }
444082790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
4441098859f1SRichard Henderson             set_temp_val_reg(s, ts, reg);
4442c896fe29Sbellard             ts->mem_coherent = 0;
4443c896fe29Sbellard             new_args[i] = reg;
4444c896fe29Sbellard         }
4445e8996ee0Sbellard     }
4446c896fe29Sbellard 
4447c896fe29Sbellard     /* emit instruction */
4448d2fd745fSRichard Henderson     if (def->flags & TCG_OPF_VECTOR) {
4449d2fd745fSRichard Henderson         tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
4450d2fd745fSRichard Henderson                        new_args, const_args);
4451d2fd745fSRichard Henderson     } else {
4452dd186292SRichard Henderson         tcg_out_op(s, op->opc, new_args, const_args);
4453d2fd745fSRichard Henderson     }
4454c896fe29Sbellard 
4455c896fe29Sbellard     /* move the outputs in the correct register if needed */
4456c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
445743439139SRichard Henderson         ts = arg_temp(op->args[i]);
4458d63e3b6eSRichard Henderson 
4459d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
4460e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
4461d63e3b6eSRichard Henderson 
4462ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
446398b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
446459d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4465f8bf00f1SRichard Henderson             temp_dead(s, ts);
4466ec7a869dSAurelien Jarno         }
4467c896fe29Sbellard     }
4468c896fe29Sbellard }
4469c896fe29Sbellard 
4470efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op)
4471efe86b21SRichard Henderson {
4472efe86b21SRichard Henderson     const TCGLifeData arg_life = op->life;
4473efe86b21SRichard Henderson     TCGTemp *ots, *itsl, *itsh;
4474efe86b21SRichard Henderson     TCGType vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
4475efe86b21SRichard Henderson 
4476efe86b21SRichard Henderson     /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */
4477efe86b21SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 32);
4478efe86b21SRichard Henderson     tcg_debug_assert(TCGOP_VECE(op) == MO_64);
4479efe86b21SRichard Henderson 
4480efe86b21SRichard Henderson     ots = arg_temp(op->args[0]);
4481efe86b21SRichard Henderson     itsl = arg_temp(op->args[1]);
4482efe86b21SRichard Henderson     itsh = arg_temp(op->args[2]);
4483efe86b21SRichard Henderson 
4484efe86b21SRichard Henderson     /* ENV should not be modified.  */
4485efe86b21SRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4486efe86b21SRichard Henderson 
4487efe86b21SRichard Henderson     /* Allocate the output register now.  */
4488efe86b21SRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
4489efe86b21SRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
4490efe86b21SRichard Henderson         TCGRegSet dup_out_regs =
4491efe86b21SRichard Henderson             tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
4492098859f1SRichard Henderson         TCGReg oreg;
4493efe86b21SRichard Henderson 
4494efe86b21SRichard Henderson         /* Make sure to not spill the input registers. */
4495efe86b21SRichard Henderson         if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) {
4496efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsl->reg);
4497efe86b21SRichard Henderson         }
4498efe86b21SRichard Henderson         if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) {
4499efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsh->reg);
4500efe86b21SRichard Henderson         }
4501efe86b21SRichard Henderson 
4502098859f1SRichard Henderson         oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
450331fd884bSRichard Henderson                              output_pref(op, 0), ots->indirect_base);
4504098859f1SRichard Henderson         set_temp_val_reg(s, ots, oreg);
4505efe86b21SRichard Henderson     }
4506efe86b21SRichard Henderson 
4507efe86b21SRichard Henderson     /* Promote dup2 of immediates to dupi_vec. */
4508efe86b21SRichard Henderson     if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) {
4509efe86b21SRichard Henderson         uint64_t val = deposit64(itsl->val, 32, 32, itsh->val);
4510efe86b21SRichard Henderson         MemOp vece = MO_64;
4511efe86b21SRichard Henderson 
4512efe86b21SRichard Henderson         if (val == dup_const(MO_8, val)) {
4513efe86b21SRichard Henderson             vece = MO_8;
4514efe86b21SRichard Henderson         } else if (val == dup_const(MO_16, val)) {
4515efe86b21SRichard Henderson             vece = MO_16;
4516efe86b21SRichard Henderson         } else if (val == dup_const(MO_32, val)) {
4517efe86b21SRichard Henderson             vece = MO_32;
4518efe86b21SRichard Henderson         }
4519efe86b21SRichard Henderson 
4520efe86b21SRichard Henderson         tcg_out_dupi_vec(s, vtype, vece, ots->reg, val);
4521efe86b21SRichard Henderson         goto done;
4522efe86b21SRichard Henderson     }
4523efe86b21SRichard Henderson 
4524efe86b21SRichard Henderson     /* If the two inputs form one 64-bit value, try dupm_vec. */
4525aef85402SRichard Henderson     if (itsl->temp_subindex == HOST_BIG_ENDIAN &&
4526aef85402SRichard Henderson         itsh->temp_subindex == !HOST_BIG_ENDIAN &&
4527aef85402SRichard Henderson         itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) {
4528aef85402SRichard Henderson         TCGTemp *its = itsl - HOST_BIG_ENDIAN;
4529aef85402SRichard Henderson 
4530aef85402SRichard Henderson         temp_sync(s, its + 0, s->reserved_regs, 0, 0);
4531aef85402SRichard Henderson         temp_sync(s, its + 1, s->reserved_regs, 0, 0);
4532aef85402SRichard Henderson 
4533efe86b21SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg,
4534efe86b21SRichard Henderson                              its->mem_base->reg, its->mem_offset)) {
4535efe86b21SRichard Henderson             goto done;
4536efe86b21SRichard Henderson         }
4537efe86b21SRichard Henderson     }
4538efe86b21SRichard Henderson 
4539efe86b21SRichard Henderson     /* Fall back to generic expansion. */
4540efe86b21SRichard Henderson     return false;
4541efe86b21SRichard Henderson 
4542efe86b21SRichard Henderson  done:
454336f5539cSRichard Henderson     ots->mem_coherent = 0;
4544efe86b21SRichard Henderson     if (IS_DEAD_ARG(1)) {
4545efe86b21SRichard Henderson         temp_dead(s, itsl);
4546efe86b21SRichard Henderson     }
4547efe86b21SRichard Henderson     if (IS_DEAD_ARG(2)) {
4548efe86b21SRichard Henderson         temp_dead(s, itsh);
4549efe86b21SRichard Henderson     }
4550efe86b21SRichard Henderson     if (NEED_SYNC_ARG(0)) {
4551efe86b21SRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0));
4552efe86b21SRichard Henderson     } else if (IS_DEAD_ARG(0)) {
4553efe86b21SRichard Henderson         temp_dead(s, ots);
4554efe86b21SRichard Henderson     }
4555efe86b21SRichard Henderson     return true;
4556efe86b21SRichard Henderson }
4557efe86b21SRichard Henderson 
455839004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts,
455939004a71SRichard Henderson                          TCGRegSet allocated_regs)
4560c896fe29Sbellard {
4561c896fe29Sbellard     if (ts->val_type == TEMP_VAL_REG) {
4562c896fe29Sbellard         if (ts->reg != reg) {
45634250da10SRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
456478113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4565240c08d0SRichard Henderson                 /*
4566240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
4567240c08d0SRichard Henderson                  * temp back to its slot and load from there.
4568240c08d0SRichard Henderson                  */
4569240c08d0SRichard Henderson                 temp_sync(s, ts, allocated_regs, 0, 0);
4570240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
4571240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
457278113e83SRichard Henderson             }
4573c896fe29Sbellard         }
4574c896fe29Sbellard     } else {
4575ccb1bb66SRichard Henderson         TCGRegSet arg_set = 0;
457640ae5c62SRichard Henderson 
45774250da10SRichard Henderson         tcg_reg_free(s, reg, allocated_regs);
457840ae5c62SRichard Henderson         tcg_regset_set_reg(arg_set, reg);
4579b722452aSRichard Henderson         temp_load(s, ts, arg_set, allocated_regs, 0);
4580c896fe29Sbellard     }
458139004a71SRichard Henderson }
458240ae5c62SRichard Henderson 
458339004a71SRichard Henderson static void load_arg_stk(TCGContext *s, int stk_slot, TCGTemp *ts,
458439004a71SRichard Henderson                          TCGRegSet allocated_regs)
458539004a71SRichard Henderson {
458639004a71SRichard Henderson     /*
458739004a71SRichard Henderson      * When the destination is on the stack, load up the temp and store.
458839004a71SRichard Henderson      * If there are many call-saved registers, the temp might live to
458939004a71SRichard Henderson      * see another use; otherwise it'll be discarded.
459039004a71SRichard Henderson      */
459139004a71SRichard Henderson     temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0);
459239004a71SRichard Henderson     tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK,
459339004a71SRichard Henderson                TCG_TARGET_CALL_STACK_OFFSET +
459439004a71SRichard Henderson                stk_slot * sizeof(tcg_target_long));
459539004a71SRichard Henderson }
459639004a71SRichard Henderson 
459739004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l,
459839004a71SRichard Henderson                             TCGTemp *ts, TCGRegSet *allocated_regs)
459939004a71SRichard Henderson {
460039004a71SRichard Henderson     if (REG_P(l)) {
460139004a71SRichard Henderson         TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot];
460239004a71SRichard Henderson         load_arg_reg(s, reg, ts, *allocated_regs);
460339004a71SRichard Henderson         tcg_regset_set_reg(*allocated_regs, reg);
460439004a71SRichard Henderson     } else {
460539004a71SRichard Henderson         load_arg_stk(s, l->arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs),
460639004a71SRichard Henderson                      ts, *allocated_regs);
4607c896fe29Sbellard     }
460839cf05d3Sbellard }
4609c896fe29Sbellard 
4610313bdea8SRichard Henderson static void load_arg_ref(TCGContext *s, int arg_slot, TCGReg ref_base,
4611313bdea8SRichard Henderson                          intptr_t ref_off, TCGRegSet *allocated_regs)
4612313bdea8SRichard Henderson {
4613313bdea8SRichard Henderson     TCGReg reg;
4614313bdea8SRichard Henderson     int stk_slot = arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs);
4615313bdea8SRichard Henderson 
4616313bdea8SRichard Henderson     if (stk_slot < 0) {
4617313bdea8SRichard Henderson         reg = tcg_target_call_iarg_regs[arg_slot];
4618313bdea8SRichard Henderson         tcg_reg_free(s, reg, *allocated_regs);
4619313bdea8SRichard Henderson         tcg_out_addi_ptr(s, reg, ref_base, ref_off);
4620313bdea8SRichard Henderson         tcg_regset_set_reg(*allocated_regs, reg);
4621313bdea8SRichard Henderson     } else {
4622313bdea8SRichard Henderson         reg = tcg_reg_alloc(s, tcg_target_available_regs[TCG_TYPE_PTR],
4623313bdea8SRichard Henderson                             *allocated_regs, 0, false);
4624313bdea8SRichard Henderson         tcg_out_addi_ptr(s, reg, ref_base, ref_off);
4625313bdea8SRichard Henderson         tcg_out_st(s, TCG_TYPE_PTR, reg, TCG_REG_CALL_STACK,
4626313bdea8SRichard Henderson                    TCG_TARGET_CALL_STACK_OFFSET
4627313bdea8SRichard Henderson                    + stk_slot * sizeof(tcg_target_long));
4628313bdea8SRichard Henderson     }
4629313bdea8SRichard Henderson }
4630313bdea8SRichard Henderson 
463139004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
463239004a71SRichard Henderson {
463339004a71SRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
463439004a71SRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
463539004a71SRichard Henderson     const TCGLifeData arg_life = op->life;
463639004a71SRichard Henderson     const TCGHelperInfo *info = tcg_call_info(op);
463739004a71SRichard Henderson     TCGRegSet allocated_regs = s->reserved_regs;
463839004a71SRichard Henderson     int i;
463939004a71SRichard Henderson 
464039004a71SRichard Henderson     /*
464139004a71SRichard Henderson      * Move inputs into place in reverse order,
464239004a71SRichard Henderson      * so that we place stacked arguments first.
464339004a71SRichard Henderson      */
464439004a71SRichard Henderson     for (i = nb_iargs - 1; i >= 0; --i) {
464539004a71SRichard Henderson         const TCGCallArgumentLoc *loc = &info->in[i];
464639004a71SRichard Henderson         TCGTemp *ts = arg_temp(op->args[nb_oargs + i]);
464739004a71SRichard Henderson 
464839004a71SRichard Henderson         switch (loc->kind) {
464939004a71SRichard Henderson         case TCG_CALL_ARG_NORMAL:
465039004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
465139004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
465239004a71SRichard Henderson             load_arg_normal(s, loc, ts, &allocated_regs);
465339004a71SRichard Henderson             break;
4654313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF:
4655313bdea8SRichard Henderson             load_arg_stk(s, loc->ref_slot, ts, allocated_regs);
4656313bdea8SRichard Henderson             load_arg_ref(s, loc->arg_slot, TCG_REG_CALL_STACK,
4657313bdea8SRichard Henderson                          TCG_TARGET_CALL_STACK_OFFSET
4658313bdea8SRichard Henderson                          + loc->ref_slot * sizeof(tcg_target_long),
4659313bdea8SRichard Henderson                          &allocated_regs);
4660313bdea8SRichard Henderson             break;
4661313bdea8SRichard Henderson         case TCG_CALL_ARG_BY_REF_N:
4662313bdea8SRichard Henderson             load_arg_stk(s, loc->ref_slot, ts, allocated_regs);
4663313bdea8SRichard Henderson             break;
466439004a71SRichard Henderson         default:
466539004a71SRichard Henderson             g_assert_not_reached();
466639004a71SRichard Henderson         }
466739004a71SRichard Henderson     }
466839004a71SRichard Henderson 
466939004a71SRichard Henderson     /* Mark dead temporaries and free the associated registers.  */
4670866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4671866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
467243439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4673c896fe29Sbellard         }
4674c896fe29Sbellard     }
4675c896fe29Sbellard 
467639004a71SRichard Henderson     /* Clobber call registers.  */
4677c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4678c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
4679b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
4680c896fe29Sbellard         }
4681c896fe29Sbellard     }
4682c896fe29Sbellard 
468339004a71SRichard Henderson     /*
468439004a71SRichard Henderson      * Save globals if they might be written by the helper,
468539004a71SRichard Henderson      * sync them if they might be read.
468639004a71SRichard Henderson      */
468739004a71SRichard Henderson     if (info->flags & TCG_CALL_NO_READ_GLOBALS) {
468878505279SAurelien Jarno         /* Nothing to do */
468939004a71SRichard Henderson     } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) {
469078505279SAurelien Jarno         sync_globals(s, allocated_regs);
469178505279SAurelien Jarno     } else {
4692e8996ee0Sbellard         save_globals(s, allocated_regs);
4693b9c18f56Saurel32     }
4694c896fe29Sbellard 
4695313bdea8SRichard Henderson     /*
4696313bdea8SRichard Henderson      * If the ABI passes a pointer to the returned struct as the first
4697313bdea8SRichard Henderson      * argument, load that now.  Pass a pointer to the output home slot.
4698313bdea8SRichard Henderson      */
4699313bdea8SRichard Henderson     if (info->out_kind == TCG_CALL_RET_BY_REF) {
4700313bdea8SRichard Henderson         TCGTemp *ts = arg_temp(op->args[0]);
4701313bdea8SRichard Henderson 
4702313bdea8SRichard Henderson         if (!ts->mem_allocated) {
4703313bdea8SRichard Henderson             temp_allocate_frame(s, ts);
4704313bdea8SRichard Henderson         }
4705313bdea8SRichard Henderson         load_arg_ref(s, 0, ts->mem_base->reg, ts->mem_offset, &allocated_regs);
4706313bdea8SRichard Henderson     }
4707313bdea8SRichard Henderson 
4708cee44b03SRichard Henderson     tcg_out_call(s, tcg_call_func(op), info);
4709c896fe29Sbellard 
471039004a71SRichard Henderson     /* Assign output registers and emit moves if needed.  */
471139004a71SRichard Henderson     switch (info->out_kind) {
471239004a71SRichard Henderson     case TCG_CALL_RET_NORMAL:
4713c896fe29Sbellard         for (i = 0; i < nb_oargs; i++) {
471439004a71SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
47155e3d0c19SRichard Henderson             TCGReg reg = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, i);
4716d63e3b6eSRichard Henderson 
4717d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
4718e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
4719d63e3b6eSRichard Henderson 
4720098859f1SRichard Henderson             set_temp_val_reg(s, ts, reg);
4721c896fe29Sbellard             ts->mem_coherent = 0;
472239004a71SRichard Henderson         }
472339004a71SRichard Henderson         break;
4724313bdea8SRichard Henderson 
4725c6556aa0SRichard Henderson     case TCG_CALL_RET_BY_VEC:
4726c6556aa0SRichard Henderson         {
4727c6556aa0SRichard Henderson             TCGTemp *ts = arg_temp(op->args[0]);
4728c6556aa0SRichard Henderson 
4729c6556aa0SRichard Henderson             tcg_debug_assert(ts->base_type == TCG_TYPE_I128);
4730c6556aa0SRichard Henderson             tcg_debug_assert(ts->temp_subindex == 0);
4731c6556aa0SRichard Henderson             if (!ts->mem_allocated) {
4732c6556aa0SRichard Henderson                 temp_allocate_frame(s, ts);
4733c6556aa0SRichard Henderson             }
4734c6556aa0SRichard Henderson             tcg_out_st(s, TCG_TYPE_V128,
4735c6556aa0SRichard Henderson                        tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0),
4736c6556aa0SRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
4737c6556aa0SRichard Henderson         }
4738c6556aa0SRichard Henderson         /* fall through to mark all parts in memory */
4739c6556aa0SRichard Henderson 
4740313bdea8SRichard Henderson     case TCG_CALL_RET_BY_REF:
4741313bdea8SRichard Henderson         /* The callee has performed a write through the reference. */
4742313bdea8SRichard Henderson         for (i = 0; i < nb_oargs; i++) {
4743313bdea8SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
4744313bdea8SRichard Henderson             ts->val_type = TEMP_VAL_MEM;
4745313bdea8SRichard Henderson         }
4746313bdea8SRichard Henderson         break;
4747313bdea8SRichard Henderson 
474839004a71SRichard Henderson     default:
474939004a71SRichard Henderson         g_assert_not_reached();
475039004a71SRichard Henderson     }
475139004a71SRichard Henderson 
475239004a71SRichard Henderson     /* Flush or discard output registers as needed. */
475339004a71SRichard Henderson     for (i = 0; i < nb_oargs; i++) {
475439004a71SRichard Henderson         TCGTemp *ts = arg_temp(op->args[i]);
4755ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
475639004a71SRichard Henderson             temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i));
475759d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4758f8bf00f1SRichard Henderson             temp_dead(s, ts);
4759c896fe29Sbellard         }
4760c896fe29Sbellard     }
47618c11ad25SAurelien Jarno }
4762c896fe29Sbellard 
4763c896fe29Sbellard #ifdef CONFIG_PROFILER
4764c896fe29Sbellard 
4765c3fac113SEmilio G. Cota /* avoid copy/paste errors */
4766c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field)                       \
4767c3fac113SEmilio G. Cota     do {                                                \
4768d73415a3SStefan Hajnoczi         (to)->field += qatomic_read(&((from)->field));  \
4769c3fac113SEmilio G. Cota     } while (0)
4770c896fe29Sbellard 
4771c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field)                                       \
4772c3fac113SEmilio G. Cota     do {                                                                \
4773d73415a3SStefan Hajnoczi         typeof((from)->field) val__ = qatomic_read(&((from)->field));   \
4774c3fac113SEmilio G. Cota         if (val__ > (to)->field) {                                      \
4775c3fac113SEmilio G. Cota             (to)->field = val__;                                        \
4776c3fac113SEmilio G. Cota         }                                                               \
4777c3fac113SEmilio G. Cota     } while (0)
4778c3fac113SEmilio G. Cota 
4779c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */
4780c3fac113SEmilio G. Cota static inline
4781c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
4782c896fe29Sbellard {
47830e2d61cfSRichard Henderson     unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
4784c3fac113SEmilio G. Cota     unsigned int i;
4785c3fac113SEmilio G. Cota 
47863468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4787d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
47883468b59eSEmilio G. Cota         const TCGProfile *orig = &s->prof;
4789c3fac113SEmilio G. Cota 
4790c3fac113SEmilio G. Cota         if (counters) {
479172fd2efbSEmilio G. Cota             PROF_ADD(prof, orig, cpu_exec_time);
4792c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count1);
4793c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count);
4794c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, op_count);
4795c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, op_count_max);
4796c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, temp_count);
4797c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, temp_count_max);
4798c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, del_op_count);
4799c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_in_len);
4800c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_out_len);
4801c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, search_out_len);
4802c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, interm_time);
4803c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_time);
4804c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, la_time);
4805c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, opt_time);
4806c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_count);
4807c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_time);
4808c3fac113SEmilio G. Cota         }
4809c3fac113SEmilio G. Cota         if (table) {
4810c896fe29Sbellard             int i;
4811d70724ceSzhanghailiang 
481215fc7daaSRichard Henderson             for (i = 0; i < NB_OPS; i++) {
4813c3fac113SEmilio G. Cota                 PROF_ADD(prof, orig, table_op_count[i]);
4814c3fac113SEmilio G. Cota             }
4815c3fac113SEmilio G. Cota         }
4816c3fac113SEmilio G. Cota     }
4817c3fac113SEmilio G. Cota }
4818c3fac113SEmilio G. Cota 
4819c3fac113SEmilio G. Cota #undef PROF_ADD
4820c3fac113SEmilio G. Cota #undef PROF_MAX
4821c3fac113SEmilio G. Cota 
4822c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof)
4823c3fac113SEmilio G. Cota {
4824c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, true, false);
4825c3fac113SEmilio G. Cota }
4826c3fac113SEmilio G. Cota 
4827c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof)
4828c3fac113SEmilio G. Cota {
4829c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, false, true);
4830c3fac113SEmilio G. Cota }
4831c3fac113SEmilio G. Cota 
4832b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf)
4833c3fac113SEmilio G. Cota {
4834c3fac113SEmilio G. Cota     TCGProfile prof = {};
4835c3fac113SEmilio G. Cota     int i;
4836c3fac113SEmilio G. Cota 
4837c3fac113SEmilio G. Cota     tcg_profile_snapshot_table(&prof);
4838c3fac113SEmilio G. Cota     for (i = 0; i < NB_OPS; i++) {
4839b6a7f3e0SDaniel P. Berrangé         g_string_append_printf(buf, "%s %" PRId64 "\n", tcg_op_defs[i].name,
4840c3fac113SEmilio G. Cota                                prof.table_op_count[i]);
4841c896fe29Sbellard     }
4842c896fe29Sbellard }
484372fd2efbSEmilio G. Cota 
484472fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
484572fd2efbSEmilio G. Cota {
48460e2d61cfSRichard Henderson     unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
484772fd2efbSEmilio G. Cota     unsigned int i;
484872fd2efbSEmilio G. Cota     int64_t ret = 0;
484972fd2efbSEmilio G. Cota 
485072fd2efbSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4851d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
485272fd2efbSEmilio G. Cota         const TCGProfile *prof = &s->prof;
485372fd2efbSEmilio G. Cota 
4854d73415a3SStefan Hajnoczi         ret += qatomic_read(&prof->cpu_exec_time);
485572fd2efbSEmilio G. Cota     }
485672fd2efbSEmilio G. Cota     return ret;
485772fd2efbSEmilio G. Cota }
4858246ae24dSMax Filippov #else
4859b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf)
4860246ae24dSMax Filippov {
4861b6a7f3e0SDaniel P. Berrangé     g_string_append_printf(buf, "[TCG profiler not compiled]\n");
4862246ae24dSMax Filippov }
486372fd2efbSEmilio G. Cota 
486472fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
486572fd2efbSEmilio G. Cota {
486672fd2efbSEmilio G. Cota     error_report("%s: TCG profiler not compiled", __func__);
486772fd2efbSEmilio G. Cota     exit(EXIT_FAILURE);
486872fd2efbSEmilio G. Cota }
4869c896fe29Sbellard #endif
4870c896fe29Sbellard 
4871c896fe29Sbellard 
4872fbf59aadSRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start)
4873c896fe29Sbellard {
4874c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER
4875c3fac113SEmilio G. Cota     TCGProfile *prof = &s->prof;
4876c3fac113SEmilio G. Cota #endif
487715fa08f8SRichard Henderson     int i, num_insns;
487815fa08f8SRichard Henderson     TCGOp *op;
4879c896fe29Sbellard 
488004fe6400SRichard Henderson #ifdef CONFIG_PROFILER
488104fe6400SRichard Henderson     {
4882c1f543b7SEmilio G. Cota         int n = 0;
488304fe6400SRichard Henderson 
488415fa08f8SRichard Henderson         QTAILQ_FOREACH(op, &s->ops, link) {
488515fa08f8SRichard Henderson             n++;
488615fa08f8SRichard Henderson         }
4887d73415a3SStefan Hajnoczi         qatomic_set(&prof->op_count, prof->op_count + n);
4888c3fac113SEmilio G. Cota         if (n > prof->op_count_max) {
4889d73415a3SStefan Hajnoczi             qatomic_set(&prof->op_count_max, n);
489004fe6400SRichard Henderson         }
489104fe6400SRichard Henderson 
489204fe6400SRichard Henderson         n = s->nb_temps;
4893d73415a3SStefan Hajnoczi         qatomic_set(&prof->temp_count, prof->temp_count + n);
4894c3fac113SEmilio G. Cota         if (n > prof->temp_count_max) {
4895d73415a3SStefan Hajnoczi             qatomic_set(&prof->temp_count_max, n);
489604fe6400SRichard Henderson         }
489704fe6400SRichard Henderson     }
489804fe6400SRichard Henderson #endif
489904fe6400SRichard Henderson 
4900c896fe29Sbellard #ifdef DEBUG_DISAS
4901d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
4902fbf59aadSRichard Henderson                  && qemu_log_in_addr_range(pc_start))) {
4903c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
490478b54858SRichard Henderson         if (logfile) {
490578b54858SRichard Henderson             fprintf(logfile, "OP:\n");
4906b7a83ff8SRichard Henderson             tcg_dump_ops(s, logfile, false);
490778b54858SRichard Henderson             fprintf(logfile, "\n");
4908fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
4909c896fe29Sbellard         }
491078b54858SRichard Henderson     }
4911c896fe29Sbellard #endif
4912c896fe29Sbellard 
4913bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
4914bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
4915bef16ab4SRichard Henderson     {
4916bef16ab4SRichard Henderson         TCGLabel *l;
4917bef16ab4SRichard Henderson         bool error = false;
4918bef16ab4SRichard Henderson 
4919bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
4920bef16ab4SRichard Henderson             if (unlikely(!l->present) && l->refs) {
4921bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
4922bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
4923bef16ab4SRichard Henderson                 error = true;
4924bef16ab4SRichard Henderson             }
4925bef16ab4SRichard Henderson         }
4926bef16ab4SRichard Henderson         assert(!error);
4927bef16ab4SRichard Henderson     }
4928bef16ab4SRichard Henderson #endif
4929bef16ab4SRichard Henderson 
4930c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
4931d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
4932c5cc28ffSAurelien Jarno #endif
4933c5cc28ffSAurelien Jarno 
49348f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
4935c45cb8bbSRichard Henderson     tcg_optimize(s);
49368f2e8c07SKirill Batuzov #endif
49378f2e8c07SKirill Batuzov 
4938a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4939d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
4940d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time - profile_getclock());
4941a23a9ec6Sbellard #endif
4942c5cc28ffSAurelien Jarno 
4943b4fc67c7SRichard Henderson     reachable_code_pass(s);
4944*874b8574SRichard Henderson     liveness_pass_0(s);
4945b83eabeaSRichard Henderson     liveness_pass_1(s);
49465a18407fSRichard Henderson 
49475a18407fSRichard Henderson     if (s->nb_indirects > 0) {
49485a18407fSRichard Henderson #ifdef DEBUG_DISAS
49495a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
4950fbf59aadSRichard Henderson                      && qemu_log_in_addr_range(pc_start))) {
4951c60f599bSRichard Henderson             FILE *logfile = qemu_log_trylock();
495278b54858SRichard Henderson             if (logfile) {
495378b54858SRichard Henderson                 fprintf(logfile, "OP before indirect lowering:\n");
4954b7a83ff8SRichard Henderson                 tcg_dump_ops(s, logfile, false);
495578b54858SRichard Henderson                 fprintf(logfile, "\n");
4956fc59d2d8SRobert Foley                 qemu_log_unlock(logfile);
49575a18407fSRichard Henderson             }
495878b54858SRichard Henderson         }
49595a18407fSRichard Henderson #endif
49605a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
4961b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
49625a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
4963b83eabeaSRichard Henderson             liveness_pass_1(s);
49645a18407fSRichard Henderson         }
49655a18407fSRichard Henderson     }
4966c5cc28ffSAurelien Jarno 
4967a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4968d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time + profile_getclock());
4969a23a9ec6Sbellard #endif
4970c896fe29Sbellard 
4971c896fe29Sbellard #ifdef DEBUG_DISAS
4972d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
4973fbf59aadSRichard Henderson                  && qemu_log_in_addr_range(pc_start))) {
4974c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
497578b54858SRichard Henderson         if (logfile) {
497678b54858SRichard Henderson             fprintf(logfile, "OP after optimization and liveness analysis:\n");
4977b7a83ff8SRichard Henderson             tcg_dump_ops(s, logfile, true);
497878b54858SRichard Henderson             fprintf(logfile, "\n");
4979fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
4980c896fe29Sbellard         }
498178b54858SRichard Henderson     }
4982c896fe29Sbellard #endif
4983c896fe29Sbellard 
498435abb009SRichard Henderson     /* Initialize goto_tb jump offsets. */
49853a50f424SRichard Henderson     tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID;
49863a50f424SRichard Henderson     tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID;
49879da6079bSRichard Henderson     tb->jmp_insn_offset[0] = TB_JMP_OFFSET_INVALID;
49889da6079bSRichard Henderson     tb->jmp_insn_offset[1] = TB_JMP_OFFSET_INVALID;
498935abb009SRichard Henderson 
4990c896fe29Sbellard     tcg_reg_alloc_start(s);
4991c896fe29Sbellard 
4992db0c51a3SRichard Henderson     /*
4993db0c51a3SRichard Henderson      * Reset the buffer pointers when restarting after overflow.
4994db0c51a3SRichard Henderson      * TODO: Move this into translate-all.c with the rest of the
4995db0c51a3SRichard Henderson      * buffer management.  Having only this done here is confusing.
4996db0c51a3SRichard Henderson      */
4997db0c51a3SRichard Henderson     s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr);
4998db0c51a3SRichard Henderson     s->code_ptr = s->code_buf;
4999c896fe29Sbellard 
5000659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
50016001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
5002659ef5cbSRichard Henderson #endif
500357a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
500457a26946SRichard Henderson     s->pool_labels = NULL;
500557a26946SRichard Henderson #endif
50069ecefc84SRichard Henderson 
5007fca8a500SRichard Henderson     num_insns = -1;
500815fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
5009c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
5010b3db8758Sblueswir1 
5011c896fe29Sbellard #ifdef CONFIG_PROFILER
5012d73415a3SStefan Hajnoczi         qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
5013c896fe29Sbellard #endif
5014c45cb8bbSRichard Henderson 
5015c896fe29Sbellard         switch (opc) {
5016c896fe29Sbellard         case INDEX_op_mov_i32:
5017c896fe29Sbellard         case INDEX_op_mov_i64:
5018d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
5019dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
5020c896fe29Sbellard             break;
5021bab1671fSRichard Henderson         case INDEX_op_dup_vec:
5022bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
5023bab1671fSRichard Henderson             break;
5024765b842aSRichard Henderson         case INDEX_op_insn_start:
5025fca8a500SRichard Henderson             if (num_insns >= 0) {
50269f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
50279f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
50289f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
50299f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
5030fca8a500SRichard Henderson             }
5031fca8a500SRichard Henderson             num_insns++;
5032bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
5033bad729e2SRichard Henderson                 target_ulong a;
5034bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
5035efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
5036bad729e2SRichard Henderson #else
5037efee3746SRichard Henderson                 a = op->args[i];
5038bad729e2SRichard Henderson #endif
5039fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
5040bad729e2SRichard Henderson             }
5041c896fe29Sbellard             break;
50425ff9d6a4Sbellard         case INDEX_op_discard:
504343439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
50445ff9d6a4Sbellard             break;
5045c896fe29Sbellard         case INDEX_op_set_label:
5046e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
504792ab8e7dSRichard Henderson             tcg_out_label(s, arg_label(op->args[0]));
5048c896fe29Sbellard             break;
5049c896fe29Sbellard         case INDEX_op_call:
5050dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
5051c45cb8bbSRichard Henderson             break;
5052b55a8d9dSRichard Henderson         case INDEX_op_exit_tb:
5053b55a8d9dSRichard Henderson             tcg_out_exit_tb(s, op->args[0]);
5054b55a8d9dSRichard Henderson             break;
5055cf7d6b8eSRichard Henderson         case INDEX_op_goto_tb:
5056cf7d6b8eSRichard Henderson             tcg_out_goto_tb(s, op->args[0]);
5057cf7d6b8eSRichard Henderson             break;
5058efe86b21SRichard Henderson         case INDEX_op_dup2_vec:
5059efe86b21SRichard Henderson             if (tcg_reg_alloc_dup2(s, op)) {
5060efe86b21SRichard Henderson                 break;
5061efe86b21SRichard Henderson             }
5062efe86b21SRichard Henderson             /* fall through */
5063c896fe29Sbellard         default:
506425c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
5065be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
5066c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
5067c896fe29Sbellard                faster to have specialized register allocator functions for
5068c896fe29Sbellard                some common argument patterns */
5069dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
5070c896fe29Sbellard             break;
5071c896fe29Sbellard         }
5072b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
5073b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
5074b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
5075b125f9dcSRichard Henderson            generating code without having to check during generation.  */
5076644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
5077b125f9dcSRichard Henderson             return -1;
5078b125f9dcSRichard Henderson         }
50796e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
50806e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
50816e6c4efeSRichard Henderson             return -2;
50826e6c4efeSRichard Henderson         }
5083c896fe29Sbellard     }
5084fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
5085fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
5086c45cb8bbSRichard Henderson 
5087b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
5088659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
5089aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
5090aeee05f5SRichard Henderson     if (i < 0) {
5091aeee05f5SRichard Henderson         return i;
509223dceda6SRichard Henderson     }
5093659ef5cbSRichard Henderson #endif
509457a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
50951768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
50961768987bSRichard Henderson     if (i < 0) {
50971768987bSRichard Henderson         return i;
509857a26946SRichard Henderson     }
509957a26946SRichard Henderson #endif
51007ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
51017ecd02a0SRichard Henderson         return -2;
51027ecd02a0SRichard Henderson     }
5103c896fe29Sbellard 
5104df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
5105c896fe29Sbellard     /* flush instruction cache */
5106db0c51a3SRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
5107db0c51a3SRichard Henderson                         (uintptr_t)s->code_buf,
51081da8de39SRichard Henderson                         tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
5109df5d2b16SRichard Henderson #endif
51102aeabc08SStefan Weil 
51111813e175SRichard Henderson     return tcg_current_code_size(s);
5112c896fe29Sbellard }
5113c896fe29Sbellard 
5114a23a9ec6Sbellard #ifdef CONFIG_PROFILER
51153a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf)
5116a23a9ec6Sbellard {
5117c3fac113SEmilio G. Cota     TCGProfile prof = {};
5118c3fac113SEmilio G. Cota     const TCGProfile *s;
5119c3fac113SEmilio G. Cota     int64_t tb_count;
5120c3fac113SEmilio G. Cota     int64_t tb_div_count;
5121c3fac113SEmilio G. Cota     int64_t tot;
5122c3fac113SEmilio G. Cota 
5123c3fac113SEmilio G. Cota     tcg_profile_snapshot_counters(&prof);
5124c3fac113SEmilio G. Cota     s = &prof;
5125c3fac113SEmilio G. Cota     tb_count = s->tb_count;
5126c3fac113SEmilio G. Cota     tb_div_count = tb_count ? tb_count : 1;
5127c3fac113SEmilio G. Cota     tot = s->interm_time + s->code_time;
5128a23a9ec6Sbellard 
51293a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "JIT cycles          %" PRId64
51303a841ab5SDaniel P. Berrangé                            " (%0.3f s at 2.4 GHz)\n",
5131a23a9ec6Sbellard                            tot, tot / 2.4e9);
51323a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "translated TBs      %" PRId64
51333a841ab5SDaniel P. Berrangé                            " (aborted=%" PRId64 " %0.1f%%)\n",
5134fca8a500SRichard Henderson                            tb_count, s->tb_count1 - tb_count,
5135fca8a500SRichard Henderson                            (double)(s->tb_count1 - s->tb_count)
5136fca8a500SRichard Henderson                            / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
51373a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg ops/TB          %0.1f max=%d\n",
5138fca8a500SRichard Henderson                            (double)s->op_count / tb_div_count, s->op_count_max);
51393a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "deleted ops/TB      %0.2f\n",
5140fca8a500SRichard Henderson                            (double)s->del_op_count / tb_div_count);
51413a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg temps/TB        %0.2f max=%d\n",
51423a841ab5SDaniel P. Berrangé                            (double)s->temp_count / tb_div_count,
51433a841ab5SDaniel P. Berrangé                            s->temp_count_max);
51443a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg host code/TB    %0.1f\n",
5145fca8a500SRichard Henderson                            (double)s->code_out_len / tb_div_count);
51463a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg search data/TB  %0.1f\n",
5147fca8a500SRichard Henderson                            (double)s->search_out_len / tb_div_count);
5148a23a9ec6Sbellard 
51493a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/op           %0.1f\n",
5150a23a9ec6Sbellard                            s->op_count ? (double)tot / s->op_count : 0);
51513a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/in byte      %0.1f\n",
5152a23a9ec6Sbellard                            s->code_in_len ? (double)tot / s->code_in_len : 0);
51533a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/out byte     %0.1f\n",
5154a23a9ec6Sbellard                            s->code_out_len ? (double)tot / s->code_out_len : 0);
51553a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/search byte     %0.1f\n",
51563a841ab5SDaniel P. Berrangé                            s->search_out_len ?
51573a841ab5SDaniel P. Berrangé                            (double)tot / s->search_out_len : 0);
5158fca8a500SRichard Henderson     if (tot == 0) {
5159a23a9ec6Sbellard         tot = 1;
5160fca8a500SRichard Henderson     }
51613a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "  gen_interm time   %0.1f%%\n",
5162a23a9ec6Sbellard                            (double)s->interm_time / tot * 100.0);
51633a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "  gen_code time     %0.1f%%\n",
5164a23a9ec6Sbellard                            (double)s->code_time / tot * 100.0);
51653a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "optim./code time    %0.1f%%\n",
51663a841ab5SDaniel P. Berrangé                            (double)s->opt_time / (s->code_time ?
51673a841ab5SDaniel P. Berrangé                                                   s->code_time : 1)
5168c5cc28ffSAurelien Jarno                            * 100.0);
51693a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "liveness/code time  %0.1f%%\n",
51703a841ab5SDaniel P. Berrangé                            (double)s->la_time / (s->code_time ?
51713a841ab5SDaniel P. Berrangé                                                  s->code_time : 1) * 100.0);
51723a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cpu_restore count   %" PRId64 "\n",
5173a23a9ec6Sbellard                            s->restore_count);
51743a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "  avg cycles        %0.1f\n",
51753a841ab5SDaniel P. Berrangé                            s->restore_count ?
51763a841ab5SDaniel P. Berrangé                            (double)s->restore_time / s->restore_count : 0);
5177a23a9ec6Sbellard }
5178a23a9ec6Sbellard #else
51793a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf)
5180a23a9ec6Sbellard {
51813a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "[TCG profiler not compiled]\n");
5182a23a9ec6Sbellard }
5183a23a9ec6Sbellard #endif
5184813da627SRichard Henderson 
5185813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
51865872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
51875872bbf2SRichard Henderson 
51885872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
51895872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
51905872bbf2SRichard Henderson 
51915872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
51925872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
51935872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
51945872bbf2SRichard Henderson 
51955872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
51965872bbf2SRichard Henderson */
5197813da627SRichard Henderson 
5198813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
5199813da627SRichard Henderson typedef enum {
5200813da627SRichard Henderson     JIT_NOACTION = 0,
5201813da627SRichard Henderson     JIT_REGISTER_FN,
5202813da627SRichard Henderson     JIT_UNREGISTER_FN
5203813da627SRichard Henderson } jit_actions_t;
5204813da627SRichard Henderson 
5205813da627SRichard Henderson struct jit_code_entry {
5206813da627SRichard Henderson     struct jit_code_entry *next_entry;
5207813da627SRichard Henderson     struct jit_code_entry *prev_entry;
5208813da627SRichard Henderson     const void *symfile_addr;
5209813da627SRichard Henderson     uint64_t symfile_size;
5210813da627SRichard Henderson };
5211813da627SRichard Henderson 
5212813da627SRichard Henderson struct jit_descriptor {
5213813da627SRichard Henderson     uint32_t version;
5214813da627SRichard Henderson     uint32_t action_flag;
5215813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
5216813da627SRichard Henderson     struct jit_code_entry *first_entry;
5217813da627SRichard Henderson };
5218813da627SRichard Henderson 
5219813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
5220813da627SRichard Henderson void __jit_debug_register_code(void)
5221813da627SRichard Henderson {
5222813da627SRichard Henderson     asm("");
5223813da627SRichard Henderson }
5224813da627SRichard Henderson 
5225813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
5226813da627SRichard Henderson    the version before we can set it.  */
5227813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
5228813da627SRichard Henderson 
5229813da627SRichard Henderson /* End GDB interface.  */
5230813da627SRichard Henderson 
5231813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
5232813da627SRichard Henderson {
5233813da627SRichard Henderson     const char *p = strtab + 1;
5234813da627SRichard Henderson 
5235813da627SRichard Henderson     while (1) {
5236813da627SRichard Henderson         if (strcmp(p, str) == 0) {
5237813da627SRichard Henderson             return p - strtab;
5238813da627SRichard Henderson         }
5239813da627SRichard Henderson         p += strlen(p) + 1;
5240813da627SRichard Henderson     }
5241813da627SRichard Henderson }
5242813da627SRichard Henderson 
5243755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size,
52442c90784aSRichard Henderson                                  const void *debug_frame,
52452c90784aSRichard Henderson                                  size_t debug_frame_size)
5246813da627SRichard Henderson {
52475872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
52485872bbf2SRichard Henderson         uint32_t  len;
52495872bbf2SRichard Henderson         uint16_t  version;
52505872bbf2SRichard Henderson         uint32_t  abbrev;
52515872bbf2SRichard Henderson         uint8_t   ptr_size;
52525872bbf2SRichard Henderson         uint8_t   cu_die;
52535872bbf2SRichard Henderson         uint16_t  cu_lang;
52545872bbf2SRichard Henderson         uintptr_t cu_low_pc;
52555872bbf2SRichard Henderson         uintptr_t cu_high_pc;
52565872bbf2SRichard Henderson         uint8_t   fn_die;
52575872bbf2SRichard Henderson         char      fn_name[16];
52585872bbf2SRichard Henderson         uintptr_t fn_low_pc;
52595872bbf2SRichard Henderson         uintptr_t fn_high_pc;
52605872bbf2SRichard Henderson         uint8_t   cu_eoc;
52615872bbf2SRichard Henderson     };
5262813da627SRichard Henderson 
5263813da627SRichard Henderson     struct ElfImage {
5264813da627SRichard Henderson         ElfW(Ehdr) ehdr;
5265813da627SRichard Henderson         ElfW(Phdr) phdr;
52665872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
52675872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
52685872bbf2SRichard Henderson         struct DebugInfo di;
52695872bbf2SRichard Henderson         uint8_t    da[24];
52705872bbf2SRichard Henderson         char       str[80];
52715872bbf2SRichard Henderson     };
52725872bbf2SRichard Henderson 
52735872bbf2SRichard Henderson     struct ElfImage *img;
52745872bbf2SRichard Henderson 
52755872bbf2SRichard Henderson     static const struct ElfImage img_template = {
52765872bbf2SRichard Henderson         .ehdr = {
52775872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
52785872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
52795872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
52805872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
52815872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
52825872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
52835872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
52845872bbf2SRichard Henderson             .e_type = ET_EXEC,
52855872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
52865872bbf2SRichard Henderson             .e_version = EV_CURRENT,
52875872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
52885872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
52895872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
52905872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
52915872bbf2SRichard Henderson             .e_phnum = 1,
52925872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
52935872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
52945872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
5295abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
5296abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
5297abbb3eaeSRichard Henderson #endif
5298abbb3eaeSRichard Henderson #ifdef ELF_OSABI
5299abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
5300abbb3eaeSRichard Henderson #endif
53015872bbf2SRichard Henderson         },
53025872bbf2SRichard Henderson         .phdr = {
53035872bbf2SRichard Henderson             .p_type = PT_LOAD,
53045872bbf2SRichard Henderson             .p_flags = PF_X,
53055872bbf2SRichard Henderson         },
53065872bbf2SRichard Henderson         .shdr = {
53075872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
53085872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
53095872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
53105872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
53115872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
53125872bbf2SRichard Henderson             [1] = { /* .text */
53135872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
53145872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
53155872bbf2SRichard Henderson             },
53165872bbf2SRichard Henderson             [2] = { /* .debug_info */
53175872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
53185872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
53195872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
53205872bbf2SRichard Henderson             },
53215872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
53225872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
53235872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
53245872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
53255872bbf2SRichard Henderson             },
53265872bbf2SRichard Henderson             [4] = { /* .debug_frame */
53275872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
53285872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
53295872bbf2SRichard Henderson             },
53305872bbf2SRichard Henderson             [5] = { /* .symtab */
53315872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
53325872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
53335872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
53345872bbf2SRichard Henderson                 .sh_info = 1,
53355872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
53365872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
53375872bbf2SRichard Henderson             },
53385872bbf2SRichard Henderson             [6] = { /* .strtab */
53395872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
53405872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
53415872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
53425872bbf2SRichard Henderson             }
53435872bbf2SRichard Henderson         },
53445872bbf2SRichard Henderson         .sym = {
53455872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
53465872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
53475872bbf2SRichard Henderson                 .st_shndx = 1,
53485872bbf2SRichard Henderson             }
53495872bbf2SRichard Henderson         },
53505872bbf2SRichard Henderson         .di = {
53515872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
53525872bbf2SRichard Henderson             .version = 2,
53535872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
53545872bbf2SRichard Henderson             .cu_die = 1,
53555872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
53565872bbf2SRichard Henderson             .fn_die = 2,
53575872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
53585872bbf2SRichard Henderson         },
53595872bbf2SRichard Henderson         .da = {
53605872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
53615872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
53625872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
53635872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
53645872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
53655872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
53665872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
53675872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
53685872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
53695872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
53705872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
53715872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
53725872bbf2SRichard Henderson             0           /* no more abbrev */
53735872bbf2SRichard Henderson         },
53745872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
53755872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
5376813da627SRichard Henderson     };
5377813da627SRichard Henderson 
5378813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
5379813da627SRichard Henderson     static struct jit_code_entry one_entry;
5380813da627SRichard Henderson 
53815872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
5382813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
53832c90784aSRichard Henderson     DebugFrameHeader *dfh;
5384813da627SRichard Henderson 
53855872bbf2SRichard Henderson     img = g_malloc(img_size);
53865872bbf2SRichard Henderson     *img = img_template;
5387813da627SRichard Henderson 
53885872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
53895872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
53905872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
5391813da627SRichard Henderson 
53925872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
53935872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
53945872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
5395813da627SRichard Henderson 
53965872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
53975872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
53985872bbf2SRichard Henderson 
53995872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
54005872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
54015872bbf2SRichard Henderson 
54025872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
54035872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
54045872bbf2SRichard Henderson 
54055872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
54065872bbf2SRichard Henderson     img->sym[1].st_value = buf;
54075872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
54085872bbf2SRichard Henderson 
54095872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
541045aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
54115872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
541245aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
5413813da627SRichard Henderson 
54142c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
54152c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
54162c90784aSRichard Henderson     dfh->fde.func_start = buf;
54172c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
54182c90784aSRichard Henderson 
5419813da627SRichard Henderson #ifdef DEBUG_JIT
5420813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
5421813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
5422813da627SRichard Henderson     {
5423eb6b2edfSBin Meng         g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir());
5424eb6b2edfSBin Meng         FILE *f = fopen(jit, "w+b");
5425813da627SRichard Henderson         if (f) {
54265872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
5427813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
5428813da627SRichard Henderson             }
5429813da627SRichard Henderson             fclose(f);
5430813da627SRichard Henderson         }
5431813da627SRichard Henderson     }
5432813da627SRichard Henderson #endif
5433813da627SRichard Henderson 
5434813da627SRichard Henderson     one_entry.symfile_addr = img;
5435813da627SRichard Henderson     one_entry.symfile_size = img_size;
5436813da627SRichard Henderson 
5437813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
5438813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
5439813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
5440813da627SRichard Henderson     __jit_debug_register_code();
5441813da627SRichard Henderson }
5442813da627SRichard Henderson #else
54435872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
54445872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
5445813da627SRichard Henderson 
5446755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
54472c90784aSRichard Henderson                                  const void *debug_frame,
54482c90784aSRichard Henderson                                  size_t debug_frame_size)
5449813da627SRichard Henderson {
5450813da627SRichard Henderson }
5451813da627SRichard Henderson 
5452755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size)
5453813da627SRichard Henderson {
5454813da627SRichard Henderson }
5455813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
5456db432672SRichard Henderson 
5457db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
5458db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
5459db432672SRichard Henderson {
5460db432672SRichard Henderson     g_assert_not_reached();
5461db432672SRichard Henderson }
5462db432672SRichard Henderson #endif
5463