xref: /qemu/tcg/tcg.c (revision 7319d83a735004ba24b439491a9d7727dac2ddbe)
1c896fe29Sbellard /*
2c896fe29Sbellard  * Tiny Code Generator for QEMU
3c896fe29Sbellard  *
4c896fe29Sbellard  * Copyright (c) 2008 Fabrice Bellard
5c896fe29Sbellard  *
6c896fe29Sbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
7c896fe29Sbellard  * of this software and associated documentation files (the "Software"), to deal
8c896fe29Sbellard  * in the Software without restriction, including without limitation the rights
9c896fe29Sbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10c896fe29Sbellard  * copies of the Software, and to permit persons to whom the Software is
11c896fe29Sbellard  * furnished to do so, subject to the following conditions:
12c896fe29Sbellard  *
13c896fe29Sbellard  * The above copyright notice and this permission notice shall be included in
14c896fe29Sbellard  * all copies or substantial portions of the Software.
15c896fe29Sbellard  *
16c896fe29Sbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17c896fe29Sbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18c896fe29Sbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19c896fe29Sbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20c896fe29Sbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21c896fe29Sbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22c896fe29Sbellard  * THE SOFTWARE.
23c896fe29Sbellard  */
24c896fe29Sbellard 
25c896fe29Sbellard /* define it to use liveness analysis (better code) */
268f2e8c07SKirill Batuzov #define USE_TCG_OPTIMIZATIONS
27c896fe29Sbellard 
28757e725bSPeter Maydell #include "qemu/osdep.h"
29cca82982Saurel32 
30813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB.  */
31813da627SRichard Henderson #undef DEBUG_JIT
32813da627SRichard Henderson 
3372fd2efbSEmilio G. Cota #include "qemu/error-report.h"
34f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
351de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
36d4c51a0aSMarkus Armbruster #include "qemu/qemu-print.h"
371de7afc9SPaolo Bonzini #include "qemu/timer.h"
38084cfca1SRichard Henderson #include "qemu/cacheflush.h"
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
53813da627SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
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"
615ff7258cSRichard Henderson #include "tcg-internal.h"
62c896fe29Sbellard 
63139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and
64ce151109SPeter Maydell    used here. */
65e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s);
66e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
676ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
682ba7fae2SRichard Henderson                         intptr_t value, intptr_t addend);
69c896fe29Sbellard 
70497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts.  */
71497a22ebSRichard Henderson typedef struct {
72497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
73497a22ebSRichard Henderson     uint32_t id;
74497a22ebSRichard Henderson     uint8_t version;
75497a22ebSRichard Henderson     char augmentation[1];
76497a22ebSRichard Henderson     uint8_t code_align;
77497a22ebSRichard Henderson     uint8_t data_align;
78497a22ebSRichard Henderson     uint8_t return_column;
79497a22ebSRichard Henderson } DebugFrameCIE;
80497a22ebSRichard Henderson 
81497a22ebSRichard Henderson typedef struct QEMU_PACKED {
82497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
83497a22ebSRichard Henderson     uint32_t cie_offset;
84edee2579SRichard Henderson     uintptr_t func_start;
85edee2579SRichard Henderson     uintptr_t func_len;
86497a22ebSRichard Henderson } DebugFrameFDEHeader;
87497a22ebSRichard Henderson 
882c90784aSRichard Henderson typedef struct QEMU_PACKED {
892c90784aSRichard Henderson     DebugFrameCIE cie;
902c90784aSRichard Henderson     DebugFrameFDEHeader fde;
912c90784aSRichard Henderson } DebugFrameHeader;
922c90784aSRichard Henderson 
93755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
942c90784aSRichard Henderson                                  const void *debug_frame,
952c90784aSRichard Henderson                                  size_t debug_frame_size)
96813da627SRichard Henderson     __attribute__((unused));
97813da627SRichard Henderson 
98139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */
992a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
100a05b5b9bSRichard Henderson                        intptr_t arg2);
10178113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
102c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1032a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
1045e8892dbSMiroslav Rezanina static void tcg_out_op(TCGContext *s, TCGOpcode opc,
1055e8892dbSMiroslav Rezanina                        const TCGArg args[TCG_MAX_OP_ARGS],
1065e8892dbSMiroslav Rezanina                        const int const_args[TCG_MAX_OP_ARGS]);
107d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec
108e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
109e7632cfaSRichard Henderson                             TCGReg dst, TCGReg src);
110d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
111d6ecb4a9SRichard Henderson                              TCGReg dst, TCGReg base, intptr_t offset);
1124e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1134e186175SRichard Henderson                              TCGReg dst, int64_t arg);
1145e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1155e8892dbSMiroslav Rezanina                            unsigned vecl, unsigned vece,
1165e8892dbSMiroslav Rezanina                            const TCGArg args[TCG_MAX_OP_ARGS],
1175e8892dbSMiroslav Rezanina                            const int const_args[TCG_MAX_OP_ARGS]);
118d2fd745fSRichard Henderson #else
119e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
120e7632cfaSRichard Henderson                                    TCGReg dst, TCGReg src)
121e7632cfaSRichard Henderson {
122e7632cfaSRichard Henderson     g_assert_not_reached();
123e7632cfaSRichard Henderson }
124d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
125d6ecb4a9SRichard Henderson                                     TCGReg dst, TCGReg base, intptr_t offset)
126d6ecb4a9SRichard Henderson {
127d6ecb4a9SRichard Henderson     g_assert_not_reached();
128d6ecb4a9SRichard Henderson }
1294e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1304e186175SRichard Henderson                                     TCGReg dst, int64_t arg)
131e7632cfaSRichard Henderson {
132e7632cfaSRichard Henderson     g_assert_not_reached();
133e7632cfaSRichard Henderson }
1345e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1355e8892dbSMiroslav Rezanina                                   unsigned vecl, unsigned vece,
1365e8892dbSMiroslav Rezanina                                   const TCGArg args[TCG_MAX_OP_ARGS],
1375e8892dbSMiroslav Rezanina                                   const int const_args[TCG_MAX_OP_ARGS])
138d2fd745fSRichard Henderson {
139d2fd745fSRichard Henderson     g_assert_not_reached();
140d2fd745fSRichard Henderson }
141d2fd745fSRichard Henderson #endif
1422a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
143a05b5b9bSRichard Henderson                        intptr_t arg2);
14459d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
14559d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
1462be7d76bSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target);
147a4fbbd77SRichard Henderson static bool tcg_target_const_match(int64_t val, TCGType type, int ct);
148659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
149aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s);
150659ef5cbSRichard Henderson #endif
151c896fe29Sbellard 
15242eb6dfcSRichard Henderson TCGContext tcg_init_ctx;
15342eb6dfcSRichard Henderson __thread TCGContext *tcg_ctx;
15442eb6dfcSRichard Henderson 
1555ff7258cSRichard Henderson TCGContext **tcg_ctxs;
1560e2d61cfSRichard Henderson unsigned int tcg_cur_ctxs;
1570e2d61cfSRichard Henderson unsigned int tcg_max_ctxs;
1581c2adb95SRichard Henderson TCGv_env cpu_env = 0;
159c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue;
160db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff;
161df2cce29SEmilio G. Cota 
162b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
163b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec;
164b91ccb31SRichard Henderson #endif
165b91ccb31SRichard Henderson 
166d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
167b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
168c896fe29Sbellard 
1691813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
1704196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
171c896fe29Sbellard {
172c896fe29Sbellard     *s->code_ptr++ = v;
173c896fe29Sbellard }
174c896fe29Sbellard 
1754196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
1764196dca6SPeter Maydell                                                       uint8_t v)
1775c53bb81SPeter Maydell {
1781813e175SRichard Henderson     *p = v;
1795c53bb81SPeter Maydell }
1801813e175SRichard Henderson #endif
1815c53bb81SPeter Maydell 
1821813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
1834196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
184c896fe29Sbellard {
1851813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
1861813e175SRichard Henderson         *s->code_ptr++ = v;
1871813e175SRichard Henderson     } else {
1881813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
1894387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
1901813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
1911813e175SRichard Henderson     }
192c896fe29Sbellard }
193c896fe29Sbellard 
1944196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
1954196dca6SPeter Maydell                                                        uint16_t v)
1965c53bb81SPeter Maydell {
1971813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
1981813e175SRichard Henderson         *p = v;
1991813e175SRichard Henderson     } else {
2005c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2015c53bb81SPeter Maydell     }
2021813e175SRichard Henderson }
2031813e175SRichard Henderson #endif
2045c53bb81SPeter Maydell 
2051813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
2064196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
207c896fe29Sbellard {
2081813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2091813e175SRichard Henderson         *s->code_ptr++ = v;
2101813e175SRichard Henderson     } else {
2111813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2124387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2131813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
2141813e175SRichard Henderson     }
215c896fe29Sbellard }
216c896fe29Sbellard 
2174196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
2184196dca6SPeter Maydell                                                        uint32_t v)
2195c53bb81SPeter Maydell {
2201813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2211813e175SRichard Henderson         *p = v;
2221813e175SRichard Henderson     } else {
2235c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2245c53bb81SPeter Maydell     }
2251813e175SRichard Henderson }
2261813e175SRichard Henderson #endif
2275c53bb81SPeter Maydell 
2281813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
2294196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
230ac26eb69SRichard Henderson {
2311813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2321813e175SRichard Henderson         *s->code_ptr++ = v;
2331813e175SRichard Henderson     } else {
2341813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2354387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2361813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
2371813e175SRichard Henderson     }
238ac26eb69SRichard Henderson }
239ac26eb69SRichard Henderson 
2404196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
2414196dca6SPeter Maydell                                                        uint64_t v)
2425c53bb81SPeter Maydell {
2431813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2441813e175SRichard Henderson         *p = v;
2451813e175SRichard Henderson     } else {
2465c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2475c53bb81SPeter Maydell     }
2481813e175SRichard Henderson }
2491813e175SRichard Henderson #endif
2505c53bb81SPeter Maydell 
251c896fe29Sbellard /* label relocation processing */
252c896fe29Sbellard 
2531813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
254bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
255c896fe29Sbellard {
2567ecd02a0SRichard Henderson     TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation));
257c896fe29Sbellard 
258c896fe29Sbellard     r->type = type;
259c896fe29Sbellard     r->ptr = code_ptr;
260c896fe29Sbellard     r->addend = addend;
2617ecd02a0SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
262c896fe29Sbellard }
263c896fe29Sbellard 
26492ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l)
265c896fe29Sbellard {
266eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
267c896fe29Sbellard     l->has_value = 1;
26892ab8e7dSRichard Henderson     l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr);
269c896fe29Sbellard }
270c896fe29Sbellard 
27142a268c2SRichard Henderson TCGLabel *gen_new_label(void)
272c896fe29Sbellard {
273b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
27451e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
275c896fe29Sbellard 
2767ecd02a0SRichard Henderson     memset(l, 0, sizeof(TCGLabel));
2777ecd02a0SRichard Henderson     l->id = s->nb_labels++;
2787ecd02a0SRichard Henderson     QSIMPLEQ_INIT(&l->relocs);
2797ecd02a0SRichard Henderson 
280bef16ab4SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
28142a268c2SRichard Henderson 
28242a268c2SRichard Henderson     return l;
283c896fe29Sbellard }
284c896fe29Sbellard 
2857ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s)
2867ecd02a0SRichard Henderson {
2877ecd02a0SRichard Henderson     TCGLabel *l;
2887ecd02a0SRichard Henderson 
2897ecd02a0SRichard Henderson     QSIMPLEQ_FOREACH(l, &s->labels, next) {
2907ecd02a0SRichard Henderson         TCGRelocation *r;
2917ecd02a0SRichard Henderson         uintptr_t value = l->u.value;
2927ecd02a0SRichard Henderson 
2937ecd02a0SRichard Henderson         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
2947ecd02a0SRichard Henderson             if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
2957ecd02a0SRichard Henderson                 return false;
2967ecd02a0SRichard Henderson             }
2977ecd02a0SRichard Henderson         }
2987ecd02a0SRichard Henderson     }
2997ecd02a0SRichard Henderson     return true;
3007ecd02a0SRichard Henderson }
3017ecd02a0SRichard Henderson 
3029f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3039f754620SRichard Henderson {
304f14bed3fSRichard Henderson     /*
305f14bed3fSRichard Henderson      * We will check for overflow at the end of the opcode loop in
306f14bed3fSRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
307f14bed3fSRichard Henderson      */
308f14bed3fSRichard Henderson     s->tb_jmp_reset_offset[which] = tcg_current_code_size(s);
3099f754620SRichard Henderson }
3109f754620SRichard Henderson 
311db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */
312db6b7d0cSRichard Henderson static void QEMU_NORETURN tcg_raise_tb_overflow(TCGContext *s)
313db6b7d0cSRichard Henderson {
314db6b7d0cSRichard Henderson     siglongjmp(s->jmp_trans, -2);
315db6b7d0cSRichard Henderson }
316db6b7d0cSRichard Henderson 
3174c22e840SRichard Henderson #define C_PFX1(P, A)                    P##A
3184c22e840SRichard Henderson #define C_PFX2(P, A, B)                 P##A##_##B
3194c22e840SRichard Henderson #define C_PFX3(P, A, B, C)              P##A##_##B##_##C
3204c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D)           P##A##_##B##_##C##_##D
3214c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E)        P##A##_##B##_##C##_##D##_##E
3224c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F)     P##A##_##B##_##C##_##D##_##E##_##F
3234c22e840SRichard Henderson 
3244c22e840SRichard Henderson /* Define an enumeration for the various combinations. */
3254c22e840SRichard Henderson 
3264c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1),
3274c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2),
3284c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3),
3294c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4),
3304c22e840SRichard Henderson 
3314c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1),
3324c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2),
3334c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3),
3344c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4),
3354c22e840SRichard Henderson 
3364c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2),
3374c22e840SRichard Henderson 
3384c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1),
3394c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2),
3404c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3),
3414c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4),
3424c22e840SRichard Henderson 
3434c22e840SRichard Henderson typedef enum {
3444c22e840SRichard Henderson #include "tcg-target-con-set.h"
3454c22e840SRichard Henderson } TCGConstraintSetIndex;
3464c22e840SRichard Henderson 
3474c22e840SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode);
3484c22e840SRichard Henderson 
3494c22e840SRichard Henderson #undef C_O0_I1
3504c22e840SRichard Henderson #undef C_O0_I2
3514c22e840SRichard Henderson #undef C_O0_I3
3524c22e840SRichard Henderson #undef C_O0_I4
3534c22e840SRichard Henderson #undef C_O1_I1
3544c22e840SRichard Henderson #undef C_O1_I2
3554c22e840SRichard Henderson #undef C_O1_I3
3564c22e840SRichard Henderson #undef C_O1_I4
3574c22e840SRichard Henderson #undef C_N1_I2
3584c22e840SRichard Henderson #undef C_O2_I1
3594c22e840SRichard Henderson #undef C_O2_I2
3604c22e840SRichard Henderson #undef C_O2_I3
3614c22e840SRichard Henderson #undef C_O2_I4
3624c22e840SRichard Henderson 
3634c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */
3644c22e840SRichard Henderson 
3654c22e840SRichard Henderson #define C_O0_I1(I1)                     { .args_ct_str = { #I1 } },
3664c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 { .args_ct_str = { #I1, #I2 } },
3674c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             { .args_ct_str = { #I1, #I2, #I3 } },
3684c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         { .args_ct_str = { #I1, #I2, #I3, #I4 } },
3694c22e840SRichard Henderson 
3704c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 { .args_ct_str = { #O1, #I1 } },
3714c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             { .args_ct_str = { #O1, #I1, #I2 } },
3724c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         { .args_ct_str = { #O1, #I1, #I2, #I3 } },
3734c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } },
3744c22e840SRichard Henderson 
3754c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             { .args_ct_str = { "&" #O1, #I1, #I2 } },
3764c22e840SRichard Henderson 
3774c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             { .args_ct_str = { #O1, #O2, #I1 } },
3784c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         { .args_ct_str = { #O1, #O2, #I1, #I2 } },
3794c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } },
3804c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } },
3814c22e840SRichard Henderson 
3824c22e840SRichard Henderson static const TCGTargetOpDef constraint_sets[] = {
3834c22e840SRichard Henderson #include "tcg-target-con-set.h"
3844c22e840SRichard Henderson };
3854c22e840SRichard Henderson 
3864c22e840SRichard Henderson 
3874c22e840SRichard Henderson #undef C_O0_I1
3884c22e840SRichard Henderson #undef C_O0_I2
3894c22e840SRichard Henderson #undef C_O0_I3
3904c22e840SRichard Henderson #undef C_O0_I4
3914c22e840SRichard Henderson #undef C_O1_I1
3924c22e840SRichard Henderson #undef C_O1_I2
3934c22e840SRichard Henderson #undef C_O1_I3
3944c22e840SRichard Henderson #undef C_O1_I4
3954c22e840SRichard Henderson #undef C_N1_I2
3964c22e840SRichard Henderson #undef C_O2_I1
3974c22e840SRichard Henderson #undef C_O2_I2
3984c22e840SRichard Henderson #undef C_O2_I3
3994c22e840SRichard Henderson #undef C_O2_I4
4004c22e840SRichard Henderson 
4014c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */
4024c22e840SRichard Henderson 
4034c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1)
4044c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2)
4054c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3)
4064c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4)
4074c22e840SRichard Henderson 
4084c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1)
4094c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2)
4104c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3)
4114c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4)
4124c22e840SRichard Henderson 
4134c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2)
4144c22e840SRichard Henderson 
4154c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1)
4164c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2)
4174c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3)
4184c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4)
4194c22e840SRichard Henderson 
420139c1837SPaolo Bonzini #include "tcg-target.c.inc"
421c896fe29Sbellard 
42238b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s)
42338b47b19SEmilio G. Cota {
42438b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
42538b47b19SEmilio G. Cota     s->plugin_tb = g_new0(struct qemu_plugin_tb, 1);
42638b47b19SEmilio G. Cota     s->plugin_tb->insns =
42738b47b19SEmilio G. Cota         g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn);
42838b47b19SEmilio G. Cota #endif
42938b47b19SEmilio G. Cota }
43038b47b19SEmilio G. Cota 
431e8feb96fSEmilio G. Cota /*
4323468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
4333468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
4343468b59eSEmilio G. Cota  * before initiating translation.
4353468b59eSEmilio G. Cota  *
4363468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
4373468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
4383468b59eSEmilio G. Cota  *
4393468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
4403468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
4413468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
4423468b59eSEmilio G. Cota  *
4433468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
4443468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
4453468b59eSEmilio G. Cota  */
4463468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
4473468b59eSEmilio G. Cota void tcg_register_thread(void)
4483468b59eSEmilio G. Cota {
4493468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
4503468b59eSEmilio G. Cota }
4513468b59eSEmilio G. Cota #else
4523468b59eSEmilio G. Cota void tcg_register_thread(void)
4533468b59eSEmilio G. Cota {
4543468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
4553468b59eSEmilio G. Cota     unsigned int i, n;
4563468b59eSEmilio G. Cota 
4573468b59eSEmilio G. Cota     *s = tcg_init_ctx;
4583468b59eSEmilio G. Cota 
4593468b59eSEmilio G. Cota     /* Relink mem_base.  */
4603468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
4613468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
4623468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
4633468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
4643468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
4653468b59eSEmilio G. Cota         }
4663468b59eSEmilio G. Cota     }
4673468b59eSEmilio G. Cota 
4683468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
4690e2d61cfSRichard Henderson     n = qatomic_fetch_inc(&tcg_cur_ctxs);
4700e2d61cfSRichard Henderson     g_assert(n < tcg_max_ctxs);
471d73415a3SStefan Hajnoczi     qatomic_set(&tcg_ctxs[n], s);
4723468b59eSEmilio G. Cota 
47338b47b19SEmilio G. Cota     if (n > 0) {
47438b47b19SEmilio G. Cota         alloc_tcg_plugin_context(s);
475bf042e8eSRichard Henderson         tcg_region_initial_alloc(s);
47638b47b19SEmilio G. Cota     }
47738b47b19SEmilio G. Cota 
4783468b59eSEmilio G. Cota     tcg_ctx = s;
4793468b59eSEmilio G. Cota }
4803468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
4813468b59eSEmilio G. Cota 
482c896fe29Sbellard /* pool based memory allocation */
483c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
484c896fe29Sbellard {
485c896fe29Sbellard     TCGPool *p;
486c896fe29Sbellard     int pool_size;
487c896fe29Sbellard 
488c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
489c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
4907267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
491c896fe29Sbellard         p->size = size;
4924055299eSKirill Batuzov         p->next = s->pool_first_large;
4934055299eSKirill Batuzov         s->pool_first_large = p;
4944055299eSKirill Batuzov         return p->data;
495c896fe29Sbellard     } else {
496c896fe29Sbellard         p = s->pool_current;
497c896fe29Sbellard         if (!p) {
498c896fe29Sbellard             p = s->pool_first;
499c896fe29Sbellard             if (!p)
500c896fe29Sbellard                 goto new_pool;
501c896fe29Sbellard         } else {
502c896fe29Sbellard             if (!p->next) {
503c896fe29Sbellard             new_pool:
504c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
5057267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
506c896fe29Sbellard                 p->size = pool_size;
507c896fe29Sbellard                 p->next = NULL;
508c896fe29Sbellard                 if (s->pool_current)
509c896fe29Sbellard                     s->pool_current->next = p;
510c896fe29Sbellard                 else
511c896fe29Sbellard                     s->pool_first = p;
512c896fe29Sbellard             } else {
513c896fe29Sbellard                 p = p->next;
514c896fe29Sbellard             }
515c896fe29Sbellard         }
516c896fe29Sbellard     }
517c896fe29Sbellard     s->pool_current = p;
518c896fe29Sbellard     s->pool_cur = p->data + size;
519c896fe29Sbellard     s->pool_end = p->data + p->size;
520c896fe29Sbellard     return p->data;
521c896fe29Sbellard }
522c896fe29Sbellard 
523c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
524c896fe29Sbellard {
5254055299eSKirill Batuzov     TCGPool *p, *t;
5264055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
5274055299eSKirill Batuzov         t = p->next;
5284055299eSKirill Batuzov         g_free(p);
5294055299eSKirill Batuzov     }
5304055299eSKirill Batuzov     s->pool_first_large = NULL;
531c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
532c896fe29Sbellard     s->pool_current = NULL;
533c896fe29Sbellard }
534c896fe29Sbellard 
535100b5e01SRichard Henderson typedef struct TCGHelperInfo {
536100b5e01SRichard Henderson     void *func;
537100b5e01SRichard Henderson     const char *name;
538afb49896SRichard Henderson     unsigned flags;
539*7319d83aSRichard Henderson     unsigned typemask;
540100b5e01SRichard Henderson } TCGHelperInfo;
541100b5e01SRichard Henderson 
5422ef6175aSRichard Henderson #include "exec/helper-proto.h"
5432ef6175aSRichard Henderson 
544100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = {
5452ef6175aSRichard Henderson #include "exec/helper-tcg.h"
546100b5e01SRichard Henderson };
547619205fdSEmilio G. Cota static GHashTable *helper_table;
548100b5e01SRichard Henderson 
54991478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
550f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
5511c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
5521c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
55391478cefSRichard Henderson 
55443b972b7SRichard Henderson static void tcg_context_init(unsigned max_cpus)
555c896fe29Sbellard {
556a76aabd3SRichard Henderson     TCGContext *s = &tcg_init_ctx;
557100b5e01SRichard Henderson     int op, total_args, n, i;
558c896fe29Sbellard     TCGOpDef *def;
559c896fe29Sbellard     TCGArgConstraint *args_ct;
5601c2adb95SRichard Henderson     TCGTemp *ts;
561c896fe29Sbellard 
562c896fe29Sbellard     memset(s, 0, sizeof(*s));
563c896fe29Sbellard     s->nb_globals = 0;
564c896fe29Sbellard 
565c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
566c896fe29Sbellard        space */
567c896fe29Sbellard     total_args = 0;
568c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
569c896fe29Sbellard         def = &tcg_op_defs[op];
570c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
571c896fe29Sbellard         total_args += n;
572c896fe29Sbellard     }
573c896fe29Sbellard 
574bc2b17e6SRichard Henderson     args_ct = g_new0(TCGArgConstraint, total_args);
575c896fe29Sbellard 
576c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
577c896fe29Sbellard         def = &tcg_op_defs[op];
578c896fe29Sbellard         def->args_ct = args_ct;
579c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
580c896fe29Sbellard         args_ct += n;
581c896fe29Sbellard     }
582c896fe29Sbellard 
5835cd8f621SRichard Henderson     /* Register helpers.  */
58484fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
585619205fdSEmilio G. Cota     helper_table = g_hash_table_new(NULL, NULL);
58684fd9dd3SRichard Henderson 
587100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
58884fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
58972866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
590100b5e01SRichard Henderson     }
5915cd8f621SRichard Henderson 
592c896fe29Sbellard     tcg_target_init(s);
593f69d277eSRichard Henderson     process_op_defs(s);
59491478cefSRichard Henderson 
59591478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
59691478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
59791478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
59891478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
59991478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
60091478cefSRichard Henderson             break;
60191478cefSRichard Henderson         }
60291478cefSRichard Henderson     }
60391478cefSRichard Henderson     for (i = 0; i < n; ++i) {
60491478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
60591478cefSRichard Henderson     }
60691478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
60791478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
60891478cefSRichard Henderson     }
609b1311c4aSEmilio G. Cota 
61038b47b19SEmilio G. Cota     alloc_tcg_plugin_context(s);
61138b47b19SEmilio G. Cota 
612b1311c4aSEmilio G. Cota     tcg_ctx = s;
6133468b59eSEmilio G. Cota     /*
6143468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
6153468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
6163468b59eSEmilio G. Cota      * reasoning behind this.
6173468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
6183468b59eSEmilio G. Cota      */
6193468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
620df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
6210e2d61cfSRichard Henderson     tcg_cur_ctxs = 1;
6220e2d61cfSRichard Henderson     tcg_max_ctxs = 1;
6233468b59eSEmilio G. Cota #else
6240e2d61cfSRichard Henderson     tcg_max_ctxs = max_cpus;
6250e2d61cfSRichard Henderson     tcg_ctxs = g_new0(TCGContext *, max_cpus);
6263468b59eSEmilio G. Cota #endif
6271c2adb95SRichard Henderson 
6281c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
6291c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
6301c2adb95SRichard Henderson     cpu_env = temp_tcgv_ptr(ts);
6319002ec79SRichard Henderson }
632b03cce8eSbellard 
63343b972b7SRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus)
634a76aabd3SRichard Henderson {
63543b972b7SRichard Henderson     tcg_context_init(max_cpus);
63643b972b7SRichard Henderson     tcg_region_init(tb_size, splitwx, max_cpus);
637a76aabd3SRichard Henderson }
638a76aabd3SRichard Henderson 
6396e3b2bfdSEmilio G. Cota /*
6406e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
6416e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
6426e3b2bfdSEmilio G. Cota  */
6436e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
6446e3b2bfdSEmilio G. Cota {
6456e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
6466e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
6476e3b2bfdSEmilio G. Cota     void *next;
6486e3b2bfdSEmilio G. Cota 
649e8feb96fSEmilio G. Cota  retry:
6506e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
6516e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
6526e3b2bfdSEmilio G. Cota 
6536e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
654e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
6556e3b2bfdSEmilio G. Cota             return NULL;
6566e3b2bfdSEmilio G. Cota         }
657e8feb96fSEmilio G. Cota         goto retry;
658e8feb96fSEmilio G. Cota     }
659d73415a3SStefan Hajnoczi     qatomic_set(&s->code_gen_ptr, next);
66057a26946SRichard Henderson     s->data_gen_ptr = NULL;
6616e3b2bfdSEmilio G. Cota     return tb;
6626e3b2bfdSEmilio G. Cota }
6636e3b2bfdSEmilio G. Cota 
6649002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
6659002ec79SRichard Henderson {
666b0a0794aSRichard Henderson     size_t prologue_size;
6678163b749SRichard Henderson 
668b0a0794aSRichard Henderson     s->code_ptr = s->code_gen_ptr;
669b0a0794aSRichard Henderson     s->code_buf = s->code_gen_ptr;
6705b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
671b91ccb31SRichard Henderson 
672b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
673b0a0794aSRichard Henderson     tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr);
674b91ccb31SRichard Henderson #endif
6758163b749SRichard Henderson 
6765b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
6775b38ee31SRichard Henderson     s->pool_labels = NULL;
6785b38ee31SRichard Henderson #endif
6795b38ee31SRichard Henderson 
680653b87ebSRoman Bolshakov     qemu_thread_jit_write();
6818163b749SRichard Henderson     /* Generate the prologue.  */
682b03cce8eSbellard     tcg_target_qemu_prologue(s);
6835b38ee31SRichard Henderson 
6845b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
6855b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
6865b38ee31SRichard Henderson     {
6871768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
6881768987bSRichard Henderson         tcg_debug_assert(result == 0);
6895b38ee31SRichard Henderson     }
6905b38ee31SRichard Henderson #endif
6915b38ee31SRichard Henderson 
692b0a0794aSRichard Henderson     prologue_size = tcg_current_code_size(s);
693b0a0794aSRichard Henderson 
694df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
695b0a0794aSRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
696b0a0794aSRichard Henderson                         (uintptr_t)s->code_buf, prologue_size);
697df5d2b16SRichard Henderson #endif
6988163b749SRichard Henderson 
699bf042e8eSRichard Henderson     tcg_region_prologue_set(s);
700d6b64b2bSRichard Henderson 
701d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
702d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
703fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
7048163b749SRichard Henderson         qemu_log("PROLOGUE: [size=%zu]\n", prologue_size);
7055b38ee31SRichard Henderson         if (s->data_gen_ptr) {
706b0a0794aSRichard Henderson             size_t code_size = s->data_gen_ptr - s->code_gen_ptr;
7075b38ee31SRichard Henderson             size_t data_size = prologue_size - code_size;
7085b38ee31SRichard Henderson             size_t i;
7095b38ee31SRichard Henderson 
710b0a0794aSRichard Henderson             log_disas(s->code_gen_ptr, code_size);
7115b38ee31SRichard Henderson 
7125b38ee31SRichard Henderson             for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
7135b38ee31SRichard Henderson                 if (sizeof(tcg_target_ulong) == 8) {
7145b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
7155b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
7165b38ee31SRichard Henderson                              *(uint64_t *)(s->data_gen_ptr + i));
7175b38ee31SRichard Henderson                 } else {
7185b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .long  0x%08x\n",
7195b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
7205b38ee31SRichard Henderson                              *(uint32_t *)(s->data_gen_ptr + i));
7215b38ee31SRichard Henderson                 }
7225b38ee31SRichard Henderson             }
7235b38ee31SRichard Henderson         } else {
724b0a0794aSRichard Henderson             log_disas(s->code_gen_ptr, prologue_size);
7255b38ee31SRichard Henderson         }
726d6b64b2bSRichard Henderson         qemu_log("\n");
727d6b64b2bSRichard Henderson         qemu_log_flush();
728fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
729d6b64b2bSRichard Henderson     }
730d6b64b2bSRichard Henderson #endif
731cedbcb01SEmilio G. Cota 
732cedbcb01SEmilio G. Cota     /* Assert that goto_ptr is implemented completely.  */
733cedbcb01SEmilio G. Cota     if (TCG_TARGET_HAS_goto_ptr) {
7348b5c2b62SRichard Henderson         tcg_debug_assert(tcg_code_gen_epilogue != NULL);
735cedbcb01SEmilio G. Cota     }
736c896fe29Sbellard }
737c896fe29Sbellard 
738c896fe29Sbellard void tcg_func_start(TCGContext *s)
739c896fe29Sbellard {
740c896fe29Sbellard     tcg_pool_reset(s);
741c896fe29Sbellard     s->nb_temps = s->nb_globals;
7420ec9eabcSRichard Henderson 
7430ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
7440ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
7450ec9eabcSRichard Henderson 
746c0522136SRichard Henderson     /* No constant temps have been previously allocated. */
747c0522136SRichard Henderson     for (int i = 0; i < TCG_TYPE_COUNT; ++i) {
748c0522136SRichard Henderson         if (s->const_table[i]) {
749c0522136SRichard Henderson             g_hash_table_remove_all(s->const_table[i]);
750c0522136SRichard Henderson         }
751c0522136SRichard Henderson     }
752c0522136SRichard Henderson 
753abebf925SRichard Henderson     s->nb_ops = 0;
754c896fe29Sbellard     s->nb_labels = 0;
755c896fe29Sbellard     s->current_frame_offset = s->frame_start;
756c896fe29Sbellard 
7570a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
7580a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
7590a209d4bSRichard Henderson #endif
7600a209d4bSRichard Henderson 
76115fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
76215fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
763bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
764c896fe29Sbellard }
765c896fe29Sbellard 
766ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s)
7677ca4b752SRichard Henderson {
7687ca4b752SRichard Henderson     int n = s->nb_temps++;
769ae30e866SRichard Henderson 
770ae30e866SRichard Henderson     if (n >= TCG_MAX_TEMPS) {
771db6b7d0cSRichard Henderson         tcg_raise_tb_overflow(s);
772ae30e866SRichard Henderson     }
7737ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
7747ca4b752SRichard Henderson }
7757ca4b752SRichard Henderson 
776ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s)
7777ca4b752SRichard Henderson {
778fa477d25SRichard Henderson     TCGTemp *ts;
779fa477d25SRichard Henderson 
7807ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
781ae30e866SRichard Henderson     tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS);
7827ca4b752SRichard Henderson     s->nb_globals++;
783fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
784ee17db83SRichard Henderson     ts->kind = TEMP_GLOBAL;
785fa477d25SRichard Henderson 
786fa477d25SRichard Henderson     return ts;
787c896fe29Sbellard }
788c896fe29Sbellard 
789085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
790b6638662SRichard Henderson                                             TCGReg reg, const char *name)
791c896fe29Sbellard {
792c896fe29Sbellard     TCGTemp *ts;
793c896fe29Sbellard 
794b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
795c896fe29Sbellard         tcg_abort();
796b3a62939SRichard Henderson     }
7977ca4b752SRichard Henderson 
7987ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
799c896fe29Sbellard     ts->base_type = type;
800c896fe29Sbellard     ts->type = type;
801ee17db83SRichard Henderson     ts->kind = TEMP_FIXED;
802c896fe29Sbellard     ts->reg = reg;
803c896fe29Sbellard     ts->name = name;
804c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
8057ca4b752SRichard Henderson 
806085272b3SRichard Henderson     return ts;
807a7812ae4Spbrook }
808a7812ae4Spbrook 
809b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
810a7812ae4Spbrook {
811b3a62939SRichard Henderson     s->frame_start = start;
812b3a62939SRichard Henderson     s->frame_end = start + size;
813085272b3SRichard Henderson     s->frame_temp
814085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
815b3a62939SRichard Henderson }
816a7812ae4Spbrook 
817085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
818e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
819c896fe29Sbellard {
820b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
821dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
8227ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
823b3915dbbSRichard Henderson     int indirect_reg = 0, bigendian = 0;
8247ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
8257ca4b752SRichard Henderson     bigendian = 1;
8267ca4b752SRichard Henderson #endif
827c896fe29Sbellard 
828c0522136SRichard Henderson     switch (base_ts->kind) {
829c0522136SRichard Henderson     case TEMP_FIXED:
830c0522136SRichard Henderson         break;
831c0522136SRichard Henderson     case TEMP_GLOBAL:
8325a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
8335a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
834b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
8355a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
8365a18407fSRichard Henderson                             ? 2 : 1);
8375a18407fSRichard Henderson         indirect_reg = 1;
838c0522136SRichard Henderson         break;
839c0522136SRichard Henderson     default:
840c0522136SRichard Henderson         g_assert_not_reached();
841b3915dbbSRichard Henderson     }
842b3915dbbSRichard Henderson 
8437ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
8447ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
845c896fe29Sbellard         char buf[64];
8467ca4b752SRichard Henderson 
8477ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
848c896fe29Sbellard         ts->type = TCG_TYPE_I32;
849b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
850c896fe29Sbellard         ts->mem_allocated = 1;
851b3a62939SRichard Henderson         ts->mem_base = base_ts;
8527ca4b752SRichard Henderson         ts->mem_offset = offset + bigendian * 4;
853c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
854c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
855c896fe29Sbellard         ts->name = strdup(buf);
856c896fe29Sbellard 
8577ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
8587ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
8597ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
860b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
8617ca4b752SRichard Henderson         ts2->mem_allocated = 1;
8627ca4b752SRichard Henderson         ts2->mem_base = base_ts;
8637ca4b752SRichard Henderson         ts2->mem_offset = offset + (1 - bigendian) * 4;
864c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
865c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
866120c1084SRichard Henderson         ts2->name = strdup(buf);
8677ca4b752SRichard Henderson     } else {
868c896fe29Sbellard         ts->base_type = type;
869c896fe29Sbellard         ts->type = type;
870b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
871c896fe29Sbellard         ts->mem_allocated = 1;
872b3a62939SRichard Henderson         ts->mem_base = base_ts;
873c896fe29Sbellard         ts->mem_offset = offset;
874c896fe29Sbellard         ts->name = name;
875c896fe29Sbellard     }
876085272b3SRichard Henderson     return ts;
877c896fe29Sbellard }
878c896fe29Sbellard 
8795bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local)
880c896fe29Sbellard {
881b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
882ee17db83SRichard Henderson     TCGTempKind kind = temp_local ? TEMP_LOCAL : TEMP_NORMAL;
883c896fe29Sbellard     TCGTemp *ts;
884641d5fbeSbellard     int idx, k;
885c896fe29Sbellard 
8860ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
8870ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
8880ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
8890ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
8900ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
8910ec9eabcSRichard Henderson 
892e8996ee0Sbellard         ts = &s->temps[idx];
893e8996ee0Sbellard         ts->temp_allocated = 1;
8947ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
895ee17db83SRichard Henderson         tcg_debug_assert(ts->kind == kind);
896e8996ee0Sbellard     } else {
8977ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
8987ca4b752SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
8997ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
9007ca4b752SRichard Henderson 
901c896fe29Sbellard             ts->base_type = type;
902c896fe29Sbellard             ts->type = TCG_TYPE_I32;
903e8996ee0Sbellard             ts->temp_allocated = 1;
904ee17db83SRichard Henderson             ts->kind = kind;
9057ca4b752SRichard Henderson 
9067ca4b752SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
9077ca4b752SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
9087ca4b752SRichard Henderson             ts2->type = TCG_TYPE_I32;
9097ca4b752SRichard Henderson             ts2->temp_allocated = 1;
910ee17db83SRichard Henderson             ts2->kind = kind;
9117ca4b752SRichard Henderson         } else {
912c896fe29Sbellard             ts->base_type = type;
913c896fe29Sbellard             ts->type = type;
914e8996ee0Sbellard             ts->temp_allocated = 1;
915ee17db83SRichard Henderson             ts->kind = kind;
916c896fe29Sbellard         }
917e8996ee0Sbellard     }
91827bfd83cSPeter Maydell 
91927bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
92027bfd83cSPeter Maydell     s->temps_in_use++;
92127bfd83cSPeter Maydell #endif
922085272b3SRichard Henderson     return ts;
923c896fe29Sbellard }
924c896fe29Sbellard 
925d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
926d2fd745fSRichard Henderson {
927d2fd745fSRichard Henderson     TCGTemp *t;
928d2fd745fSRichard Henderson 
929d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
930d2fd745fSRichard Henderson     switch (type) {
931d2fd745fSRichard Henderson     case TCG_TYPE_V64:
932d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
933d2fd745fSRichard Henderson         break;
934d2fd745fSRichard Henderson     case TCG_TYPE_V128:
935d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
936d2fd745fSRichard Henderson         break;
937d2fd745fSRichard Henderson     case TCG_TYPE_V256:
938d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
939d2fd745fSRichard Henderson         break;
940d2fd745fSRichard Henderson     default:
941d2fd745fSRichard Henderson         g_assert_not_reached();
942d2fd745fSRichard Henderson     }
943d2fd745fSRichard Henderson #endif
944d2fd745fSRichard Henderson 
945d2fd745fSRichard Henderson     t = tcg_temp_new_internal(type, 0);
946d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
947d2fd745fSRichard Henderson }
948d2fd745fSRichard Henderson 
949d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
950d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
951d2fd745fSRichard Henderson {
952d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
953d2fd745fSRichard Henderson 
954d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
955d2fd745fSRichard Henderson 
956d2fd745fSRichard Henderson     t = tcg_temp_new_internal(t->base_type, 0);
957d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
958d2fd745fSRichard Henderson }
959d2fd745fSRichard Henderson 
9605bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
961c896fe29Sbellard {
962b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
963085272b3SRichard Henderson     int k, idx;
964c896fe29Sbellard 
965c0522136SRichard Henderson     /* In order to simplify users of tcg_constant_*, silently ignore free. */
966c0522136SRichard Henderson     if (ts->kind == TEMP_CONST) {
967c0522136SRichard Henderson         return;
968c0522136SRichard Henderson     }
969c0522136SRichard Henderson 
97027bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
97127bfd83cSPeter Maydell     s->temps_in_use--;
97227bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
97327bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
97427bfd83cSPeter Maydell     }
97527bfd83cSPeter Maydell #endif
97627bfd83cSPeter Maydell 
977ee17db83SRichard Henderson     tcg_debug_assert(ts->kind < TEMP_GLOBAL);
978eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
979e8996ee0Sbellard     ts->temp_allocated = 0;
9800ec9eabcSRichard Henderson 
981085272b3SRichard Henderson     idx = temp_idx(ts);
982ee17db83SRichard Henderson     k = ts->base_type + (ts->kind == TEMP_NORMAL ? 0 : TCG_TYPE_COUNT);
9830ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
984e8996ee0Sbellard }
985e8996ee0Sbellard 
986c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val)
987c0522136SRichard Henderson {
988c0522136SRichard Henderson     TCGContext *s = tcg_ctx;
989c0522136SRichard Henderson     GHashTable *h = s->const_table[type];
990c0522136SRichard Henderson     TCGTemp *ts;
991c0522136SRichard Henderson 
992c0522136SRichard Henderson     if (h == NULL) {
993c0522136SRichard Henderson         h = g_hash_table_new(g_int64_hash, g_int64_equal);
994c0522136SRichard Henderson         s->const_table[type] = h;
995c0522136SRichard Henderson     }
996c0522136SRichard Henderson 
997c0522136SRichard Henderson     ts = g_hash_table_lookup(h, &val);
998c0522136SRichard Henderson     if (ts == NULL) {
999c0522136SRichard Henderson         ts = tcg_temp_alloc(s);
1000c0522136SRichard Henderson 
1001c0522136SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
1002c0522136SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
1003c0522136SRichard Henderson 
1004c0522136SRichard Henderson             ts->base_type = TCG_TYPE_I64;
1005c0522136SRichard Henderson             ts->type = TCG_TYPE_I32;
1006c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1007c0522136SRichard Henderson             ts->temp_allocated = 1;
1008c0522136SRichard Henderson             /*
1009c0522136SRichard Henderson              * Retain the full value of the 64-bit constant in the low
1010c0522136SRichard Henderson              * part, so that the hash table works.  Actual uses will
1011c0522136SRichard Henderson              * truncate the value to the low part.
1012c0522136SRichard Henderson              */
1013c0522136SRichard Henderson             ts->val = val;
1014c0522136SRichard Henderson 
1015c0522136SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
1016c0522136SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
1017c0522136SRichard Henderson             ts2->type = TCG_TYPE_I32;
1018c0522136SRichard Henderson             ts2->kind = TEMP_CONST;
1019c0522136SRichard Henderson             ts2->temp_allocated = 1;
1020c0522136SRichard Henderson             ts2->val = val >> 32;
1021c0522136SRichard Henderson         } else {
1022c0522136SRichard Henderson             ts->base_type = type;
1023c0522136SRichard Henderson             ts->type = type;
1024c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1025c0522136SRichard Henderson             ts->temp_allocated = 1;
1026c0522136SRichard Henderson             ts->val = val;
1027c0522136SRichard Henderson         }
1028c0522136SRichard Henderson         g_hash_table_insert(h, &ts->val, ts);
1029c0522136SRichard Henderson     }
1030c0522136SRichard Henderson 
1031c0522136SRichard Henderson     return ts;
1032c0522136SRichard Henderson }
1033c0522136SRichard Henderson 
1034c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val)
1035c0522136SRichard Henderson {
1036c0522136SRichard Henderson     val = dup_const(vece, val);
1037c0522136SRichard Henderson     return temp_tcgv_vec(tcg_constant_internal(type, val));
1038c0522136SRichard Henderson }
1039c0522136SRichard Henderson 
104088d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val)
104188d4005bSRichard Henderson {
104288d4005bSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
104388d4005bSRichard Henderson 
104488d4005bSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
104588d4005bSRichard Henderson     return tcg_constant_vec(t->base_type, vece, val);
104688d4005bSRichard Henderson }
104788d4005bSRichard Henderson 
1048a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
1049a7812ae4Spbrook {
1050a7812ae4Spbrook     TCGv_i32 t0;
1051a7812ae4Spbrook     t0 = tcg_temp_new_i32();
1052e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
1053e8996ee0Sbellard     return t0;
1054c896fe29Sbellard }
1055c896fe29Sbellard 
1056a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
1057c896fe29Sbellard {
1058a7812ae4Spbrook     TCGv_i64 t0;
1059a7812ae4Spbrook     t0 = tcg_temp_new_i64();
1060e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
1061e8996ee0Sbellard     return t0;
1062c896fe29Sbellard }
1063c896fe29Sbellard 
1064a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
1065bdffd4a9Saurel32 {
1066a7812ae4Spbrook     TCGv_i32 t0;
1067a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
1068bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
1069bdffd4a9Saurel32     return t0;
1070bdffd4a9Saurel32 }
1071bdffd4a9Saurel32 
1072a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
1073bdffd4a9Saurel32 {
1074a7812ae4Spbrook     TCGv_i64 t0;
1075a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
1076bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
1077bdffd4a9Saurel32     return t0;
1078bdffd4a9Saurel32 }
1079bdffd4a9Saurel32 
108027bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
108127bfd83cSPeter Maydell void tcg_clear_temp_count(void)
108227bfd83cSPeter Maydell {
1083b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
108427bfd83cSPeter Maydell     s->temps_in_use = 0;
108527bfd83cSPeter Maydell }
108627bfd83cSPeter Maydell 
108727bfd83cSPeter Maydell int tcg_check_temp_count(void)
108827bfd83cSPeter Maydell {
1089b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
109027bfd83cSPeter Maydell     if (s->temps_in_use) {
109127bfd83cSPeter Maydell         /* Clear the count so that we don't give another
109227bfd83cSPeter Maydell          * warning immediately next time around.
109327bfd83cSPeter Maydell          */
109427bfd83cSPeter Maydell         s->temps_in_use = 0;
109527bfd83cSPeter Maydell         return 1;
109627bfd83cSPeter Maydell     }
109727bfd83cSPeter Maydell     return 0;
109827bfd83cSPeter Maydell }
109927bfd83cSPeter Maydell #endif
110027bfd83cSPeter Maydell 
1101be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1102be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1103be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1104be0f34b5SRichard Henderson {
1105d2fd745fSRichard Henderson     const bool have_vec
1106d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1107d2fd745fSRichard Henderson 
1108be0f34b5SRichard Henderson     switch (op) {
1109be0f34b5SRichard Henderson     case INDEX_op_discard:
1110be0f34b5SRichard Henderson     case INDEX_op_set_label:
1111be0f34b5SRichard Henderson     case INDEX_op_call:
1112be0f34b5SRichard Henderson     case INDEX_op_br:
1113be0f34b5SRichard Henderson     case INDEX_op_mb:
1114be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1115be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1116be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1117be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i32:
1118be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i32:
1119be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i64:
1120be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i64:
1121be0f34b5SRichard Henderson         return true;
1122be0f34b5SRichard Henderson 
112307ce0b05SRichard Henderson     case INDEX_op_qemu_st8_i32:
112407ce0b05SRichard Henderson         return TCG_TARGET_HAS_qemu_st8_i32;
112507ce0b05SRichard Henderson 
1126be0f34b5SRichard Henderson     case INDEX_op_goto_ptr:
1127be0f34b5SRichard Henderson         return TCG_TARGET_HAS_goto_ptr;
1128be0f34b5SRichard Henderson 
1129be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1130be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1131be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1132be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1133be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1134be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1135be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1136be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1137be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1138be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1139be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1140be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1141be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1142be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1143be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1144be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1145be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1146be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1147be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1148be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1149be0f34b5SRichard Henderson         return true;
1150be0f34b5SRichard Henderson 
1151be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1152be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1153be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1154be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1155be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1156be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1157be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1158be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1159be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1160be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1161be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1162be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1163be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1164be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1165be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1166be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1167be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1168be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1169be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1170be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1171fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
1172fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
1173be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1174be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1175be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1176be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1177be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1178be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1179be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1180be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1181be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1182be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1183be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1184be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1185be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1186be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1187be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1188be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1189be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1190be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1191be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1192be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1193be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1194be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1195be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1196be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1197be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1198be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1199be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1200be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1201be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1202be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1203be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1204be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1205be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1206be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1207be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1208be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1209be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1210be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1211be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1212be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1213be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1214be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1215be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1216be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1217be0f34b5SRichard Henderson 
1218be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1219be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1220be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1221be0f34b5SRichard Henderson 
1222be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1223be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1224be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1225be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1226be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1227be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1228be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1229be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1230be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1231be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1232be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1233be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1234be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1235be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1236be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1237be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1238be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1239be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1240be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1241be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1242be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1243be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1244be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1245be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1246be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1247be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1248be0f34b5SRichard Henderson 
1249be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1250be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1251be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1252be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1253be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1254be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1255be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1256be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1257be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1258be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
1259be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
1260be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
1261be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
1262be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
1263be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
1264be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
1265be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
1266be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
1267be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
1268be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
1269fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
1270fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
1271be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
1272be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrl_i64_i32;
1273be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
1274be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrh_i64_i32;
1275be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
1276be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
1277be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
1278be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
1279be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
1280be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
1281be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
1282be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
1283be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
1284be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
1285be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
1286be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
1287be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
1288be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
1289be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
1290be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
1291be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
1292be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
1293be0f34b5SRichard Henderson     case INDEX_op_not_i64:
1294be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
1295be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
1296be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
1297be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
1298be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
1299be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
1300be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
1301be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
1302be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
1303be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
1304be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
1305be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
1306be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
1307be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
1308be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
1309be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
1310be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
1311be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
1312be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
1313be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
1314be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
1315be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
1316be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
1317be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
1318be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
1319be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
1320be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
1321be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
1322be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
1323be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
1324be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
1325be0f34b5SRichard Henderson 
1326d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
1327d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
132837ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
1329d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
1330d2fd745fSRichard Henderson     case INDEX_op_st_vec:
1331d2fd745fSRichard Henderson     case INDEX_op_add_vec:
1332d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
1333d2fd745fSRichard Henderson     case INDEX_op_and_vec:
1334d2fd745fSRichard Henderson     case INDEX_op_or_vec:
1335d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
1336212be173SRichard Henderson     case INDEX_op_cmp_vec:
1337d2fd745fSRichard Henderson         return have_vec;
1338d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
1339d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
1340d2fd745fSRichard Henderson     case INDEX_op_not_vec:
1341d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
1342d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
1343d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
1344bcefc902SRichard Henderson     case INDEX_op_abs_vec:
1345bcefc902SRichard Henderson         return have_vec && TCG_TARGET_HAS_abs_vec;
1346d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
1347d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
1348d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
1349d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
13503774030aSRichard Henderson     case INDEX_op_mul_vec:
13513774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
1352d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
1353d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
1354d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
1355d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
1356d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
1357d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
1358d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
1359d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
1360d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
1361d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
1362d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
1363d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
1364b0f7e744SRichard Henderson     case INDEX_op_rotli_vec:
1365b0f7e744SRichard Henderson         return have_vec && TCG_TARGET_HAS_roti_vec;
136623850a74SRichard Henderson     case INDEX_op_rotls_vec:
136723850a74SRichard Henderson         return have_vec && TCG_TARGET_HAS_rots_vec;
13685d0ceda9SRichard Henderson     case INDEX_op_rotlv_vec:
13695d0ceda9SRichard Henderson     case INDEX_op_rotrv_vec:
13705d0ceda9SRichard Henderson         return have_vec && TCG_TARGET_HAS_rotv_vec;
13718afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
13728afaf050SRichard Henderson     case INDEX_op_usadd_vec:
13738afaf050SRichard Henderson     case INDEX_op_sssub_vec:
13748afaf050SRichard Henderson     case INDEX_op_ussub_vec:
13758afaf050SRichard Henderson         return have_vec && TCG_TARGET_HAS_sat_vec;
1376dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
1377dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
1378dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
1379dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
1380dd0a0fcdSRichard Henderson         return have_vec && TCG_TARGET_HAS_minmax_vec;
138138dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
138238dc1294SRichard Henderson         return have_vec && TCG_TARGET_HAS_bitsel_vec;
1383f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
1384f75da298SRichard Henderson         return have_vec && TCG_TARGET_HAS_cmpsel_vec;
1385d2fd745fSRichard Henderson 
1386db432672SRichard Henderson     default:
1387db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
1388db432672SRichard Henderson         return true;
1389be0f34b5SRichard Henderson     }
1390be0f34b5SRichard Henderson }
1391be0f34b5SRichard Henderson 
139239cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment
139339cf05d3Sbellard    and endian swap. Maybe it would be better to do the alignment
139439cf05d3Sbellard    and endian swap in tcg_reg_alloc_call(). */
1395ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
1396c896fe29Sbellard {
139775e8b9b7SRichard Henderson     int i, real_args, nb_rets, pi;
1398*7319d83aSRichard Henderson     unsigned typemask, flags;
1399afb49896SRichard Henderson     TCGHelperInfo *info;
140075e8b9b7SRichard Henderson     TCGOp *op;
1401afb49896SRichard Henderson 
1402619205fdSEmilio G. Cota     info = g_hash_table_lookup(helper_table, (gpointer)func);
1403bbb8a1b4SRichard Henderson     flags = info->flags;
1404*7319d83aSRichard Henderson     typemask = info->typemask;
14052bece2c8SRichard Henderson 
140638b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
140738b47b19SEmilio G. Cota     /* detect non-plugin helpers */
140838b47b19SEmilio G. Cota     if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) {
140938b47b19SEmilio G. Cota         tcg_ctx->plugin_insn->calls_helpers = true;
141038b47b19SEmilio G. Cota     }
141138b47b19SEmilio G. Cota #endif
141238b47b19SEmilio G. Cota 
141334b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
141434b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
141534b1a49cSRichard Henderson     /* We have 64-bit values in one register, but need to pass as two
141634b1a49cSRichard Henderson        separate parameters.  Split them.  */
1417*7319d83aSRichard Henderson     int orig_typemask = typemask;
141834b1a49cSRichard Henderson     int orig_nargs = nargs;
141934b1a49cSRichard Henderson     TCGv_i64 retl, reth;
1420ae8b75dcSRichard Henderson     TCGTemp *split_args[MAX_OPC_PARAM];
142134b1a49cSRichard Henderson 
1422f764718dSRichard Henderson     retl = NULL;
1423f764718dSRichard Henderson     reth = NULL;
1424*7319d83aSRichard Henderson     typemask = 0;
142534b1a49cSRichard Henderson     for (i = real_args = 0; i < nargs; ++i) {
1426*7319d83aSRichard Henderson         int argtype = extract32(orig_typemask, (i + 1) * 3, 3);
1427*7319d83aSRichard Henderson         bool is_64bit = (argtype & ~1) == dh_typecode_i64;
1428*7319d83aSRichard Henderson 
142934b1a49cSRichard Henderson         if (is_64bit) {
1430085272b3SRichard Henderson             TCGv_i64 orig = temp_tcgv_i64(args[i]);
143134b1a49cSRichard Henderson             TCGv_i32 h = tcg_temp_new_i32();
143234b1a49cSRichard Henderson             TCGv_i32 l = tcg_temp_new_i32();
143334b1a49cSRichard Henderson             tcg_gen_extr_i64_i32(l, h, orig);
1434ae8b75dcSRichard Henderson             split_args[real_args++] = tcgv_i32_temp(h);
1435*7319d83aSRichard Henderson             typemask |= dh_typecode_i32 << (real_args * 3);
1436ae8b75dcSRichard Henderson             split_args[real_args++] = tcgv_i32_temp(l);
1437*7319d83aSRichard Henderson             typemask |= dh_typecode_i32 << (real_args * 3);
143834b1a49cSRichard Henderson         } else {
143934b1a49cSRichard Henderson             split_args[real_args++] = args[i];
1440*7319d83aSRichard Henderson             typemask |= argtype << (real_args * 3);
144134b1a49cSRichard Henderson         }
144234b1a49cSRichard Henderson     }
144334b1a49cSRichard Henderson     nargs = real_args;
144434b1a49cSRichard Henderson     args = split_args;
144534b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
14462bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
1447*7319d83aSRichard Henderson         int argtype = extract32(typemask, (i + 1) * 3, 3);
1448*7319d83aSRichard Henderson         bool is_32bit = (argtype & ~1) == dh_typecode_i32;
1449*7319d83aSRichard Henderson         bool is_signed = argtype & 1;
1450*7319d83aSRichard Henderson 
1451*7319d83aSRichard Henderson         if (is_32bit) {
14522bece2c8SRichard Henderson             TCGv_i64 temp = tcg_temp_new_i64();
1453085272b3SRichard Henderson             TCGv_i64 orig = temp_tcgv_i64(args[i]);
14542bece2c8SRichard Henderson             if (is_signed) {
14552bece2c8SRichard Henderson                 tcg_gen_ext32s_i64(temp, orig);
14562bece2c8SRichard Henderson             } else {
14572bece2c8SRichard Henderson                 tcg_gen_ext32u_i64(temp, orig);
14582bece2c8SRichard Henderson             }
1459ae8b75dcSRichard Henderson             args[i] = tcgv_i64_temp(temp);
14602bece2c8SRichard Henderson         }
14612bece2c8SRichard Henderson     }
14622bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
14632bece2c8SRichard Henderson 
146415fa08f8SRichard Henderson     op = tcg_emit_op(INDEX_op_call);
146575e8b9b7SRichard Henderson 
146675e8b9b7SRichard Henderson     pi = 0;
1467ae8b75dcSRichard Henderson     if (ret != NULL) {
146834b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
146934b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
1470*7319d83aSRichard Henderson         if ((typemask & 6) == dh_typecode_i64) {
147134b1a49cSRichard Henderson             /* The 32-bit ABI is going to return the 64-bit value in
147234b1a49cSRichard Henderson                the %o0/%o1 register pair.  Prepare for this by using
147334b1a49cSRichard Henderson                two return temporaries, and reassemble below.  */
147434b1a49cSRichard Henderson             retl = tcg_temp_new_i64();
147534b1a49cSRichard Henderson             reth = tcg_temp_new_i64();
1476ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(reth);
1477ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(retl);
147834b1a49cSRichard Henderson             nb_rets = 2;
147934b1a49cSRichard Henderson         } else {
1480ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
148134b1a49cSRichard Henderson             nb_rets = 1;
148234b1a49cSRichard Henderson         }
148334b1a49cSRichard Henderson #else
1484*7319d83aSRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && (typemask & 6) == dh_typecode_i64) {
148502eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
1486ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1487ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1488a7812ae4Spbrook #else
1489ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1490ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1491a7812ae4Spbrook #endif
1492a7812ae4Spbrook             nb_rets = 2;
149334b1a49cSRichard Henderson         } else {
1494ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1495a7812ae4Spbrook             nb_rets = 1;
1496a7812ae4Spbrook         }
149734b1a49cSRichard Henderson #endif
1498a7812ae4Spbrook     } else {
1499a7812ae4Spbrook         nb_rets = 0;
1500a7812ae4Spbrook     }
1501cd9090aaSRichard Henderson     TCGOP_CALLO(op) = nb_rets;
150275e8b9b7SRichard Henderson 
1503a7812ae4Spbrook     real_args = 0;
1504a7812ae4Spbrook     for (i = 0; i < nargs; i++) {
1505*7319d83aSRichard Henderson         int argtype = extract32(typemask, (i + 1) * 3, 3);
1506*7319d83aSRichard Henderson         bool is_64bit = (argtype & ~1) == dh_typecode_i64;
1507*7319d83aSRichard Henderson 
1508bbb8a1b4SRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
150939cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS
151039cf05d3Sbellard             /* some targets want aligned 64 bit args */
1511ebd486d5Smalc             if (real_args & 1) {
151275e8b9b7SRichard Henderson                 op->args[pi++] = TCG_CALL_DUMMY_ARG;
1513ebd486d5Smalc                 real_args++;
151439cf05d3Sbellard             }
151539cf05d3Sbellard #endif
15163f90f252SRichard Henderson            /* If stack grows up, then we will be placing successive
15173f90f252SRichard Henderson               arguments at lower addresses, which means we need to
15183f90f252SRichard Henderson               reverse the order compared to how we would normally
15193f90f252SRichard Henderson               treat either big or little-endian.  For those arguments
15203f90f252SRichard Henderson               that will wind up in registers, this still works for
15213f90f252SRichard Henderson               HPPA (the only current STACK_GROWSUP target) since the
15223f90f252SRichard Henderson               argument registers are *also* allocated in decreasing
15233f90f252SRichard Henderson               order.  If another such target is added, this logic may
15243f90f252SRichard Henderson               have to get more complicated to differentiate between
15253f90f252SRichard Henderson               stack arguments and register arguments.  */
152602eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
1527ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1528ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1529c896fe29Sbellard #else
1530ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1531ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1532c896fe29Sbellard #endif
1533a7812ae4Spbrook             real_args += 2;
15342bece2c8SRichard Henderson             continue;
15352bece2c8SRichard Henderson         }
15362bece2c8SRichard Henderson 
1537ae8b75dcSRichard Henderson         op->args[pi++] = temp_arg(args[i]);
1538a7812ae4Spbrook         real_args++;
1539c896fe29Sbellard     }
154075e8b9b7SRichard Henderson     op->args[pi++] = (uintptr_t)func;
154175e8b9b7SRichard Henderson     op->args[pi++] = flags;
1542cd9090aaSRichard Henderson     TCGOP_CALLI(op) = real_args;
1543a7812ae4Spbrook 
154475e8b9b7SRichard Henderson     /* Make sure the fields didn't overflow.  */
1545cd9090aaSRichard Henderson     tcg_debug_assert(TCGOP_CALLI(op) == real_args);
154675e8b9b7SRichard Henderson     tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
15472bece2c8SRichard Henderson 
154834b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
154934b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
155034b1a49cSRichard Henderson     /* Free all of the parts we allocated above.  */
155134b1a49cSRichard Henderson     for (i = real_args = 0; i < orig_nargs; ++i) {
1552*7319d83aSRichard Henderson         int argtype = extract32(orig_typemask, (i + 1) * 3, 3);
1553*7319d83aSRichard Henderson         bool is_64bit = (argtype & ~1) == dh_typecode_i64;
1554*7319d83aSRichard Henderson 
155534b1a49cSRichard Henderson         if (is_64bit) {
1556085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
1557085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
155834b1a49cSRichard Henderson         } else {
155934b1a49cSRichard Henderson             real_args++;
156034b1a49cSRichard Henderson         }
156134b1a49cSRichard Henderson     }
1562*7319d83aSRichard Henderson     if ((orig_typemask & 6) == dh_typecode_i64) {
156334b1a49cSRichard Henderson         /* The 32-bit ABI returned two 32-bit pieces.  Re-assemble them.
156434b1a49cSRichard Henderson            Note that describing these as TCGv_i64 eliminates an unnecessary
156534b1a49cSRichard Henderson            zero-extension that tcg_gen_concat_i32_i64 would create.  */
1566085272b3SRichard Henderson         tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth);
156734b1a49cSRichard Henderson         tcg_temp_free_i64(retl);
156834b1a49cSRichard Henderson         tcg_temp_free_i64(reth);
156934b1a49cSRichard Henderson     }
157034b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
15712bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
1572*7319d83aSRichard Henderson         int argtype = extract32(typemask, (i + 1) * 3, 3);
1573*7319d83aSRichard Henderson         bool is_32bit = (argtype & ~1) == dh_typecode_i32;
1574*7319d83aSRichard Henderson 
1575*7319d83aSRichard Henderson         if (is_32bit) {
1576085272b3SRichard Henderson             tcg_temp_free_internal(args[i]);
15772bece2c8SRichard Henderson         }
15782bece2c8SRichard Henderson     }
15792bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
1580a7812ae4Spbrook }
1581c896fe29Sbellard 
15828fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
1583c896fe29Sbellard {
1584ac3b8891SRichard Henderson     int i, n;
1585ac3b8891SRichard Henderson 
1586ee17db83SRichard Henderson     for (i = 0, n = s->nb_temps; i < n; i++) {
1587ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
1588ee17db83SRichard Henderson         TCGTempVal val = TEMP_VAL_MEM;
1589ee17db83SRichard Henderson 
1590ee17db83SRichard Henderson         switch (ts->kind) {
1591c0522136SRichard Henderson         case TEMP_CONST:
1592c0522136SRichard Henderson             val = TEMP_VAL_CONST;
1593c0522136SRichard Henderson             break;
1594ee17db83SRichard Henderson         case TEMP_FIXED:
1595ee17db83SRichard Henderson             val = TEMP_VAL_REG;
1596ee17db83SRichard Henderson             break;
1597ee17db83SRichard Henderson         case TEMP_GLOBAL:
1598ee17db83SRichard Henderson             break;
1599ee17db83SRichard Henderson         case TEMP_NORMAL:
1600ee17db83SRichard Henderson             val = TEMP_VAL_DEAD;
1601ee17db83SRichard Henderson             /* fall through */
1602ee17db83SRichard Henderson         case TEMP_LOCAL:
1603e8996ee0Sbellard             ts->mem_allocated = 0;
1604ee17db83SRichard Henderson             break;
1605ee17db83SRichard Henderson         default:
1606ee17db83SRichard Henderson             g_assert_not_reached();
1607ee17db83SRichard Henderson         }
1608ee17db83SRichard Henderson         ts->val_type = val;
1609e8996ee0Sbellard     }
1610f8b2f202SRichard Henderson 
1611f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
1612c896fe29Sbellard }
1613c896fe29Sbellard 
1614f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
1615f8b2f202SRichard Henderson                                  TCGTemp *ts)
1616c896fe29Sbellard {
16171807f4c4SRichard Henderson     int idx = temp_idx(ts);
1618ac56dd48Spbrook 
1619ee17db83SRichard Henderson     switch (ts->kind) {
1620ee17db83SRichard Henderson     case TEMP_FIXED:
1621ee17db83SRichard Henderson     case TEMP_GLOBAL:
1622ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
1623ee17db83SRichard Henderson         break;
1624ee17db83SRichard Henderson     case TEMP_LOCAL:
1625641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
1626ee17db83SRichard Henderson         break;
1627ee17db83SRichard Henderson     case TEMP_NORMAL:
1628ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
1629ee17db83SRichard Henderson         break;
1630c0522136SRichard Henderson     case TEMP_CONST:
1631c0522136SRichard Henderson         switch (ts->type) {
1632c0522136SRichard Henderson         case TCG_TYPE_I32:
1633c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val);
1634c0522136SRichard Henderson             break;
1635c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32
1636c0522136SRichard Henderson         case TCG_TYPE_I64:
1637c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%" PRIx64, ts->val);
1638c0522136SRichard Henderson             break;
1639c0522136SRichard Henderson #endif
1640c0522136SRichard Henderson         case TCG_TYPE_V64:
1641c0522136SRichard Henderson         case TCG_TYPE_V128:
1642c0522136SRichard Henderson         case TCG_TYPE_V256:
1643c0522136SRichard Henderson             snprintf(buf, buf_size, "v%d$0x%" PRIx64,
1644c0522136SRichard Henderson                      64 << (ts->type - TCG_TYPE_V64), ts->val);
1645c0522136SRichard Henderson             break;
1646c0522136SRichard Henderson         default:
1647c0522136SRichard Henderson             g_assert_not_reached();
1648c0522136SRichard Henderson         }
1649c0522136SRichard Henderson         break;
1650c896fe29Sbellard     }
1651c896fe29Sbellard     return buf;
1652c896fe29Sbellard }
1653c896fe29Sbellard 
165443439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
165543439139SRichard Henderson                              int buf_size, TCGArg arg)
1656f8b2f202SRichard Henderson {
165743439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
1658f8b2f202SRichard Henderson }
1659f8b2f202SRichard Henderson 
16606e085f72SRichard Henderson /* Find helper name.  */
16616e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val)
1662e8996ee0Sbellard {
16636e085f72SRichard Henderson     const char *ret = NULL;
1664619205fdSEmilio G. Cota     if (helper_table) {
1665619205fdSEmilio G. Cota         TCGHelperInfo *info = g_hash_table_lookup(helper_table, (gpointer)val);
166672866e82SRichard Henderson         if (info) {
166772866e82SRichard Henderson             ret = info->name;
166872866e82SRichard Henderson         }
1669e8996ee0Sbellard     }
16706e085f72SRichard Henderson     return ret;
16714dc81f28Sbellard }
16724dc81f28Sbellard 
1673f48f3edeSblueswir1 static const char * const cond_name[] =
1674f48f3edeSblueswir1 {
16750aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
16760aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
1677f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
1678f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
1679f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
1680f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
1681f48f3edeSblueswir1     [TCG_COND_LE] = "le",
1682f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
1683f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
1684f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
1685f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
1686f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
1687f48f3edeSblueswir1 };
1688f48f3edeSblueswir1 
1689f713d6adSRichard Henderson static const char * const ldst_name[] =
1690f713d6adSRichard Henderson {
1691f713d6adSRichard Henderson     [MO_UB]   = "ub",
1692f713d6adSRichard Henderson     [MO_SB]   = "sb",
1693f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
1694f713d6adSRichard Henderson     [MO_LESW] = "lesw",
1695f713d6adSRichard Henderson     [MO_LEUL] = "leul",
1696f713d6adSRichard Henderson     [MO_LESL] = "lesl",
1697f713d6adSRichard Henderson     [MO_LEQ]  = "leq",
1698f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
1699f713d6adSRichard Henderson     [MO_BESW] = "besw",
1700f713d6adSRichard Henderson     [MO_BEUL] = "beul",
1701f713d6adSRichard Henderson     [MO_BESL] = "besl",
1702f713d6adSRichard Henderson     [MO_BEQ]  = "beq",
1703f713d6adSRichard Henderson };
1704f713d6adSRichard Henderson 
17051f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
170652bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY
17071f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
17081f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
17091f00b27fSSergey Sorokin #else
17101f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
17111f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
17121f00b27fSSergey Sorokin #endif
17131f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
17141f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
17151f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
17161f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
17171f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
17181f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
17191f00b27fSSergey Sorokin };
17201f00b27fSSergey Sorokin 
1721b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
1722b016486eSRichard Henderson {
1723b016486eSRichard Henderson     return (d & (d - 1)) == 0;
1724b016486eSRichard Henderson }
1725b016486eSRichard Henderson 
1726b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
1727b016486eSRichard Henderson {
1728b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
1729b016486eSRichard Henderson         return ctz32(d);
1730b016486eSRichard Henderson     } else {
1731b016486eSRichard Henderson         return ctz64(d);
1732b016486eSRichard Henderson     }
1733b016486eSRichard Henderson }
1734b016486eSRichard Henderson 
17351894f69aSRichard Henderson static void tcg_dump_ops(TCGContext *s, bool have_prefs)
1736c896fe29Sbellard {
1737c896fe29Sbellard     char buf[128];
1738c45cb8bbSRichard Henderson     TCGOp *op;
1739c896fe29Sbellard 
174015fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
1741c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
1742c45cb8bbSRichard Henderson         const TCGOpDef *def;
1743c45cb8bbSRichard Henderson         TCGOpcode c;
1744bdfb460eSRichard Henderson         int col = 0;
1745c45cb8bbSRichard Henderson 
1746c45cb8bbSRichard Henderson         c = op->opc;
1747c896fe29Sbellard         def = &tcg_op_defs[c];
1748c45cb8bbSRichard Henderson 
1749765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
1750b016486eSRichard Henderson             nb_oargs = 0;
175115fa08f8SRichard Henderson             col += qemu_log("\n ----");
17529aef40edSRichard Henderson 
17539aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
17549aef40edSRichard Henderson                 target_ulong a;
17557e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
1756efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
17577e4597d7Sbellard #else
1758efee3746SRichard Henderson                 a = op->args[i];
17597e4597d7Sbellard #endif
1760bdfb460eSRichard Henderson                 col += qemu_log(" " TARGET_FMT_lx, a);
1761eeacee4dSBlue Swirl             }
17627e4597d7Sbellard         } else if (c == INDEX_op_call) {
1763c896fe29Sbellard             /* variable number of arguments */
1764cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
1765cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
1766c896fe29Sbellard             nb_cargs = def->nb_cargs;
1767b03cce8eSbellard 
1768cf066674SRichard Henderson             /* function name, flags, out args */
1769bdfb460eSRichard Henderson             col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name,
1770efee3746SRichard Henderson                             tcg_find_helper(s, op->args[nb_oargs + nb_iargs]),
1771efee3746SRichard Henderson                             op->args[nb_oargs + nb_iargs + 1], nb_oargs);
1772b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
177343439139SRichard Henderson                 col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf),
1774efee3746SRichard Henderson                                                        op->args[i]));
1775b03cce8eSbellard             }
1776cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
1777efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
1778cf066674SRichard Henderson                 const char *t = "<dummy>";
1779cf066674SRichard Henderson                 if (arg != TCG_CALL_DUMMY_ARG) {
178043439139SRichard Henderson                     t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
1781b03cce8eSbellard                 }
1782bdfb460eSRichard Henderson                 col += qemu_log(",%s", t);
1783e8996ee0Sbellard             }
1784b03cce8eSbellard         } else {
1785bdfb460eSRichard Henderson             col += qemu_log(" %s ", def->name);
1786c45cb8bbSRichard Henderson 
1787c896fe29Sbellard             nb_oargs = def->nb_oargs;
1788c896fe29Sbellard             nb_iargs = def->nb_iargs;
1789c896fe29Sbellard             nb_cargs = def->nb_cargs;
1790c896fe29Sbellard 
1791d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
1792d2fd745fSRichard Henderson                 col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op),
1793d2fd745fSRichard Henderson                                 8 << TCGOP_VECE(op));
1794d2fd745fSRichard Henderson             }
1795d2fd745fSRichard Henderson 
1796c896fe29Sbellard             k = 0;
1797c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
1798eeacee4dSBlue Swirl                 if (k != 0) {
1799bdfb460eSRichard Henderson                     col += qemu_log(",");
1800eeacee4dSBlue Swirl                 }
180143439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
1802efee3746SRichard Henderson                                                       op->args[k++]));
1803c896fe29Sbellard             }
1804c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
1805eeacee4dSBlue Swirl                 if (k != 0) {
1806bdfb460eSRichard Henderson                     col += qemu_log(",");
1807eeacee4dSBlue Swirl                 }
180843439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
1809efee3746SRichard Henderson                                                       op->args[k++]));
1810c896fe29Sbellard             }
1811be210acbSRichard Henderson             switch (c) {
1812be210acbSRichard Henderson             case INDEX_op_brcond_i32:
1813ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
1814ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
1815be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
1816be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
1817ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
1818be210acbSRichard Henderson             case INDEX_op_setcond_i64:
1819ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
1820212be173SRichard Henderson             case INDEX_op_cmp_vec:
1821f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
1822efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
1823efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
1824efee3746SRichard Henderson                     col += qemu_log(",%s", cond_name[op->args[k++]]);
1825eeacee4dSBlue Swirl                 } else {
1826efee3746SRichard Henderson                     col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]);
1827eeacee4dSBlue Swirl                 }
1828f48f3edeSblueswir1                 i = 1;
1829be210acbSRichard Henderson                 break;
1830f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
1831f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
183207ce0b05SRichard Henderson             case INDEX_op_qemu_st8_i32:
1833f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
1834f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
183559227d5dSRichard Henderson                 {
1836efee3746SRichard Henderson                     TCGMemOpIdx oi = op->args[k++];
183714776ab5STony Nguyen                     MemOp op = get_memop(oi);
183859227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
183959227d5dSRichard Henderson 
184059c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
1841bdfb460eSRichard Henderson                         col += qemu_log(",$0x%x,%u", op, ix);
184259c4b7e8SRichard Henderson                     } else {
18431f00b27fSSergey Sorokin                         const char *s_al, *s_op;
18441f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
184559c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
1846bdfb460eSRichard Henderson                         col += qemu_log(",%s%s,%u", s_al, s_op, ix);
1847f713d6adSRichard Henderson                     }
1848f713d6adSRichard Henderson                     i = 1;
184959227d5dSRichard Henderson                 }
1850f713d6adSRichard Henderson                 break;
1851be210acbSRichard Henderson             default:
1852f48f3edeSblueswir1                 i = 0;
1853be210acbSRichard Henderson                 break;
1854be210acbSRichard Henderson             }
185551e3972cSRichard Henderson             switch (c) {
185651e3972cSRichard Henderson             case INDEX_op_set_label:
185751e3972cSRichard Henderson             case INDEX_op_br:
185851e3972cSRichard Henderson             case INDEX_op_brcond_i32:
185951e3972cSRichard Henderson             case INDEX_op_brcond_i64:
186051e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
1861efee3746SRichard Henderson                 col += qemu_log("%s$L%d", k ? "," : "",
1862efee3746SRichard Henderson                                 arg_label(op->args[k])->id);
186351e3972cSRichard Henderson                 i++, k++;
186451e3972cSRichard Henderson                 break;
186551e3972cSRichard Henderson             default:
186651e3972cSRichard Henderson                 break;
1867eeacee4dSBlue Swirl             }
186851e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
1869efee3746SRichard Henderson                 col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]);
1870bdfb460eSRichard Henderson             }
1871bdfb460eSRichard Henderson         }
1872bdfb460eSRichard Henderson 
18731894f69aSRichard Henderson         if (have_prefs || op->life) {
18747606488cSRobert Foley 
18757606488cSRobert Foley             QemuLogFile *logfile;
18767606488cSRobert Foley 
18777606488cSRobert Foley             rcu_read_lock();
1878d73415a3SStefan Hajnoczi             logfile = qatomic_rcu_read(&qemu_logfile);
18797606488cSRobert Foley             if (logfile) {
18801894f69aSRichard Henderson                 for (; col < 40; ++col) {
18817606488cSRobert Foley                     putc(' ', logfile->fd);
1882bdfb460eSRichard Henderson                 }
18831894f69aSRichard Henderson             }
18847606488cSRobert Foley             rcu_read_unlock();
18857606488cSRobert Foley         }
18861894f69aSRichard Henderson 
18871894f69aSRichard Henderson         if (op->life) {
18881894f69aSRichard Henderson             unsigned life = op->life;
1889bdfb460eSRichard Henderson 
1890bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
1891bdfb460eSRichard Henderson                 qemu_log("  sync:");
1892bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
1893bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
1894bdfb460eSRichard Henderson                         qemu_log(" %d", i);
1895bdfb460eSRichard Henderson                     }
1896bdfb460eSRichard Henderson                 }
1897bdfb460eSRichard Henderson             }
1898bdfb460eSRichard Henderson             life /= DEAD_ARG;
1899bdfb460eSRichard Henderson             if (life) {
1900bdfb460eSRichard Henderson                 qemu_log("  dead:");
1901bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
1902bdfb460eSRichard Henderson                     if (life & 1) {
1903bdfb460eSRichard Henderson                         qemu_log(" %d", i);
1904bdfb460eSRichard Henderson                     }
1905bdfb460eSRichard Henderson                 }
1906c896fe29Sbellard             }
1907b03cce8eSbellard         }
19081894f69aSRichard Henderson 
19091894f69aSRichard Henderson         if (have_prefs) {
19101894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
19111894f69aSRichard Henderson                 TCGRegSet set = op->output_pref[i];
19121894f69aSRichard Henderson 
19131894f69aSRichard Henderson                 if (i == 0) {
19141894f69aSRichard Henderson                     qemu_log("  pref=");
19151894f69aSRichard Henderson                 } else {
19161894f69aSRichard Henderson                     qemu_log(",");
19171894f69aSRichard Henderson                 }
19181894f69aSRichard Henderson                 if (set == 0) {
19191894f69aSRichard Henderson                     qemu_log("none");
19201894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
19211894f69aSRichard Henderson                     qemu_log("all");
19221894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
19231894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
19241894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
19251894f69aSRichard Henderson                     qemu_log("%s", tcg_target_reg_names[reg]);
19261894f69aSRichard Henderson #endif
19271894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
19281894f69aSRichard Henderson                     qemu_log("%#x", (uint32_t)set);
19291894f69aSRichard Henderson                 } else {
19301894f69aSRichard Henderson                     qemu_log("%#" PRIx64, (uint64_t)set);
19311894f69aSRichard Henderson                 }
19321894f69aSRichard Henderson             }
19331894f69aSRichard Henderson         }
19341894f69aSRichard Henderson 
1935eeacee4dSBlue Swirl         qemu_log("\n");
1936c896fe29Sbellard     }
1937c896fe29Sbellard }
1938c896fe29Sbellard 
1939c896fe29Sbellard /* we give more priority to constraints with less registers */
1940c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
1941c896fe29Sbellard {
194274a11790SRichard Henderson     const TCGArgConstraint *arg_ct = &def->args_ct[k];
194374a11790SRichard Henderson     int n;
1944c896fe29Sbellard 
1945bc2b17e6SRichard Henderson     if (arg_ct->oalias) {
1946c896fe29Sbellard         /* an alias is equivalent to a single register */
1947c896fe29Sbellard         n = 1;
1948c896fe29Sbellard     } else {
194974a11790SRichard Henderson         n = ctpop64(arg_ct->regs);
1950c896fe29Sbellard     }
1951c896fe29Sbellard     return TCG_TARGET_NB_REGS - n + 1;
1952c896fe29Sbellard }
1953c896fe29Sbellard 
1954c896fe29Sbellard /* sort from highest priority to lowest */
1955c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
1956c896fe29Sbellard {
195766792f90SRichard Henderson     int i, j;
195866792f90SRichard Henderson     TCGArgConstraint *a = def->args_ct;
1959c896fe29Sbellard 
196066792f90SRichard Henderson     for (i = 0; i < n; i++) {
196166792f90SRichard Henderson         a[start + i].sort_index = start + i;
196266792f90SRichard Henderson     }
196366792f90SRichard Henderson     if (n <= 1) {
1964c896fe29Sbellard         return;
196566792f90SRichard Henderson     }
1966c896fe29Sbellard     for (i = 0; i < n - 1; i++) {
1967c896fe29Sbellard         for (j = i + 1; j < n; j++) {
196866792f90SRichard Henderson             int p1 = get_constraint_priority(def, a[start + i].sort_index);
196966792f90SRichard Henderson             int p2 = get_constraint_priority(def, a[start + j].sort_index);
1970c896fe29Sbellard             if (p1 < p2) {
197166792f90SRichard Henderson                 int tmp = a[start + i].sort_index;
197266792f90SRichard Henderson                 a[start + i].sort_index = a[start + j].sort_index;
197366792f90SRichard Henderson                 a[start + j].sort_index = tmp;
1974c896fe29Sbellard             }
1975c896fe29Sbellard         }
1976c896fe29Sbellard     }
1977c896fe29Sbellard }
1978c896fe29Sbellard 
1979f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
1980c896fe29Sbellard {
1981a9751609SRichard Henderson     TCGOpcode op;
1982c896fe29Sbellard 
1983f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
1984f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
1985f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
1986069ea736SRichard Henderson         int i, nb_args;
1987f69d277eSRichard Henderson 
1988f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
1989f69d277eSRichard Henderson             continue;
1990f69d277eSRichard Henderson         }
1991f69d277eSRichard Henderson 
1992c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
1993f69d277eSRichard Henderson         if (nb_args == 0) {
1994f69d277eSRichard Henderson             continue;
1995f69d277eSRichard Henderson         }
1996f69d277eSRichard Henderson 
19974c22e840SRichard Henderson         /*
19984c22e840SRichard Henderson          * Macro magic should make it impossible, but double-check that
19994c22e840SRichard Henderson          * the array index is in range.  Since the signness of an enum
20004c22e840SRichard Henderson          * is implementation defined, force the result to unsigned.
20014c22e840SRichard Henderson          */
20024c22e840SRichard Henderson         unsigned con_set = tcg_target_op_def(op);
20034c22e840SRichard Henderson         tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets));
20044c22e840SRichard Henderson         tdefs = &constraint_sets[con_set];
2005f69d277eSRichard Henderson 
2006c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2007f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
2008f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2009eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2010f69d277eSRichard Henderson 
201117280ff4SRichard Henderson             while (*ct_str != '\0') {
201217280ff4SRichard Henderson                 switch(*ct_str) {
201317280ff4SRichard Henderson                 case '0' ... '9':
201417280ff4SRichard Henderson                     {
201517280ff4SRichard Henderson                         int oarg = *ct_str - '0';
201617280ff4SRichard Henderson                         tcg_debug_assert(ct_str == tdefs->args_ct_str[i]);
2017eabb7b91SAurelien Jarno                         tcg_debug_assert(oarg < def->nb_oargs);
201874a11790SRichard Henderson                         tcg_debug_assert(def->args_ct[oarg].regs != 0);
2019c896fe29Sbellard                         def->args_ct[i] = def->args_ct[oarg];
2020bc2b17e6SRichard Henderson                         /* The output sets oalias.  */
2021bc2b17e6SRichard Henderson                         def->args_ct[oarg].oalias = true;
20225ff9d6a4Sbellard                         def->args_ct[oarg].alias_index = i;
2023bc2b17e6SRichard Henderson                         /* The input sets ialias. */
2024bc2b17e6SRichard Henderson                         def->args_ct[i].ialias = true;
20255ff9d6a4Sbellard                         def->args_ct[i].alias_index = oarg;
202617280ff4SRichard Henderson                     }
202717280ff4SRichard Henderson                     ct_str++;
2028c896fe29Sbellard                     break;
202982790a87SRichard Henderson                 case '&':
2030bc2b17e6SRichard Henderson                     def->args_ct[i].newreg = true;
203182790a87SRichard Henderson                     ct_str++;
203282790a87SRichard Henderson                     break;
2033c896fe29Sbellard                 case 'i':
2034c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2035c896fe29Sbellard                     ct_str++;
2036c896fe29Sbellard                     break;
2037358b4923SRichard Henderson 
2038358b4923SRichard Henderson                 /* Include all of the target-specific constraints. */
2039358b4923SRichard Henderson 
2040358b4923SRichard Henderson #undef CONST
2041358b4923SRichard Henderson #define CONST(CASE, MASK) \
2042358b4923SRichard Henderson     case CASE: def->args_ct[i].ct |= MASK; ct_str++; break;
2043358b4923SRichard Henderson #define REGS(CASE, MASK) \
2044358b4923SRichard Henderson     case CASE: def->args_ct[i].regs |= MASK; ct_str++; break;
2045358b4923SRichard Henderson 
2046358b4923SRichard Henderson #include "tcg-target-con-str.h"
2047358b4923SRichard Henderson 
2048358b4923SRichard Henderson #undef REGS
2049358b4923SRichard Henderson #undef CONST
2050c896fe29Sbellard                 default:
2051358b4923SRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2052358b4923SRichard Henderson                     g_assert_not_reached();
2053358b4923SRichard Henderson                 }
2054c896fe29Sbellard             }
2055c896fe29Sbellard         }
2056c896fe29Sbellard 
2057c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2058eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2059c68aaa18SStefan Weil 
2060c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
2061c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
2062c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
2063c896fe29Sbellard     }
2064c896fe29Sbellard }
2065c896fe29Sbellard 
20660c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
20670c627cdcSRichard Henderson {
2068d88a117eSRichard Henderson     TCGLabel *label;
2069d88a117eSRichard Henderson 
2070d88a117eSRichard Henderson     switch (op->opc) {
2071d88a117eSRichard Henderson     case INDEX_op_br:
2072d88a117eSRichard Henderson         label = arg_label(op->args[0]);
2073d88a117eSRichard Henderson         label->refs--;
2074d88a117eSRichard Henderson         break;
2075d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
2076d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
2077d88a117eSRichard Henderson         label = arg_label(op->args[3]);
2078d88a117eSRichard Henderson         label->refs--;
2079d88a117eSRichard Henderson         break;
2080d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
2081d88a117eSRichard Henderson         label = arg_label(op->args[5]);
2082d88a117eSRichard Henderson         label->refs--;
2083d88a117eSRichard Henderson         break;
2084d88a117eSRichard Henderson     default:
2085d88a117eSRichard Henderson         break;
2086d88a117eSRichard Henderson     }
2087d88a117eSRichard Henderson 
208815fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
208915fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
2090abebf925SRichard Henderson     s->nb_ops--;
20910c627cdcSRichard Henderson 
20920c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
2093d73415a3SStefan Hajnoczi     qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
20940c627cdcSRichard Henderson #endif
20950c627cdcSRichard Henderson }
20960c627cdcSRichard Henderson 
2097a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op)
2098a80cdd31SRichard Henderson {
2099a80cdd31SRichard Henderson     TCGContext *s = tcg_ctx;
2100a80cdd31SRichard Henderson 
2101a80cdd31SRichard Henderson     while (true) {
2102a80cdd31SRichard Henderson         TCGOp *last = tcg_last_op();
2103a80cdd31SRichard Henderson         if (last == op) {
2104a80cdd31SRichard Henderson             return;
2105a80cdd31SRichard Henderson         }
2106a80cdd31SRichard Henderson         tcg_op_remove(s, last);
2107a80cdd31SRichard Henderson     }
2108a80cdd31SRichard Henderson }
2109a80cdd31SRichard Henderson 
211015fa08f8SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc)
211115fa08f8SRichard Henderson {
211215fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
211315fa08f8SRichard Henderson     TCGOp *op;
211415fa08f8SRichard Henderson 
211515fa08f8SRichard Henderson     if (likely(QTAILQ_EMPTY(&s->free_ops))) {
211615fa08f8SRichard Henderson         op = tcg_malloc(sizeof(TCGOp));
211715fa08f8SRichard Henderson     } else {
211815fa08f8SRichard Henderson         op = QTAILQ_FIRST(&s->free_ops);
211915fa08f8SRichard Henderson         QTAILQ_REMOVE(&s->free_ops, op, link);
212015fa08f8SRichard Henderson     }
212115fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
212215fa08f8SRichard Henderson     op->opc = opc;
2123abebf925SRichard Henderson     s->nb_ops++;
212415fa08f8SRichard Henderson 
212515fa08f8SRichard Henderson     return op;
212615fa08f8SRichard Henderson }
212715fa08f8SRichard Henderson 
212815fa08f8SRichard Henderson TCGOp *tcg_emit_op(TCGOpcode opc)
212915fa08f8SRichard Henderson {
213015fa08f8SRichard Henderson     TCGOp *op = tcg_op_alloc(opc);
213115fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
213215fa08f8SRichard Henderson     return op;
213315fa08f8SRichard Henderson }
213415fa08f8SRichard Henderson 
2135ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
21365a18407fSRichard Henderson {
213715fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
213815fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
21395a18407fSRichard Henderson     return new_op;
21405a18407fSRichard Henderson }
21415a18407fSRichard Henderson 
2142ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
21435a18407fSRichard Henderson {
214415fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
214515fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
21465a18407fSRichard Henderson     return new_op;
21475a18407fSRichard Henderson }
21485a18407fSRichard Henderson 
2149b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
2150b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s)
2151b4fc67c7SRichard Henderson {
2152b4fc67c7SRichard Henderson     TCGOp *op, *op_next;
2153b4fc67c7SRichard Henderson     bool dead = false;
2154b4fc67c7SRichard Henderson 
2155b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
2156b4fc67c7SRichard Henderson         bool remove = dead;
2157b4fc67c7SRichard Henderson         TCGLabel *label;
2158b4fc67c7SRichard Henderson         int call_flags;
2159b4fc67c7SRichard Henderson 
2160b4fc67c7SRichard Henderson         switch (op->opc) {
2161b4fc67c7SRichard Henderson         case INDEX_op_set_label:
2162b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
2163b4fc67c7SRichard Henderson             if (label->refs == 0) {
2164b4fc67c7SRichard Henderson                 /*
2165b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
2166b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
2167b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
2168b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
2169b4fc67c7SRichard Henderson                  * little to be gained by iterating.
2170b4fc67c7SRichard Henderson                  */
2171b4fc67c7SRichard Henderson                 remove = true;
2172b4fc67c7SRichard Henderson             } else {
2173b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
2174b4fc67c7SRichard Henderson                 dead = false;
2175b4fc67c7SRichard Henderson                 remove = false;
2176b4fc67c7SRichard Henderson 
2177b4fc67c7SRichard Henderson                 /*
2178b4fc67c7SRichard Henderson                  * Optimization can fold conditional branches to unconditional.
2179b4fc67c7SRichard Henderson                  * If we find a label with one reference which is preceded by
2180b4fc67c7SRichard Henderson                  * an unconditional branch to it, remove both.  This needed to
2181b4fc67c7SRichard Henderson                  * wait until the dead code in between them was removed.
2182b4fc67c7SRichard Henderson                  */
2183b4fc67c7SRichard Henderson                 if (label->refs == 1) {
2184eae3eb3eSPaolo Bonzini                     TCGOp *op_prev = QTAILQ_PREV(op, link);
2185b4fc67c7SRichard Henderson                     if (op_prev->opc == INDEX_op_br &&
2186b4fc67c7SRichard Henderson                         label == arg_label(op_prev->args[0])) {
2187b4fc67c7SRichard Henderson                         tcg_op_remove(s, op_prev);
2188b4fc67c7SRichard Henderson                         remove = true;
2189b4fc67c7SRichard Henderson                     }
2190b4fc67c7SRichard Henderson                 }
2191b4fc67c7SRichard Henderson             }
2192b4fc67c7SRichard Henderson             break;
2193b4fc67c7SRichard Henderson 
2194b4fc67c7SRichard Henderson         case INDEX_op_br:
2195b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
2196b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
2197b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
2198b4fc67c7SRichard Henderson             dead = true;
2199b4fc67c7SRichard Henderson             break;
2200b4fc67c7SRichard Henderson 
2201b4fc67c7SRichard Henderson         case INDEX_op_call:
2202b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
2203b4fc67c7SRichard Henderson             call_flags = op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1];
2204b4fc67c7SRichard Henderson             if (call_flags & TCG_CALL_NO_RETURN) {
2205b4fc67c7SRichard Henderson                 dead = true;
2206b4fc67c7SRichard Henderson             }
2207b4fc67c7SRichard Henderson             break;
2208b4fc67c7SRichard Henderson 
2209b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
2210b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
2211b4fc67c7SRichard Henderson             remove = false;
2212b4fc67c7SRichard Henderson             break;
2213b4fc67c7SRichard Henderson 
2214b4fc67c7SRichard Henderson         default:
2215b4fc67c7SRichard Henderson             break;
2216b4fc67c7SRichard Henderson         }
2217b4fc67c7SRichard Henderson 
2218b4fc67c7SRichard Henderson         if (remove) {
2219b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
2220b4fc67c7SRichard Henderson         }
2221b4fc67c7SRichard Henderson     }
2222b4fc67c7SRichard Henderson }
2223b4fc67c7SRichard Henderson 
2224c70fbf0aSRichard Henderson #define TS_DEAD  1
2225c70fbf0aSRichard Henderson #define TS_MEM   2
2226c70fbf0aSRichard Henderson 
22275a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
22285a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
22295a18407fSRichard Henderson 
223025f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
223125f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
223225f49c5fSRichard Henderson {
223325f49c5fSRichard Henderson     return ts->state_ptr;
223425f49c5fSRichard Henderson }
223525f49c5fSRichard Henderson 
223625f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
223725f49c5fSRichard Henderson  * maximal regset for its type.
223825f49c5fSRichard Henderson  */
223925f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
224025f49c5fSRichard Henderson {
224125f49c5fSRichard Henderson     *la_temp_pref(ts)
224225f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
224325f49c5fSRichard Henderson }
224425f49c5fSRichard Henderson 
22459c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
22469c43b68dSAurelien Jarno    should be in memory. */
22472616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
2248c896fe29Sbellard {
2249b83eabeaSRichard Henderson     int i;
2250b83eabeaSRichard Henderson 
2251b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2252b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
225325f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2254b83eabeaSRichard Henderson     }
2255b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2256b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
225725f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2258b83eabeaSRichard Henderson     }
2259c896fe29Sbellard }
2260c896fe29Sbellard 
22619c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
22629c43b68dSAurelien Jarno    and local temps should be in memory. */
22632616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
2264641d5fbeSbellard {
2265b83eabeaSRichard Henderson     int i;
2266641d5fbeSbellard 
2267ee17db83SRichard Henderson     for (i = 0; i < nt; ++i) {
2268ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2269ee17db83SRichard Henderson         int state;
2270ee17db83SRichard Henderson 
2271ee17db83SRichard Henderson         switch (ts->kind) {
2272ee17db83SRichard Henderson         case TEMP_FIXED:
2273ee17db83SRichard Henderson         case TEMP_GLOBAL:
2274ee17db83SRichard Henderson         case TEMP_LOCAL:
2275ee17db83SRichard Henderson             state = TS_DEAD | TS_MEM;
2276ee17db83SRichard Henderson             break;
2277ee17db83SRichard Henderson         case TEMP_NORMAL:
2278c0522136SRichard Henderson         case TEMP_CONST:
2279ee17db83SRichard Henderson             state = TS_DEAD;
2280ee17db83SRichard Henderson             break;
2281ee17db83SRichard Henderson         default:
2282ee17db83SRichard Henderson             g_assert_not_reached();
2283c70fbf0aSRichard Henderson         }
2284ee17db83SRichard Henderson         ts->state = state;
2285ee17db83SRichard Henderson         la_reset_pref(ts);
2286641d5fbeSbellard     }
2287641d5fbeSbellard }
2288641d5fbeSbellard 
2289f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
2290f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
2291f65a061cSRichard Henderson {
2292f65a061cSRichard Henderson     int i;
2293f65a061cSRichard Henderson 
2294f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
229525f49c5fSRichard Henderson         int state = s->temps[i].state;
229625f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
229725f49c5fSRichard Henderson         if (state == TS_DEAD) {
229825f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
229925f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
230025f49c5fSRichard Henderson         }
2301f65a061cSRichard Henderson     }
2302f65a061cSRichard Henderson }
2303f65a061cSRichard Henderson 
2304b4cb76e6SRichard Henderson /*
2305b4cb76e6SRichard Henderson  * liveness analysis: conditional branch: all temps are dead,
2306b4cb76e6SRichard Henderson  * globals and local temps should be synced.
2307b4cb76e6SRichard Henderson  */
2308b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
2309b4cb76e6SRichard Henderson {
2310b4cb76e6SRichard Henderson     la_global_sync(s, ng);
2311b4cb76e6SRichard Henderson 
2312b4cb76e6SRichard Henderson     for (int i = ng; i < nt; ++i) {
2313c0522136SRichard Henderson         TCGTemp *ts = &s->temps[i];
2314c0522136SRichard Henderson         int state;
2315c0522136SRichard Henderson 
2316c0522136SRichard Henderson         switch (ts->kind) {
2317c0522136SRichard Henderson         case TEMP_LOCAL:
2318c0522136SRichard Henderson             state = ts->state;
2319c0522136SRichard Henderson             ts->state = state | TS_MEM;
2320b4cb76e6SRichard Henderson             if (state != TS_DEAD) {
2321b4cb76e6SRichard Henderson                 continue;
2322b4cb76e6SRichard Henderson             }
2323c0522136SRichard Henderson             break;
2324c0522136SRichard Henderson         case TEMP_NORMAL:
2325b4cb76e6SRichard Henderson             s->temps[i].state = TS_DEAD;
2326c0522136SRichard Henderson             break;
2327c0522136SRichard Henderson         case TEMP_CONST:
2328c0522136SRichard Henderson             continue;
2329c0522136SRichard Henderson         default:
2330c0522136SRichard Henderson             g_assert_not_reached();
2331b4cb76e6SRichard Henderson         }
2332b4cb76e6SRichard Henderson         la_reset_pref(&s->temps[i]);
2333b4cb76e6SRichard Henderson     }
2334b4cb76e6SRichard Henderson }
2335b4cb76e6SRichard Henderson 
2336f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
2337f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
2338f65a061cSRichard Henderson {
2339f65a061cSRichard Henderson     int i;
2340f65a061cSRichard Henderson 
2341f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
2342f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
234325f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
234425f49c5fSRichard Henderson     }
234525f49c5fSRichard Henderson }
234625f49c5fSRichard Henderson 
234725f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
234825f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
234925f49c5fSRichard Henderson {
235025f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
235125f49c5fSRichard Henderson     int i;
235225f49c5fSRichard Henderson 
235325f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
235425f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
235525f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
235625f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
235725f49c5fSRichard Henderson             TCGRegSet set = *pset;
235825f49c5fSRichard Henderson 
235925f49c5fSRichard Henderson             set &= mask;
236025f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
236125f49c5fSRichard Henderson             if (set == 0) {
236225f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
236325f49c5fSRichard Henderson             }
236425f49c5fSRichard Henderson             *pset = set;
236525f49c5fSRichard Henderson         }
2366f65a061cSRichard Henderson     }
2367f65a061cSRichard Henderson }
2368f65a061cSRichard Henderson 
2369a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
2370c896fe29Sbellard    given input arguments is dead. Instructions updating dead
2371c896fe29Sbellard    temporaries are removed. */
2372b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s)
2373c896fe29Sbellard {
2374c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
23752616c808SRichard Henderson     int nb_temps = s->nb_temps;
237615fa08f8SRichard Henderson     TCGOp *op, *op_prev;
237725f49c5fSRichard Henderson     TCGRegSet *prefs;
237825f49c5fSRichard Henderson     int i;
237925f49c5fSRichard Henderson 
238025f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
238125f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
238225f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
238325f49c5fSRichard Henderson     }
2384c896fe29Sbellard 
2385ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
23862616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
2387c896fe29Sbellard 
2388eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
238925f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
2390c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
2391c45cb8bbSRichard Henderson         bool have_opc_new2;
2392a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
239325f49c5fSRichard Henderson         TCGTemp *ts;
2394c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2395c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2396c45cb8bbSRichard Henderson 
2397c45cb8bbSRichard Henderson         switch (opc) {
2398c896fe29Sbellard         case INDEX_op_call:
2399c6e113f5Sbellard             {
2400c6e113f5Sbellard                 int call_flags;
240125f49c5fSRichard Henderson                 int nb_call_regs;
2402c6e113f5Sbellard 
2403cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
2404cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
2405efee3746SRichard Henderson                 call_flags = op->args[nb_oargs + nb_iargs + 1];
2406c6e113f5Sbellard 
2407c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
240878505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
2409c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
241025f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
241125f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
2412c6e113f5Sbellard                             goto do_not_remove_call;
2413c6e113f5Sbellard                         }
24149c43b68dSAurelien Jarno                     }
2415c45cb8bbSRichard Henderson                     goto do_remove;
2416152c35aaSRichard Henderson                 }
2417c6e113f5Sbellard             do_not_remove_call:
2418c896fe29Sbellard 
241925f49c5fSRichard Henderson                 /* Output args are dead.  */
2420c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
242125f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
242225f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
2423a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
24246b64b624SAurelien Jarno                     }
242525f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
2426a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
24279c43b68dSAurelien Jarno                     }
242825f49c5fSRichard Henderson                     ts->state = TS_DEAD;
242925f49c5fSRichard Henderson                     la_reset_pref(ts);
243025f49c5fSRichard Henderson 
243125f49c5fSRichard Henderson                     /* Not used -- it will be tcg_target_call_oarg_regs[i].  */
243225f49c5fSRichard Henderson                     op->output_pref[i] = 0;
2433c896fe29Sbellard                 }
2434c896fe29Sbellard 
243578505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
243678505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
2437f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
2438c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
2439f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
2440b9c18f56Saurel32                 }
2441c896fe29Sbellard 
244225f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
2443866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
244425f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
244525f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
2446a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
2447c896fe29Sbellard                     }
2448c896fe29Sbellard                 }
244925f49c5fSRichard Henderson 
245025f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
245125f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
245225f49c5fSRichard Henderson 
245325f49c5fSRichard Henderson                 nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
245425f49c5fSRichard Henderson 
245525f49c5fSRichard Henderson                 /* Input arguments are live for preceding opcodes.  */
245625f49c5fSRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
245725f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
245825f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
245925f49c5fSRichard Henderson                         /* For those arguments that die, and will be allocated
246025f49c5fSRichard Henderson                          * in registers, clear the register set for that arg,
246125f49c5fSRichard Henderson                          * to be filled in below.  For args that will be on
246225f49c5fSRichard Henderson                          * the stack, reset to any available reg.
246325f49c5fSRichard Henderson                          */
246425f49c5fSRichard Henderson                         *la_temp_pref(ts)
246525f49c5fSRichard Henderson                             = (i < nb_call_regs ? 0 :
246625f49c5fSRichard Henderson                                tcg_target_available_regs[ts->type]);
246725f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
246825f49c5fSRichard Henderson                     }
246925f49c5fSRichard Henderson                 }
247025f49c5fSRichard Henderson 
247125f49c5fSRichard Henderson                 /* For each input argument, add its input register to prefs.
247225f49c5fSRichard Henderson                    If a temp is used once, this produces a single set bit.  */
247325f49c5fSRichard Henderson                 for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) {
247425f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
247525f49c5fSRichard Henderson                     if (ts) {
247625f49c5fSRichard Henderson                         tcg_regset_set_reg(*la_temp_pref(ts),
247725f49c5fSRichard Henderson                                            tcg_target_call_iarg_regs[i]);
2478c70fbf0aSRichard Henderson                     }
2479c19f47bfSAurelien Jarno                 }
2480c6e113f5Sbellard             }
2481c896fe29Sbellard             break;
2482765b842aSRichard Henderson         case INDEX_op_insn_start:
2483c896fe29Sbellard             break;
24845ff9d6a4Sbellard         case INDEX_op_discard:
24855ff9d6a4Sbellard             /* mark the temporary as dead */
248625f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
248725f49c5fSRichard Henderson             ts->state = TS_DEAD;
248825f49c5fSRichard Henderson             la_reset_pref(ts);
24895ff9d6a4Sbellard             break;
24901305c451SRichard Henderson 
24911305c451SRichard Henderson         case INDEX_op_add2_i32:
2492c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
2493f1fae40cSRichard Henderson             goto do_addsub2;
24941305c451SRichard Henderson         case INDEX_op_sub2_i32:
2495c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
2496f1fae40cSRichard Henderson             goto do_addsub2;
2497f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
2498c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
2499f1fae40cSRichard Henderson             goto do_addsub2;
2500f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
2501c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
2502f1fae40cSRichard Henderson         do_addsub2:
25031305c451SRichard Henderson             nb_iargs = 4;
25041305c451SRichard Henderson             nb_oargs = 2;
25051305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
25061305c451SRichard Henderson                the low part.  The result can be optimized to a simple
25071305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
25081305c451SRichard Henderson                cpu mode is set to 32 bit.  */
2509b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2510b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
25111305c451SRichard Henderson                     goto do_remove;
25121305c451SRichard Henderson                 }
2513c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
2514c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
2515c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2516efee3746SRichard Henderson                 op->args[1] = op->args[2];
2517efee3746SRichard Henderson                 op->args[2] = op->args[4];
25181305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
25191305c451SRichard Henderson                 nb_iargs = 2;
25201305c451SRichard Henderson                 nb_oargs = 1;
25211305c451SRichard Henderson             }
25221305c451SRichard Henderson             goto do_not_remove;
25231305c451SRichard Henderson 
25241414968aSRichard Henderson         case INDEX_op_mulu2_i32:
2525c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2526c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
2527c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
252803271524SRichard Henderson             goto do_mul2;
2529f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
2530c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2531c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
2532c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
2533f1fae40cSRichard Henderson             goto do_mul2;
2534f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
2535c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2536c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
2537c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
253803271524SRichard Henderson             goto do_mul2;
2539f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
2540c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2541c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
2542c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
254303271524SRichard Henderson             goto do_mul2;
2544f1fae40cSRichard Henderson         do_mul2:
25451414968aSRichard Henderson             nb_iargs = 2;
25461414968aSRichard Henderson             nb_oargs = 2;
2547b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2548b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
254903271524SRichard Henderson                     /* Both parts of the operation are dead.  */
25501414968aSRichard Henderson                     goto do_remove;
25511414968aSRichard Henderson                 }
255203271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
2553c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2554efee3746SRichard Henderson                 op->args[1] = op->args[2];
2555efee3746SRichard Henderson                 op->args[2] = op->args[3];
2556b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
255703271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
2558c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
2559efee3746SRichard Henderson                 op->args[0] = op->args[1];
2560efee3746SRichard Henderson                 op->args[1] = op->args[2];
2561efee3746SRichard Henderson                 op->args[2] = op->args[3];
256203271524SRichard Henderson             } else {
256303271524SRichard Henderson                 goto do_not_remove;
256403271524SRichard Henderson             }
256503271524SRichard Henderson             /* Mark the single-word operation live.  */
25661414968aSRichard Henderson             nb_oargs = 1;
25671414968aSRichard Henderson             goto do_not_remove;
25681414968aSRichard Henderson 
2569c896fe29Sbellard         default:
25701305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
2571c896fe29Sbellard             nb_iargs = def->nb_iargs;
2572c896fe29Sbellard             nb_oargs = def->nb_oargs;
2573c896fe29Sbellard 
2574c896fe29Sbellard             /* Test if the operation can be removed because all
25755ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
25765ff9d6a4Sbellard                implies side effects */
25775ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
2578c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
2579b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
2580c896fe29Sbellard                         goto do_not_remove;
2581c896fe29Sbellard                     }
25829c43b68dSAurelien Jarno                 }
2583152c35aaSRichard Henderson                 goto do_remove;
2584152c35aaSRichard Henderson             }
2585152c35aaSRichard Henderson             goto do_not_remove;
2586152c35aaSRichard Henderson 
25871305c451SRichard Henderson         do_remove:
25880c627cdcSRichard Henderson             tcg_op_remove(s, op);
2589152c35aaSRichard Henderson             break;
2590152c35aaSRichard Henderson 
2591c896fe29Sbellard         do_not_remove:
2592c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
259325f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
259425f49c5fSRichard Henderson 
259525f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
259625f49c5fSRichard Henderson                 op->output_pref[i] = *la_temp_pref(ts);
259725f49c5fSRichard Henderson 
259825f49c5fSRichard Henderson                 /* Output args are dead.  */
259925f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2600a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
26016b64b624SAurelien Jarno                 }
260225f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
2603a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
26049c43b68dSAurelien Jarno                 }
260525f49c5fSRichard Henderson                 ts->state = TS_DEAD;
260625f49c5fSRichard Henderson                 la_reset_pref(ts);
2607c896fe29Sbellard             }
2608c896fe29Sbellard 
260925f49c5fSRichard Henderson             /* If end of basic block, update.  */
2610ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
2611ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
2612b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_COND_BRANCH) {
2613b4cb76e6SRichard Henderson                 la_bb_sync(s, nb_globals, nb_temps);
2614ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
26152616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
26163d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
2617f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
261825f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
261925f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
262025f49c5fSRichard Henderson                 }
2621c896fe29Sbellard             }
2622c896fe29Sbellard 
262325f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
2624866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
262525f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
262625f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2627a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
2628c896fe29Sbellard                 }
2629c19f47bfSAurelien Jarno             }
263025f49c5fSRichard Henderson 
263125f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
2632c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
263325f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
263425f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
263525f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
263625f49c5fSRichard Henderson                        all regs for the type.  */
263725f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
263825f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
263925f49c5fSRichard Henderson                 }
264025f49c5fSRichard Henderson             }
264125f49c5fSRichard Henderson 
264225f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
264325f49c5fSRichard Henderson             switch (opc) {
264425f49c5fSRichard Henderson             case INDEX_op_mov_i32:
264525f49c5fSRichard Henderson             case INDEX_op_mov_i64:
264625f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
264725f49c5fSRichard Henderson                    have proper constraints.  That said, special case
264825f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
264925f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
265025f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
265125f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
265225f49c5fSRichard Henderson                 }
265325f49c5fSRichard Henderson                 break;
265425f49c5fSRichard Henderson 
265525f49c5fSRichard Henderson             default:
265625f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
265725f49c5fSRichard Henderson                     const TCGArgConstraint *ct = &def->args_ct[i];
265825f49c5fSRichard Henderson                     TCGRegSet set, *pset;
265925f49c5fSRichard Henderson 
266025f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
266125f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
266225f49c5fSRichard Henderson                     set = *pset;
266325f49c5fSRichard Henderson 
26649be0d080SRichard Henderson                     set &= ct->regs;
2665bc2b17e6SRichard Henderson                     if (ct->ialias) {
266625f49c5fSRichard Henderson                         set &= op->output_pref[ct->alias_index];
266725f49c5fSRichard Henderson                     }
266825f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
266925f49c5fSRichard Henderson                     if (set == 0) {
26709be0d080SRichard Henderson                         set = ct->regs;
267125f49c5fSRichard Henderson                     }
267225f49c5fSRichard Henderson                     *pset = set;
267325f49c5fSRichard Henderson                 }
267425f49c5fSRichard Henderson                 break;
2675c896fe29Sbellard             }
2676c896fe29Sbellard             break;
2677c896fe29Sbellard         }
2678bee158cbSRichard Henderson         op->life = arg_life;
2679c896fe29Sbellard     }
26801ff0a2c5SEvgeny Voevodin }
2681c896fe29Sbellard 
26825a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
2683b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s)
26845a18407fSRichard Henderson {
26855a18407fSRichard Henderson     int nb_globals = s->nb_globals;
268615fa08f8SRichard Henderson     int nb_temps, i;
26875a18407fSRichard Henderson     bool changes = false;
268815fa08f8SRichard Henderson     TCGOp *op, *op_next;
26895a18407fSRichard Henderson 
26905a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
26915a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
26925a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
26935a18407fSRichard Henderson         if (its->indirect_reg) {
26945a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
26955a18407fSRichard Henderson             dts->type = its->type;
26965a18407fSRichard Henderson             dts->base_type = its->base_type;
2697b83eabeaSRichard Henderson             its->state_ptr = dts;
2698b83eabeaSRichard Henderson         } else {
2699b83eabeaSRichard Henderson             its->state_ptr = NULL;
27005a18407fSRichard Henderson         }
2701b83eabeaSRichard Henderson         /* All globals begin dead.  */
2702b83eabeaSRichard Henderson         its->state = TS_DEAD;
27035a18407fSRichard Henderson     }
2704b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
2705b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
2706b83eabeaSRichard Henderson         its->state_ptr = NULL;
2707b83eabeaSRichard Henderson         its->state = TS_DEAD;
2708b83eabeaSRichard Henderson     }
27095a18407fSRichard Henderson 
271015fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
27115a18407fSRichard Henderson         TCGOpcode opc = op->opc;
27125a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
27135a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
27145a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
2715b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
27165a18407fSRichard Henderson 
27175a18407fSRichard Henderson         if (opc == INDEX_op_call) {
2718cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2719cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2720efee3746SRichard Henderson             call_flags = op->args[nb_oargs + nb_iargs + 1];
27215a18407fSRichard Henderson         } else {
27225a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
27235a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
27245a18407fSRichard Henderson 
27255a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
2726b4cb76e6SRichard Henderson             if (def->flags & TCG_OPF_COND_BRANCH) {
2727b4cb76e6SRichard Henderson                 /* Like reading globals: sync_globals */
2728b4cb76e6SRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
2729b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
27305a18407fSRichard Henderson                 /* Like writing globals: save_globals */
27315a18407fSRichard Henderson                 call_flags = 0;
27325a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
27335a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
27345a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
27355a18407fSRichard Henderson             } else {
27365a18407fSRichard Henderson                 /* No effect on globals.  */
27375a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
27385a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
27395a18407fSRichard Henderson             }
27405a18407fSRichard Henderson         }
27415a18407fSRichard Henderson 
27425a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
27435a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2744b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2745b83eabeaSRichard Henderson             if (arg_ts) {
2746b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
2747b83eabeaSRichard Henderson                 if (dir_ts && arg_ts->state == TS_DEAD) {
2748b83eabeaSRichard Henderson                     TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
27495a18407fSRichard Henderson                                       ? INDEX_op_ld_i32
27505a18407fSRichard Henderson                                       : INDEX_op_ld_i64);
2751ac1043f6SEmilio G. Cota                     TCGOp *lop = tcg_op_insert_before(s, op, lopc);
27525a18407fSRichard Henderson 
2753b83eabeaSRichard Henderson                     lop->args[0] = temp_arg(dir_ts);
2754b83eabeaSRichard Henderson                     lop->args[1] = temp_arg(arg_ts->mem_base);
2755b83eabeaSRichard Henderson                     lop->args[2] = arg_ts->mem_offset;
27565a18407fSRichard Henderson 
27575a18407fSRichard Henderson                     /* Loaded, but synced with memory.  */
2758b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
27595a18407fSRichard Henderson                 }
27605a18407fSRichard Henderson             }
27615a18407fSRichard Henderson         }
27625a18407fSRichard Henderson 
27635a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
27645a18407fSRichard Henderson            No action is required except keeping temp_state up to date
27655a18407fSRichard Henderson            so that we reload when needed.  */
27665a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2767b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2768b83eabeaSRichard Henderson             if (arg_ts) {
2769b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
2770b83eabeaSRichard Henderson                 if (dir_ts) {
2771b83eabeaSRichard Henderson                     op->args[i] = temp_arg(dir_ts);
27725a18407fSRichard Henderson                     changes = true;
27735a18407fSRichard Henderson                     if (IS_DEAD_ARG(i)) {
2774b83eabeaSRichard Henderson                         arg_ts->state = TS_DEAD;
27755a18407fSRichard Henderson                     }
27765a18407fSRichard Henderson                 }
27775a18407fSRichard Henderson             }
27785a18407fSRichard Henderson         }
27795a18407fSRichard Henderson 
27805a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
27815a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
27825a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
27835a18407fSRichard Henderson             /* Nothing to do */
27845a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
27855a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
27865a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
27875a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
2788b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
2789b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
2790b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
27915a18407fSRichard Henderson             }
27925a18407fSRichard Henderson         } else {
27935a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
27945a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
27955a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
2796b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
2797b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
2798b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
27995a18407fSRichard Henderson             }
28005a18407fSRichard Henderson         }
28015a18407fSRichard Henderson 
28025a18407fSRichard Henderson         /* Outputs become available.  */
280361f15c48SRichard Henderson         if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) {
280461f15c48SRichard Henderson             arg_ts = arg_temp(op->args[0]);
280561f15c48SRichard Henderson             dir_ts = arg_ts->state_ptr;
280661f15c48SRichard Henderson             if (dir_ts) {
280761f15c48SRichard Henderson                 op->args[0] = temp_arg(dir_ts);
280861f15c48SRichard Henderson                 changes = true;
280961f15c48SRichard Henderson 
281061f15c48SRichard Henderson                 /* The output is now live and modified.  */
281161f15c48SRichard Henderson                 arg_ts->state = 0;
281261f15c48SRichard Henderson 
281361f15c48SRichard Henderson                 if (NEED_SYNC_ARG(0)) {
281461f15c48SRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
281561f15c48SRichard Henderson                                       ? INDEX_op_st_i32
281661f15c48SRichard Henderson                                       : INDEX_op_st_i64);
281761f15c48SRichard Henderson                     TCGOp *sop = tcg_op_insert_after(s, op, sopc);
281861f15c48SRichard Henderson                     TCGTemp *out_ts = dir_ts;
281961f15c48SRichard Henderson 
282061f15c48SRichard Henderson                     if (IS_DEAD_ARG(0)) {
282161f15c48SRichard Henderson                         out_ts = arg_temp(op->args[1]);
282261f15c48SRichard Henderson                         arg_ts->state = TS_DEAD;
282361f15c48SRichard Henderson                         tcg_op_remove(s, op);
282461f15c48SRichard Henderson                     } else {
282561f15c48SRichard Henderson                         arg_ts->state = TS_MEM;
282661f15c48SRichard Henderson                     }
282761f15c48SRichard Henderson 
282861f15c48SRichard Henderson                     sop->args[0] = temp_arg(out_ts);
282961f15c48SRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
283061f15c48SRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
283161f15c48SRichard Henderson                 } else {
283261f15c48SRichard Henderson                     tcg_debug_assert(!IS_DEAD_ARG(0));
283361f15c48SRichard Henderson                 }
283461f15c48SRichard Henderson             }
283561f15c48SRichard Henderson         } else {
28365a18407fSRichard Henderson             for (i = 0; i < nb_oargs; i++) {
2837b83eabeaSRichard Henderson                 arg_ts = arg_temp(op->args[i]);
2838b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
2839b83eabeaSRichard Henderson                 if (!dir_ts) {
28405a18407fSRichard Henderson                     continue;
28415a18407fSRichard Henderson                 }
2842b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
28435a18407fSRichard Henderson                 changes = true;
28445a18407fSRichard Henderson 
28455a18407fSRichard Henderson                 /* The output is now live and modified.  */
2846b83eabeaSRichard Henderson                 arg_ts->state = 0;
28475a18407fSRichard Henderson 
28485a18407fSRichard Henderson                 /* Sync outputs upon their last write.  */
28495a18407fSRichard Henderson                 if (NEED_SYNC_ARG(i)) {
2850b83eabeaSRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
28515a18407fSRichard Henderson                                       ? INDEX_op_st_i32
28525a18407fSRichard Henderson                                       : INDEX_op_st_i64);
2853ac1043f6SEmilio G. Cota                     TCGOp *sop = tcg_op_insert_after(s, op, sopc);
28545a18407fSRichard Henderson 
2855b83eabeaSRichard Henderson                     sop->args[0] = temp_arg(dir_ts);
2856b83eabeaSRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
2857b83eabeaSRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
28585a18407fSRichard Henderson 
2859b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
28605a18407fSRichard Henderson                 }
28615a18407fSRichard Henderson                 /* Drop outputs that are dead.  */
28625a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
2863b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
28645a18407fSRichard Henderson                 }
28655a18407fSRichard Henderson             }
28665a18407fSRichard Henderson         }
286761f15c48SRichard Henderson     }
28685a18407fSRichard Henderson 
28695a18407fSRichard Henderson     return changes;
28705a18407fSRichard Henderson }
28715a18407fSRichard Henderson 
28728d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
2873c896fe29Sbellard static void dump_regs(TCGContext *s)
2874c896fe29Sbellard {
2875c896fe29Sbellard     TCGTemp *ts;
2876c896fe29Sbellard     int i;
2877c896fe29Sbellard     char buf[64];
2878c896fe29Sbellard 
2879c896fe29Sbellard     for(i = 0; i < s->nb_temps; i++) {
2880c896fe29Sbellard         ts = &s->temps[i];
288143439139SRichard Henderson         printf("  %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
2882c896fe29Sbellard         switch(ts->val_type) {
2883c896fe29Sbellard         case TEMP_VAL_REG:
2884c896fe29Sbellard             printf("%s", tcg_target_reg_names[ts->reg]);
2885c896fe29Sbellard             break;
2886c896fe29Sbellard         case TEMP_VAL_MEM:
2887b3a62939SRichard Henderson             printf("%d(%s)", (int)ts->mem_offset,
2888b3a62939SRichard Henderson                    tcg_target_reg_names[ts->mem_base->reg]);
2889c896fe29Sbellard             break;
2890c896fe29Sbellard         case TEMP_VAL_CONST:
2891bdb38b95SRichard Henderson             printf("$0x%" PRIx64, ts->val);
2892c896fe29Sbellard             break;
2893c896fe29Sbellard         case TEMP_VAL_DEAD:
2894c896fe29Sbellard             printf("D");
2895c896fe29Sbellard             break;
2896c896fe29Sbellard         default:
2897c896fe29Sbellard             printf("???");
2898c896fe29Sbellard             break;
2899c896fe29Sbellard         }
2900c896fe29Sbellard         printf("\n");
2901c896fe29Sbellard     }
2902c896fe29Sbellard 
2903c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
2904f8b2f202SRichard Henderson         if (s->reg_to_temp[i] != NULL) {
2905c896fe29Sbellard             printf("%s: %s\n",
2906c896fe29Sbellard                    tcg_target_reg_names[i],
2907f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i]));
2908c896fe29Sbellard         }
2909c896fe29Sbellard     }
2910c896fe29Sbellard }
2911c896fe29Sbellard 
2912c896fe29Sbellard static void check_regs(TCGContext *s)
2913c896fe29Sbellard {
2914869938aeSRichard Henderson     int reg;
2915b6638662SRichard Henderson     int k;
2916c896fe29Sbellard     TCGTemp *ts;
2917c896fe29Sbellard     char buf[64];
2918c896fe29Sbellard 
2919c896fe29Sbellard     for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
2920f8b2f202SRichard Henderson         ts = s->reg_to_temp[reg];
2921f8b2f202SRichard Henderson         if (ts != NULL) {
2922f8b2f202SRichard Henderson             if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) {
2923c896fe29Sbellard                 printf("Inconsistency for register %s:\n",
2924c896fe29Sbellard                        tcg_target_reg_names[reg]);
2925b03cce8eSbellard                 goto fail;
2926c896fe29Sbellard             }
2927c896fe29Sbellard         }
2928c896fe29Sbellard     }
2929c896fe29Sbellard     for (k = 0; k < s->nb_temps; k++) {
2930c896fe29Sbellard         ts = &s->temps[k];
2931ee17db83SRichard Henderson         if (ts->val_type == TEMP_VAL_REG
2932ee17db83SRichard Henderson             && ts->kind != TEMP_FIXED
2933f8b2f202SRichard Henderson             && s->reg_to_temp[ts->reg] != ts) {
2934c896fe29Sbellard             printf("Inconsistency for temp %s:\n",
2935f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
2936b03cce8eSbellard         fail:
2937c896fe29Sbellard             printf("reg state:\n");
2938c896fe29Sbellard             dump_regs(s);
2939c896fe29Sbellard             tcg_abort();
2940c896fe29Sbellard         }
2941c896fe29Sbellard     }
2942c896fe29Sbellard }
2943c896fe29Sbellard #endif
2944c896fe29Sbellard 
29452272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
2946c896fe29Sbellard {
29479b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64)
29489b9c37c3SRichard Henderson     /* Sparc64 stack is accessed with offset of 2047 */
2949b591dc59SBlue Swirl     s->current_frame_offset = (s->current_frame_offset +
2950b591dc59SBlue Swirl                                (tcg_target_long)sizeof(tcg_target_long) - 1) &
2951b591dc59SBlue Swirl         ~(sizeof(tcg_target_long) - 1);
2952f44c9960SBlue Swirl #endif
2953b591dc59SBlue Swirl     if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
2954b591dc59SBlue Swirl         s->frame_end) {
29555ff9d6a4Sbellard         tcg_abort();
2956b591dc59SBlue Swirl     }
2957c896fe29Sbellard     ts->mem_offset = s->current_frame_offset;
2958b3a62939SRichard Henderson     ts->mem_base = s->frame_temp;
2959c896fe29Sbellard     ts->mem_allocated = 1;
2960e2c6d1b4SRichard Henderson     s->current_frame_offset += sizeof(tcg_target_long);
2961c896fe29Sbellard }
2962c896fe29Sbellard 
2963b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
2964b3915dbbSRichard Henderson 
296559d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
296659d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
296759d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
2968c896fe29Sbellard {
2969c0522136SRichard Henderson     TCGTempVal new_type;
2970c0522136SRichard Henderson 
2971c0522136SRichard Henderson     switch (ts->kind) {
2972c0522136SRichard Henderson     case TEMP_FIXED:
297359d7c14eSRichard Henderson         return;
2974c0522136SRichard Henderson     case TEMP_GLOBAL:
2975c0522136SRichard Henderson     case TEMP_LOCAL:
2976c0522136SRichard Henderson         new_type = TEMP_VAL_MEM;
2977c0522136SRichard Henderson         break;
2978c0522136SRichard Henderson     case TEMP_NORMAL:
2979c0522136SRichard Henderson         new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD;
2980c0522136SRichard Henderson         break;
2981c0522136SRichard Henderson     case TEMP_CONST:
2982c0522136SRichard Henderson         new_type = TEMP_VAL_CONST;
2983c0522136SRichard Henderson         break;
2984c0522136SRichard Henderson     default:
2985c0522136SRichard Henderson         g_assert_not_reached();
298659d7c14eSRichard Henderson     }
298759d7c14eSRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
298859d7c14eSRichard Henderson         s->reg_to_temp[ts->reg] = NULL;
298959d7c14eSRichard Henderson     }
2990c0522136SRichard Henderson     ts->val_type = new_type;
299159d7c14eSRichard Henderson }
2992c896fe29Sbellard 
299359d7c14eSRichard Henderson /* Mark a temporary as dead.  */
299459d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
299559d7c14eSRichard Henderson {
299659d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
299759d7c14eSRichard Henderson }
299859d7c14eSRichard Henderson 
299959d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
300059d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
300159d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
300259d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
300398b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
300498b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
300559d7c14eSRichard Henderson {
3006c0522136SRichard Henderson     if (!temp_readonly(ts) && !ts->mem_coherent) {
30077f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
30082272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
300959d7c14eSRichard Henderson         }
301059d7c14eSRichard Henderson         switch (ts->val_type) {
301159d7c14eSRichard Henderson         case TEMP_VAL_CONST:
301259d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
301359d7c14eSRichard Henderson                require it later in a register, so attempt to store the
301459d7c14eSRichard Henderson                constant to memory directly.  */
301559d7c14eSRichard Henderson             if (free_or_dead
301659d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
301759d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
301859d7c14eSRichard Henderson                 break;
301959d7c14eSRichard Henderson             }
302059d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
302198b4e186SRichard Henderson                       allocated_regs, preferred_regs);
302259d7c14eSRichard Henderson             /* fallthrough */
302359d7c14eSRichard Henderson 
302459d7c14eSRichard Henderson         case TEMP_VAL_REG:
302559d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
302659d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
302759d7c14eSRichard Henderson             break;
302859d7c14eSRichard Henderson 
302959d7c14eSRichard Henderson         case TEMP_VAL_MEM:
303059d7c14eSRichard Henderson             break;
303159d7c14eSRichard Henderson 
303259d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
303359d7c14eSRichard Henderson         default:
303459d7c14eSRichard Henderson             tcg_abort();
3035c896fe29Sbellard         }
30367f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
30377f6ceedfSAurelien Jarno     }
303859d7c14eSRichard Henderson     if (free_or_dead) {
303959d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
304059d7c14eSRichard Henderson     }
304159d7c14eSRichard Henderson }
30427f6ceedfSAurelien Jarno 
30437f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
3044b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
30457f6ceedfSAurelien Jarno {
3046f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
3047f8b2f202SRichard Henderson     if (ts != NULL) {
304898b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
3049c896fe29Sbellard     }
3050c896fe29Sbellard }
3051c896fe29Sbellard 
3052b016486eSRichard Henderson /**
3053b016486eSRichard Henderson  * tcg_reg_alloc:
3054b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
3055b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
3056b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
3057b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
3058b016486eSRichard Henderson  *
3059b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
3060b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
3061b016486eSRichard Henderson  */
3062b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
3063b016486eSRichard Henderson                             TCGRegSet allocated_regs,
3064b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
3065c896fe29Sbellard {
3066b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
3067b016486eSRichard Henderson     TCGRegSet reg_ct[2];
306891478cefSRichard Henderson     const int *order;
3069c896fe29Sbellard 
3070b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
3071b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
3072b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
3073b016486eSRichard Henderson 
3074b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
3075b016486eSRichard Henderson        or if the preference made no difference.  */
3076b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
3077b016486eSRichard Henderson 
307891478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
3079c896fe29Sbellard 
3080b016486eSRichard Henderson     /* Try free registers, preferences first.  */
3081b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3082b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3083b016486eSRichard Henderson 
3084b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3085b016486eSRichard Henderson             /* One register in the set.  */
3086b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3087b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
3088c896fe29Sbellard                 return reg;
3089c896fe29Sbellard             }
3090b016486eSRichard Henderson         } else {
309191478cefSRichard Henderson             for (i = 0; i < n; i++) {
3092b016486eSRichard Henderson                 TCGReg reg = order[i];
3093b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
3094b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
3095b016486eSRichard Henderson                     return reg;
3096b016486eSRichard Henderson                 }
3097b016486eSRichard Henderson             }
3098b016486eSRichard Henderson         }
3099b016486eSRichard Henderson     }
3100b016486eSRichard Henderson 
3101b016486eSRichard Henderson     /* We must spill something.  */
3102b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3103b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3104b016486eSRichard Henderson 
3105b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3106b016486eSRichard Henderson             /* One register in the set.  */
3107b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3108b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
3109c896fe29Sbellard             return reg;
3110b016486eSRichard Henderson         } else {
3111b016486eSRichard Henderson             for (i = 0; i < n; i++) {
3112b016486eSRichard Henderson                 TCGReg reg = order[i];
3113b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
3114b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
3115b016486eSRichard Henderson                     return reg;
3116b016486eSRichard Henderson                 }
3117b016486eSRichard Henderson             }
3118c896fe29Sbellard         }
3119c896fe29Sbellard     }
3120c896fe29Sbellard 
3121c896fe29Sbellard     tcg_abort();
3122c896fe29Sbellard }
3123c896fe29Sbellard 
312440ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
312540ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
312640ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
3127b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
312840ae5c62SRichard Henderson {
312940ae5c62SRichard Henderson     TCGReg reg;
313040ae5c62SRichard Henderson 
313140ae5c62SRichard Henderson     switch (ts->val_type) {
313240ae5c62SRichard Henderson     case TEMP_VAL_REG:
313340ae5c62SRichard Henderson         return;
313440ae5c62SRichard Henderson     case TEMP_VAL_CONST:
3135b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3136b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
31370a6a8bc8SRichard Henderson         if (ts->type <= TCG_TYPE_I64) {
313840ae5c62SRichard Henderson             tcg_out_movi(s, ts->type, reg, ts->val);
31390a6a8bc8SRichard Henderson         } else {
31404e186175SRichard Henderson             uint64_t val = ts->val;
31414e186175SRichard Henderson             MemOp vece = MO_64;
31424e186175SRichard Henderson 
31434e186175SRichard Henderson             /*
31444e186175SRichard Henderson              * Find the minimal vector element that matches the constant.
31454e186175SRichard Henderson              * The targets will, in general, have to do this search anyway,
31464e186175SRichard Henderson              * do this generically.
31474e186175SRichard Henderson              */
31484e186175SRichard Henderson             if (val == dup_const(MO_8, val)) {
31494e186175SRichard Henderson                 vece = MO_8;
31504e186175SRichard Henderson             } else if (val == dup_const(MO_16, val)) {
31514e186175SRichard Henderson                 vece = MO_16;
31520b4286ddSRichard Henderson             } else if (val == dup_const(MO_32, val)) {
31534e186175SRichard Henderson                 vece = MO_32;
31544e186175SRichard Henderson             }
31554e186175SRichard Henderson 
31564e186175SRichard Henderson             tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val);
31570a6a8bc8SRichard Henderson         }
315840ae5c62SRichard Henderson         ts->mem_coherent = 0;
315940ae5c62SRichard Henderson         break;
316040ae5c62SRichard Henderson     case TEMP_VAL_MEM:
3161b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3162b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
316340ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
316440ae5c62SRichard Henderson         ts->mem_coherent = 1;
316540ae5c62SRichard Henderson         break;
316640ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
316740ae5c62SRichard Henderson     default:
316840ae5c62SRichard Henderson         tcg_abort();
316940ae5c62SRichard Henderson     }
317040ae5c62SRichard Henderson     ts->reg = reg;
317140ae5c62SRichard Henderson     ts->val_type = TEMP_VAL_REG;
317240ae5c62SRichard Henderson     s->reg_to_temp[reg] = ts;
317340ae5c62SRichard Henderson }
317440ae5c62SRichard Henderson 
317559d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
3176e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
317759d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
31781ad80729SAurelien Jarno {
31792c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
3180eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
3181e01fa97dSRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts));
31821ad80729SAurelien Jarno }
31831ad80729SAurelien Jarno 
31849814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
3185641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
3186641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
3187641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
3188641d5fbeSbellard {
3189ac3b8891SRichard Henderson     int i, n;
3190641d5fbeSbellard 
3191ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
3192b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
3193641d5fbeSbellard     }
3194e5097dc8Sbellard }
3195e5097dc8Sbellard 
31963d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
31973d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
31983d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
31993d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
32003d5c5f87SAurelien Jarno {
3201ac3b8891SRichard Henderson     int i, n;
32023d5c5f87SAurelien Jarno 
3203ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
320412b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
320512b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
3206ee17db83SRichard Henderson                          || ts->kind == TEMP_FIXED
320712b9b11aSRichard Henderson                          || ts->mem_coherent);
32083d5c5f87SAurelien Jarno     }
32093d5c5f87SAurelien Jarno }
32103d5c5f87SAurelien Jarno 
3211e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
3212e8996ee0Sbellard    all globals are stored at their canonical location. */
3213e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
3214e5097dc8Sbellard {
3215e5097dc8Sbellard     int i;
3216e5097dc8Sbellard 
3217c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
3218b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
3219c0522136SRichard Henderson 
3220c0522136SRichard Henderson         switch (ts->kind) {
3221c0522136SRichard Henderson         case TEMP_LOCAL:
3222b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
3223c0522136SRichard Henderson             break;
3224c0522136SRichard Henderson         case TEMP_NORMAL:
32252c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
3226eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
3227eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3228c0522136SRichard Henderson             break;
3229c0522136SRichard Henderson         case TEMP_CONST:
3230c0522136SRichard Henderson             /* Similarly, we should have freed any allocated register. */
3231c0522136SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_CONST);
3232c0522136SRichard Henderson             break;
3233c0522136SRichard Henderson         default:
3234c0522136SRichard Henderson             g_assert_not_reached();
3235c896fe29Sbellard         }
3236641d5fbeSbellard     }
3237e8996ee0Sbellard 
3238e8996ee0Sbellard     save_globals(s, allocated_regs);
3239c896fe29Sbellard }
3240c896fe29Sbellard 
3241bab1671fSRichard Henderson /*
3242b4cb76e6SRichard Henderson  * At a conditional branch, we assume all temporaries are dead and
3243b4cb76e6SRichard Henderson  * all globals and local temps are synced to their location.
3244b4cb76e6SRichard Henderson  */
3245b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
3246b4cb76e6SRichard Henderson {
3247b4cb76e6SRichard Henderson     sync_globals(s, allocated_regs);
3248b4cb76e6SRichard Henderson 
3249b4cb76e6SRichard Henderson     for (int i = s->nb_globals; i < s->nb_temps; i++) {
3250b4cb76e6SRichard Henderson         TCGTemp *ts = &s->temps[i];
3251b4cb76e6SRichard Henderson         /*
3252b4cb76e6SRichard Henderson          * The liveness analysis already ensures that temps are dead.
3253b4cb76e6SRichard Henderson          * Keep tcg_debug_asserts for safety.
3254b4cb76e6SRichard Henderson          */
3255c0522136SRichard Henderson         switch (ts->kind) {
3256c0522136SRichard Henderson         case TEMP_LOCAL:
3257b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
3258c0522136SRichard Henderson             break;
3259c0522136SRichard Henderson         case TEMP_NORMAL:
3260b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3261c0522136SRichard Henderson             break;
3262c0522136SRichard Henderson         case TEMP_CONST:
3263c0522136SRichard Henderson             break;
3264c0522136SRichard Henderson         default:
3265c0522136SRichard Henderson             g_assert_not_reached();
3266b4cb76e6SRichard Henderson         }
3267b4cb76e6SRichard Henderson     }
3268b4cb76e6SRichard Henderson }
3269b4cb76e6SRichard Henderson 
3270b4cb76e6SRichard Henderson /*
3271c58f4c97SRichard Henderson  * Specialized code generation for INDEX_op_mov_* with a constant.
3272bab1671fSRichard Henderson  */
32730fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
3274ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
3275ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
3276e8996ee0Sbellard {
3277d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3278e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
327959d7c14eSRichard Henderson 
328059d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
3281f8b2f202SRichard Henderson     if (ots->val_type == TEMP_VAL_REG) {
3282f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = NULL;
3283f8b2f202SRichard Henderson     }
3284e8996ee0Sbellard     ots->val_type = TEMP_VAL_CONST;
3285e8996ee0Sbellard     ots->val = val;
328659d7c14eSRichard Henderson     ots->mem_coherent = 0;
3287ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
3288ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
328959d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
3290f8bf00f1SRichard Henderson         temp_dead(s, ots);
32914c4e1ab2SAurelien Jarno     }
3292e8996ee0Sbellard }
3293e8996ee0Sbellard 
3294bab1671fSRichard Henderson /*
3295bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
3296bab1671fSRichard Henderson  */
3297dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
3298c896fe29Sbellard {
3299dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
330069e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
3301c896fe29Sbellard     TCGTemp *ts, *ots;
3302450445d5SRichard Henderson     TCGType otype, itype;
3303c896fe29Sbellard 
3304d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
330569e3706dSRichard Henderson     preferred_regs = op->output_pref[0];
330643439139SRichard Henderson     ots = arg_temp(op->args[0]);
330743439139SRichard Henderson     ts = arg_temp(op->args[1]);
3308450445d5SRichard Henderson 
3309d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3310e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
3311d63e3b6eSRichard Henderson 
3312450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
3313450445d5SRichard Henderson     otype = ots->type;
3314450445d5SRichard Henderson     itype = ts->type;
3315c896fe29Sbellard 
33160fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
33170fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
33180fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
33190fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
33200fe4fca4SPaolo Bonzini             temp_dead(s, ts);
33210fe4fca4SPaolo Bonzini         }
332269e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
33230fe4fca4SPaolo Bonzini         return;
33240fe4fca4SPaolo Bonzini     }
33250fe4fca4SPaolo Bonzini 
33260fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
33270fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
33280fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
33290fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
33300fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
333169e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
333269e3706dSRichard Henderson                   allocated_regs, preferred_regs);
3333c29c1d7eSAurelien Jarno     }
3334c29c1d7eSAurelien Jarno 
33350fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
3336d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
3337c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
3338c29c1d7eSAurelien Jarno            liveness analysis disabled). */
3339eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
3340c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
33412272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
3342c29c1d7eSAurelien Jarno         }
3343b3a62939SRichard Henderson         tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset);
3344c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
3345f8bf00f1SRichard Henderson             temp_dead(s, ts);
3346c29c1d7eSAurelien Jarno         }
3347f8bf00f1SRichard Henderson         temp_dead(s, ots);
3348e8996ee0Sbellard     } else {
3349ee17db83SRichard Henderson         if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) {
3350c29c1d7eSAurelien Jarno             /* the mov can be suppressed */
3351c29c1d7eSAurelien Jarno             if (ots->val_type == TEMP_VAL_REG) {
3352f8b2f202SRichard Henderson                 s->reg_to_temp[ots->reg] = NULL;
3353c896fe29Sbellard             }
3354c29c1d7eSAurelien Jarno             ots->reg = ts->reg;
3355f8bf00f1SRichard Henderson             temp_dead(s, ts);
3356c29c1d7eSAurelien Jarno         } else {
3357c29c1d7eSAurelien Jarno             if (ots->val_type != TEMP_VAL_REG) {
3358c29c1d7eSAurelien Jarno                 /* When allocating a new register, make sure to not spill the
3359c29c1d7eSAurelien Jarno                    input one. */
3360c29c1d7eSAurelien Jarno                 tcg_regset_set_reg(allocated_regs, ts->reg);
3361450445d5SRichard Henderson                 ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
336269e3706dSRichard Henderson                                          allocated_regs, preferred_regs,
3363b016486eSRichard Henderson                                          ots->indirect_base);
3364c29c1d7eSAurelien Jarno             }
336578113e83SRichard Henderson             if (!tcg_out_mov(s, otype, ots->reg, ts->reg)) {
3366240c08d0SRichard Henderson                 /*
3367240c08d0SRichard Henderson                  * Cross register class move not supported.
3368240c08d0SRichard Henderson                  * Store the source register into the destination slot
3369240c08d0SRichard Henderson                  * and leave the destination temp as TEMP_VAL_MEM.
3370240c08d0SRichard Henderson                  */
3371e01fa97dSRichard Henderson                 assert(!temp_readonly(ots));
3372240c08d0SRichard Henderson                 if (!ts->mem_allocated) {
3373240c08d0SRichard Henderson                     temp_allocate_frame(s, ots);
3374240c08d0SRichard Henderson                 }
3375240c08d0SRichard Henderson                 tcg_out_st(s, ts->type, ts->reg,
3376240c08d0SRichard Henderson                            ots->mem_base->reg, ots->mem_offset);
3377240c08d0SRichard Henderson                 ots->mem_coherent = 1;
3378240c08d0SRichard Henderson                 temp_free_or_dead(s, ots, -1);
3379240c08d0SRichard Henderson                 return;
338078113e83SRichard Henderson             }
3381c29c1d7eSAurelien Jarno         }
3382c896fe29Sbellard         ots->val_type = TEMP_VAL_REG;
3383c896fe29Sbellard         ots->mem_coherent = 0;
3384f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3385ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(0)) {
338698b4e186SRichard Henderson             temp_sync(s, ots, allocated_regs, 0, 0);
3387c29c1d7eSAurelien Jarno         }
3388ec7a869dSAurelien Jarno     }
3389c896fe29Sbellard }
3390c896fe29Sbellard 
3391bab1671fSRichard Henderson /*
3392bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
3393bab1671fSRichard Henderson  */
3394bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
3395bab1671fSRichard Henderson {
3396bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
3397bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
3398bab1671fSRichard Henderson     TCGTemp *its, *ots;
3399bab1671fSRichard Henderson     TCGType itype, vtype;
3400d6ecb4a9SRichard Henderson     intptr_t endian_fixup;
3401bab1671fSRichard Henderson     unsigned vece;
3402bab1671fSRichard Henderson     bool ok;
3403bab1671fSRichard Henderson 
3404bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
3405bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
3406bab1671fSRichard Henderson 
3407bab1671fSRichard Henderson     /* ENV should not be modified.  */
3408e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
3409bab1671fSRichard Henderson 
3410bab1671fSRichard Henderson     itype = its->type;
3411bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
3412bab1671fSRichard Henderson     vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
3413bab1671fSRichard Henderson 
3414bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
3415bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
3416bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
3417bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
3418bab1671fSRichard Henderson             temp_dead(s, its);
3419bab1671fSRichard Henderson         }
3420bab1671fSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, op->output_pref[0]);
3421bab1671fSRichard Henderson         return;
3422bab1671fSRichard Henderson     }
3423bab1671fSRichard Henderson 
34249be0d080SRichard Henderson     dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
34259be0d080SRichard Henderson     dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs;
3426bab1671fSRichard Henderson 
3427bab1671fSRichard Henderson     /* Allocate the output register now.  */
3428bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
3429bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
3430bab1671fSRichard Henderson 
3431bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
3432bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
3433bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
3434bab1671fSRichard Henderson         }
3435bab1671fSRichard Henderson         ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
3436bab1671fSRichard Henderson                                  op->output_pref[0], ots->indirect_base);
3437bab1671fSRichard Henderson         ots->val_type = TEMP_VAL_REG;
3438bab1671fSRichard Henderson         ots->mem_coherent = 0;
3439bab1671fSRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3440bab1671fSRichard Henderson     }
3441bab1671fSRichard Henderson 
3442bab1671fSRichard Henderson     switch (its->val_type) {
3443bab1671fSRichard Henderson     case TEMP_VAL_REG:
3444bab1671fSRichard Henderson         /*
3445bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
3446bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
3447bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
3448bab1671fSRichard Henderson          */
3449bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
3450bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
3451bab1671fSRichard Henderson                 goto done;
3452bab1671fSRichard Henderson             }
3453bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
3454bab1671fSRichard Henderson         }
3455bab1671fSRichard Henderson         if (!its->mem_coherent) {
3456bab1671fSRichard Henderson             /*
3457bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
3458bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
3459bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
3460bab1671fSRichard Henderson              */
3461bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
3462bab1671fSRichard Henderson                 break;
3463bab1671fSRichard Henderson             }
3464bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
3465bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
3466bab1671fSRichard Henderson         }
3467bab1671fSRichard Henderson         /* fall through */
3468bab1671fSRichard Henderson 
3469bab1671fSRichard Henderson     case TEMP_VAL_MEM:
3470d6ecb4a9SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
3471d6ecb4a9SRichard Henderson         endian_fixup = itype == TCG_TYPE_I32 ? 4 : 8;
3472d6ecb4a9SRichard Henderson         endian_fixup -= 1 << vece;
3473d6ecb4a9SRichard Henderson #else
3474d6ecb4a9SRichard Henderson         endian_fixup = 0;
3475d6ecb4a9SRichard Henderson #endif
3476d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
3477d6ecb4a9SRichard Henderson                              its->mem_offset + endian_fixup)) {
3478d6ecb4a9SRichard Henderson             goto done;
3479d6ecb4a9SRichard Henderson         }
3480bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
3481bab1671fSRichard Henderson         break;
3482bab1671fSRichard Henderson 
3483bab1671fSRichard Henderson     default:
3484bab1671fSRichard Henderson         g_assert_not_reached();
3485bab1671fSRichard Henderson     }
3486bab1671fSRichard Henderson 
3487bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
3488bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
3489bab1671fSRichard Henderson     tcg_debug_assert(ok);
3490bab1671fSRichard Henderson 
3491bab1671fSRichard Henderson  done:
3492bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
3493bab1671fSRichard Henderson         temp_dead(s, its);
3494bab1671fSRichard Henderson     }
3495bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
3496bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
3497bab1671fSRichard Henderson     }
3498bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
3499bab1671fSRichard Henderson         temp_dead(s, ots);
3500bab1671fSRichard Henderson     }
3501bab1671fSRichard Henderson }
3502bab1671fSRichard Henderson 
3503dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
3504c896fe29Sbellard {
3505dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3506dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
350782790a87SRichard Henderson     TCGRegSet i_allocated_regs;
350882790a87SRichard Henderson     TCGRegSet o_allocated_regs;
3509b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
3510b6638662SRichard Henderson     TCGReg reg;
3511c896fe29Sbellard     TCGArg arg;
3512c896fe29Sbellard     const TCGArgConstraint *arg_ct;
3513c896fe29Sbellard     TCGTemp *ts;
3514c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
3515c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
3516c896fe29Sbellard 
3517c896fe29Sbellard     nb_oargs = def->nb_oargs;
3518c896fe29Sbellard     nb_iargs = def->nb_iargs;
3519c896fe29Sbellard 
3520c896fe29Sbellard     /* copy constants */
3521c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
3522dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
3523c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
3524c896fe29Sbellard 
3525d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
3526d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
352782790a87SRichard Henderson 
3528c896fe29Sbellard     /* satisfy input constraints */
3529c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
3530d62816f2SRichard Henderson         TCGRegSet i_preferred_regs, o_preferred_regs;
3531d62816f2SRichard Henderson 
353266792f90SRichard Henderson         i = def->args_ct[nb_oargs + k].sort_index;
3533dd186292SRichard Henderson         arg = op->args[i];
3534c896fe29Sbellard         arg_ct = &def->args_ct[i];
353543439139SRichard Henderson         ts = arg_temp(arg);
353640ae5c62SRichard Henderson 
353740ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
3538a4fbbd77SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct->ct)) {
3539c896fe29Sbellard             /* constant is OK for instruction */
3540c896fe29Sbellard             const_args[i] = 1;
3541c896fe29Sbellard             new_args[i] = ts->val;
3542d62816f2SRichard Henderson             continue;
3543c896fe29Sbellard         }
354440ae5c62SRichard Henderson 
3545d62816f2SRichard Henderson         i_preferred_regs = o_preferred_regs = 0;
3546bc2b17e6SRichard Henderson         if (arg_ct->ialias) {
3547d62816f2SRichard Henderson             o_preferred_regs = op->output_pref[arg_ct->alias_index];
3548c0522136SRichard Henderson 
3549c0522136SRichard Henderson             /*
3550c0522136SRichard Henderson              * If the input is readonly, then it cannot also be an
3551c0522136SRichard Henderson              * output and aliased to itself.  If the input is not
3552c0522136SRichard Henderson              * dead after the instruction, we must allocate a new
3553c0522136SRichard Henderson              * register and move it.
3554c0522136SRichard Henderson              */
3555c0522136SRichard Henderson             if (temp_readonly(ts) || !IS_DEAD_ARG(i)) {
3556c896fe29Sbellard                 goto allocate_in_reg;
3557c896fe29Sbellard             }
3558d62816f2SRichard Henderson 
3559c0522136SRichard Henderson             /*
3560c0522136SRichard Henderson              * Check if the current register has already been allocated
3561c0522136SRichard Henderson              * for another input aliased to an output.
3562c0522136SRichard Henderson              */
3563d62816f2SRichard Henderson             if (ts->val_type == TEMP_VAL_REG) {
3564d62816f2SRichard Henderson                 reg = ts->reg;
3565c0522136SRichard Henderson                 for (int k2 = 0; k2 < k; k2++) {
3566c0522136SRichard Henderson                     int i2 = def->args_ct[nb_oargs + k2].sort_index;
3567bc2b17e6SRichard Henderson                     if (def->args_ct[i2].ialias && reg == new_args[i2]) {
35687e1df267SAurelien Jarno                         goto allocate_in_reg;
35697e1df267SAurelien Jarno                     }
35707e1df267SAurelien Jarno                 }
35715ff9d6a4Sbellard             }
3572d62816f2SRichard Henderson             i_preferred_regs = o_preferred_regs;
3573866cb6cbSAurelien Jarno         }
3574d62816f2SRichard Henderson 
35759be0d080SRichard Henderson         temp_load(s, ts, arg_ct->regs, i_allocated_regs, i_preferred_regs);
3576c896fe29Sbellard         reg = ts->reg;
3577d62816f2SRichard Henderson 
3578c0522136SRichard Henderson         if (!tcg_regset_test_reg(arg_ct->regs, reg)) {
3579c896fe29Sbellard  allocate_in_reg:
3580c0522136SRichard Henderson             /*
3581c0522136SRichard Henderson              * Allocate a new register matching the constraint
3582c0522136SRichard Henderson              * and move the temporary register into it.
3583c0522136SRichard Henderson              */
3584d62816f2SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
3585d62816f2SRichard Henderson                       i_allocated_regs, 0);
35869be0d080SRichard Henderson             reg = tcg_reg_alloc(s, arg_ct->regs, i_allocated_regs,
3587d62816f2SRichard Henderson                                 o_preferred_regs, ts->indirect_base);
358878113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
3589240c08d0SRichard Henderson                 /*
3590240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
3591240c08d0SRichard Henderson                  * temp back to its slot and load from there.
3592240c08d0SRichard Henderson                  */
3593240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
3594240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
3595240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
359678113e83SRichard Henderson             }
3597c896fe29Sbellard         }
3598c896fe29Sbellard         new_args[i] = reg;
3599c896fe29Sbellard         const_args[i] = 0;
360082790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
3601c896fe29Sbellard     }
3602c896fe29Sbellard 
3603c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
3604866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
3605866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
360643439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
3607c896fe29Sbellard         }
3608c896fe29Sbellard     }
3609c896fe29Sbellard 
3610b4cb76e6SRichard Henderson     if (def->flags & TCG_OPF_COND_BRANCH) {
3611b4cb76e6SRichard Henderson         tcg_reg_alloc_cbranch(s, i_allocated_regs);
3612b4cb76e6SRichard Henderson     } else if (def->flags & TCG_OPF_BB_END) {
361382790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
3614a52ad07eSAurelien Jarno     } else {
3615c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
3616b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
3617c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
3618c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
361982790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
3620c896fe29Sbellard                 }
3621c896fe29Sbellard             }
36223d5c5f87SAurelien Jarno         }
36233d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
36243d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
36253d5c5f87SAurelien Jarno                an exception. */
362682790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
3627c896fe29Sbellard         }
3628c896fe29Sbellard 
3629c896fe29Sbellard         /* satisfy the output constraints */
3630c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
363166792f90SRichard Henderson             i = def->args_ct[k].sort_index;
3632dd186292SRichard Henderson             arg = op->args[i];
3633c896fe29Sbellard             arg_ct = &def->args_ct[i];
363443439139SRichard Henderson             ts = arg_temp(arg);
3635d63e3b6eSRichard Henderson 
3636d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
3637e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
3638d63e3b6eSRichard Henderson 
3639bc2b17e6SRichard Henderson             if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
36405ff9d6a4Sbellard                 reg = new_args[arg_ct->alias_index];
3641bc2b17e6SRichard Henderson             } else if (arg_ct->newreg) {
36429be0d080SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->regs,
364382790a87SRichard Henderson                                     i_allocated_regs | o_allocated_regs,
364469e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
3645c896fe29Sbellard             } else {
36469be0d080SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
364769e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
3648c896fe29Sbellard             }
364982790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
3650639368ddSAurelien Jarno             if (ts->val_type == TEMP_VAL_REG) {
3651f8b2f202SRichard Henderson                 s->reg_to_temp[ts->reg] = NULL;
3652639368ddSAurelien Jarno             }
3653c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
3654c896fe29Sbellard             ts->reg = reg;
3655d63e3b6eSRichard Henderson             /*
3656d63e3b6eSRichard Henderson              * Temp value is modified, so the value kept in memory is
3657d63e3b6eSRichard Henderson              * potentially not the same.
3658d63e3b6eSRichard Henderson              */
3659c896fe29Sbellard             ts->mem_coherent = 0;
3660f8b2f202SRichard Henderson             s->reg_to_temp[reg] = ts;
3661c896fe29Sbellard             new_args[i] = reg;
3662c896fe29Sbellard         }
3663e8996ee0Sbellard     }
3664c896fe29Sbellard 
3665c896fe29Sbellard     /* emit instruction */
3666d2fd745fSRichard Henderson     if (def->flags & TCG_OPF_VECTOR) {
3667d2fd745fSRichard Henderson         tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
3668d2fd745fSRichard Henderson                        new_args, const_args);
3669d2fd745fSRichard Henderson     } else {
3670dd186292SRichard Henderson         tcg_out_op(s, op->opc, new_args, const_args);
3671d2fd745fSRichard Henderson     }
3672c896fe29Sbellard 
3673c896fe29Sbellard     /* move the outputs in the correct register if needed */
3674c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
367543439139SRichard Henderson         ts = arg_temp(op->args[i]);
3676d63e3b6eSRichard Henderson 
3677d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
3678e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
3679d63e3b6eSRichard Henderson 
3680ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
368198b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
368259d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
3683f8bf00f1SRichard Henderson             temp_dead(s, ts);
3684ec7a869dSAurelien Jarno         }
3685c896fe29Sbellard     }
3686c896fe29Sbellard }
3687c896fe29Sbellard 
3688efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op)
3689efe86b21SRichard Henderson {
3690efe86b21SRichard Henderson     const TCGLifeData arg_life = op->life;
3691efe86b21SRichard Henderson     TCGTemp *ots, *itsl, *itsh;
3692efe86b21SRichard Henderson     TCGType vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
3693efe86b21SRichard Henderson 
3694efe86b21SRichard Henderson     /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */
3695efe86b21SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 32);
3696efe86b21SRichard Henderson     tcg_debug_assert(TCGOP_VECE(op) == MO_64);
3697efe86b21SRichard Henderson 
3698efe86b21SRichard Henderson     ots = arg_temp(op->args[0]);
3699efe86b21SRichard Henderson     itsl = arg_temp(op->args[1]);
3700efe86b21SRichard Henderson     itsh = arg_temp(op->args[2]);
3701efe86b21SRichard Henderson 
3702efe86b21SRichard Henderson     /* ENV should not be modified.  */
3703efe86b21SRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
3704efe86b21SRichard Henderson 
3705efe86b21SRichard Henderson     /* Allocate the output register now.  */
3706efe86b21SRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
3707efe86b21SRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
3708efe86b21SRichard Henderson         TCGRegSet dup_out_regs =
3709efe86b21SRichard Henderson             tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
3710efe86b21SRichard Henderson 
3711efe86b21SRichard Henderson         /* Make sure to not spill the input registers. */
3712efe86b21SRichard Henderson         if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) {
3713efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsl->reg);
3714efe86b21SRichard Henderson         }
3715efe86b21SRichard Henderson         if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) {
3716efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsh->reg);
3717efe86b21SRichard Henderson         }
3718efe86b21SRichard Henderson 
3719efe86b21SRichard Henderson         ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
3720efe86b21SRichard Henderson                                  op->output_pref[0], ots->indirect_base);
3721efe86b21SRichard Henderson         ots->val_type = TEMP_VAL_REG;
3722efe86b21SRichard Henderson         ots->mem_coherent = 0;
3723efe86b21SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3724efe86b21SRichard Henderson     }
3725efe86b21SRichard Henderson 
3726efe86b21SRichard Henderson     /* Promote dup2 of immediates to dupi_vec. */
3727efe86b21SRichard Henderson     if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) {
3728efe86b21SRichard Henderson         uint64_t val = deposit64(itsl->val, 32, 32, itsh->val);
3729efe86b21SRichard Henderson         MemOp vece = MO_64;
3730efe86b21SRichard Henderson 
3731efe86b21SRichard Henderson         if (val == dup_const(MO_8, val)) {
3732efe86b21SRichard Henderson             vece = MO_8;
3733efe86b21SRichard Henderson         } else if (val == dup_const(MO_16, val)) {
3734efe86b21SRichard Henderson             vece = MO_16;
3735efe86b21SRichard Henderson         } else if (val == dup_const(MO_32, val)) {
3736efe86b21SRichard Henderson             vece = MO_32;
3737efe86b21SRichard Henderson         }
3738efe86b21SRichard Henderson 
3739efe86b21SRichard Henderson         tcg_out_dupi_vec(s, vtype, vece, ots->reg, val);
3740efe86b21SRichard Henderson         goto done;
3741efe86b21SRichard Henderson     }
3742efe86b21SRichard Henderson 
3743efe86b21SRichard Henderson     /* If the two inputs form one 64-bit value, try dupm_vec. */
3744efe86b21SRichard Henderson     if (itsl + 1 == itsh && itsl->base_type == TCG_TYPE_I64) {
3745efe86b21SRichard Henderson         if (!itsl->mem_coherent) {
3746efe86b21SRichard Henderson             temp_sync(s, itsl, s->reserved_regs, 0, 0);
3747efe86b21SRichard Henderson         }
3748efe86b21SRichard Henderson         if (!itsh->mem_coherent) {
3749efe86b21SRichard Henderson             temp_sync(s, itsh, s->reserved_regs, 0, 0);
3750efe86b21SRichard Henderson         }
3751efe86b21SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
3752efe86b21SRichard Henderson         TCGTemp *its = itsh;
3753efe86b21SRichard Henderson #else
3754efe86b21SRichard Henderson         TCGTemp *its = itsl;
3755efe86b21SRichard Henderson #endif
3756efe86b21SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg,
3757efe86b21SRichard Henderson                              its->mem_base->reg, its->mem_offset)) {
3758efe86b21SRichard Henderson             goto done;
3759efe86b21SRichard Henderson         }
3760efe86b21SRichard Henderson     }
3761efe86b21SRichard Henderson 
3762efe86b21SRichard Henderson     /* Fall back to generic expansion. */
3763efe86b21SRichard Henderson     return false;
3764efe86b21SRichard Henderson 
3765efe86b21SRichard Henderson  done:
3766efe86b21SRichard Henderson     if (IS_DEAD_ARG(1)) {
3767efe86b21SRichard Henderson         temp_dead(s, itsl);
3768efe86b21SRichard Henderson     }
3769efe86b21SRichard Henderson     if (IS_DEAD_ARG(2)) {
3770efe86b21SRichard Henderson         temp_dead(s, itsh);
3771efe86b21SRichard Henderson     }
3772efe86b21SRichard Henderson     if (NEED_SYNC_ARG(0)) {
3773efe86b21SRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0));
3774efe86b21SRichard Henderson     } else if (IS_DEAD_ARG(0)) {
3775efe86b21SRichard Henderson         temp_dead(s, ots);
3776efe86b21SRichard Henderson     }
3777efe86b21SRichard Henderson     return true;
3778efe86b21SRichard Henderson }
3779efe86b21SRichard Henderson 
3780b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP
3781b03cce8eSbellard #define STACK_DIR(x) (-(x))
3782b03cce8eSbellard #else
3783b03cce8eSbellard #define STACK_DIR(x) (x)
3784b03cce8eSbellard #endif
3785b03cce8eSbellard 
3786dd186292SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
3787c896fe29Sbellard {
3788cd9090aaSRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
3789cd9090aaSRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
3790dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3791b6638662SRichard Henderson     int flags, nb_regs, i;
3792b6638662SRichard Henderson     TCGReg reg;
3793cf066674SRichard Henderson     TCGArg arg;
3794c896fe29Sbellard     TCGTemp *ts;
3795d3452f1fSRichard Henderson     intptr_t stack_offset;
3796d3452f1fSRichard Henderson     size_t call_stack_size;
3797cf066674SRichard Henderson     tcg_insn_unit *func_addr;
3798cf066674SRichard Henderson     int allocate_args;
3799c896fe29Sbellard     TCGRegSet allocated_regs;
3800c896fe29Sbellard 
3801dd186292SRichard Henderson     func_addr = (tcg_insn_unit *)(intptr_t)op->args[nb_oargs + nb_iargs];
3802dd186292SRichard Henderson     flags = op->args[nb_oargs + nb_iargs + 1];
3803c896fe29Sbellard 
38046e17d0c5SStefan Weil     nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
3805c45cb8bbSRichard Henderson     if (nb_regs > nb_iargs) {
3806c45cb8bbSRichard Henderson         nb_regs = nb_iargs;
3807cf066674SRichard Henderson     }
3808c896fe29Sbellard 
3809c896fe29Sbellard     /* assign stack slots first */
3810c45cb8bbSRichard Henderson     call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long);
3811c896fe29Sbellard     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
3812c896fe29Sbellard         ~(TCG_TARGET_STACK_ALIGN - 1);
3813b03cce8eSbellard     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
3814b03cce8eSbellard     if (allocate_args) {
3815345649c0SBlue Swirl         /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
3816345649c0SBlue Swirl            preallocate call stack */
3817345649c0SBlue Swirl         tcg_abort();
3818b03cce8eSbellard     }
381939cf05d3Sbellard 
382039cf05d3Sbellard     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
3821c45cb8bbSRichard Henderson     for (i = nb_regs; i < nb_iargs; i++) {
3822dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
382339cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP
382439cf05d3Sbellard         stack_offset -= sizeof(tcg_target_long);
382539cf05d3Sbellard #endif
382639cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
382743439139SRichard Henderson             ts = arg_temp(arg);
382840ae5c62SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
3829b722452aSRichard Henderson                       s->reserved_regs, 0);
3830e4d5434cSblueswir1             tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
383139cf05d3Sbellard         }
383239cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP
383339cf05d3Sbellard         stack_offset += sizeof(tcg_target_long);
383439cf05d3Sbellard #endif
3835c896fe29Sbellard     }
3836c896fe29Sbellard 
3837c896fe29Sbellard     /* assign input registers */
3838d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
3839c896fe29Sbellard     for (i = 0; i < nb_regs; i++) {
3840dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
384139cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
384243439139SRichard Henderson             ts = arg_temp(arg);
3843c896fe29Sbellard             reg = tcg_target_call_iarg_regs[i];
384440ae5c62SRichard Henderson 
3845c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
3846c896fe29Sbellard                 if (ts->reg != reg) {
38474250da10SRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
384878113e83SRichard Henderson                     if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
3849240c08d0SRichard Henderson                         /*
3850240c08d0SRichard Henderson                          * Cross register class move not supported.  Sync the
3851240c08d0SRichard Henderson                          * temp back to its slot and load from there.
3852240c08d0SRichard Henderson                          */
3853240c08d0SRichard Henderson                         temp_sync(s, ts, allocated_regs, 0, 0);
3854240c08d0SRichard Henderson                         tcg_out_ld(s, ts->type, reg,
3855240c08d0SRichard Henderson                                    ts->mem_base->reg, ts->mem_offset);
385678113e83SRichard Henderson                     }
3857c896fe29Sbellard                 }
3858c896fe29Sbellard             } else {
3859ccb1bb66SRichard Henderson                 TCGRegSet arg_set = 0;
386040ae5c62SRichard Henderson 
38614250da10SRichard Henderson                 tcg_reg_free(s, reg, allocated_regs);
386240ae5c62SRichard Henderson                 tcg_regset_set_reg(arg_set, reg);
3863b722452aSRichard Henderson                 temp_load(s, ts, arg_set, allocated_regs, 0);
3864c896fe29Sbellard             }
386540ae5c62SRichard Henderson 
3866c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
3867c896fe29Sbellard         }
386839cf05d3Sbellard     }
3869c896fe29Sbellard 
3870c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
3871866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3872866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
387343439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
3874c896fe29Sbellard         }
3875c896fe29Sbellard     }
3876c896fe29Sbellard 
3877c896fe29Sbellard     /* clobber call registers */
3878c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
3879c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
3880b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
3881c896fe29Sbellard         }
3882c896fe29Sbellard     }
3883c896fe29Sbellard 
388478505279SAurelien Jarno     /* Save globals if they might be written by the helper, sync them if
388578505279SAurelien Jarno        they might be read. */
388678505279SAurelien Jarno     if (flags & TCG_CALL_NO_READ_GLOBALS) {
388778505279SAurelien Jarno         /* Nothing to do */
388878505279SAurelien Jarno     } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) {
388978505279SAurelien Jarno         sync_globals(s, allocated_regs);
389078505279SAurelien Jarno     } else {
3891e8996ee0Sbellard         save_globals(s, allocated_regs);
3892b9c18f56Saurel32     }
3893c896fe29Sbellard 
3894cf066674SRichard Henderson     tcg_out_call(s, func_addr);
3895c896fe29Sbellard 
3896c896fe29Sbellard     /* assign output registers and emit moves if needed */
3897c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
3898dd186292SRichard Henderson         arg = op->args[i];
389943439139SRichard Henderson         ts = arg_temp(arg);
3900d63e3b6eSRichard Henderson 
3901d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
3902e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
3903d63e3b6eSRichard Henderson 
3904c896fe29Sbellard         reg = tcg_target_call_oarg_regs[i];
3905eabb7b91SAurelien Jarno         tcg_debug_assert(s->reg_to_temp[reg] == NULL);
3906639368ddSAurelien Jarno         if (ts->val_type == TEMP_VAL_REG) {
3907f8b2f202SRichard Henderson             s->reg_to_temp[ts->reg] = NULL;
3908639368ddSAurelien Jarno         }
3909c896fe29Sbellard         ts->val_type = TEMP_VAL_REG;
3910c896fe29Sbellard         ts->reg = reg;
3911c896fe29Sbellard         ts->mem_coherent = 0;
3912f8b2f202SRichard Henderson         s->reg_to_temp[reg] = ts;
3913ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
391498b4e186SRichard Henderson             temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i));
391559d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
3916f8bf00f1SRichard Henderson             temp_dead(s, ts);
3917c896fe29Sbellard         }
3918c896fe29Sbellard     }
39198c11ad25SAurelien Jarno }
3920c896fe29Sbellard 
3921c896fe29Sbellard #ifdef CONFIG_PROFILER
3922c896fe29Sbellard 
3923c3fac113SEmilio G. Cota /* avoid copy/paste errors */
3924c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field)                       \
3925c3fac113SEmilio G. Cota     do {                                                \
3926d73415a3SStefan Hajnoczi         (to)->field += qatomic_read(&((from)->field));  \
3927c3fac113SEmilio G. Cota     } while (0)
3928c896fe29Sbellard 
3929c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field)                                       \
3930c3fac113SEmilio G. Cota     do {                                                                \
3931d73415a3SStefan Hajnoczi         typeof((from)->field) val__ = qatomic_read(&((from)->field));   \
3932c3fac113SEmilio G. Cota         if (val__ > (to)->field) {                                      \
3933c3fac113SEmilio G. Cota             (to)->field = val__;                                        \
3934c3fac113SEmilio G. Cota         }                                                               \
3935c3fac113SEmilio G. Cota     } while (0)
3936c3fac113SEmilio G. Cota 
3937c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */
3938c3fac113SEmilio G. Cota static inline
3939c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
3940c896fe29Sbellard {
39410e2d61cfSRichard Henderson     unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
3942c3fac113SEmilio G. Cota     unsigned int i;
3943c3fac113SEmilio G. Cota 
39443468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
3945d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
39463468b59eSEmilio G. Cota         const TCGProfile *orig = &s->prof;
3947c3fac113SEmilio G. Cota 
3948c3fac113SEmilio G. Cota         if (counters) {
394972fd2efbSEmilio G. Cota             PROF_ADD(prof, orig, cpu_exec_time);
3950c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count1);
3951c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count);
3952c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, op_count);
3953c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, op_count_max);
3954c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, temp_count);
3955c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, temp_count_max);
3956c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, del_op_count);
3957c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_in_len);
3958c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_out_len);
3959c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, search_out_len);
3960c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, interm_time);
3961c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_time);
3962c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, la_time);
3963c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, opt_time);
3964c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_count);
3965c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_time);
3966c3fac113SEmilio G. Cota         }
3967c3fac113SEmilio G. Cota         if (table) {
3968c896fe29Sbellard             int i;
3969d70724ceSzhanghailiang 
397015fc7daaSRichard Henderson             for (i = 0; i < NB_OPS; i++) {
3971c3fac113SEmilio G. Cota                 PROF_ADD(prof, orig, table_op_count[i]);
3972c3fac113SEmilio G. Cota             }
3973c3fac113SEmilio G. Cota         }
3974c3fac113SEmilio G. Cota     }
3975c3fac113SEmilio G. Cota }
3976c3fac113SEmilio G. Cota 
3977c3fac113SEmilio G. Cota #undef PROF_ADD
3978c3fac113SEmilio G. Cota #undef PROF_MAX
3979c3fac113SEmilio G. Cota 
3980c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof)
3981c3fac113SEmilio G. Cota {
3982c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, true, false);
3983c3fac113SEmilio G. Cota }
3984c3fac113SEmilio G. Cota 
3985c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof)
3986c3fac113SEmilio G. Cota {
3987c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, false, true);
3988c3fac113SEmilio G. Cota }
3989c3fac113SEmilio G. Cota 
3990d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
3991c3fac113SEmilio G. Cota {
3992c3fac113SEmilio G. Cota     TCGProfile prof = {};
3993c3fac113SEmilio G. Cota     int i;
3994c3fac113SEmilio G. Cota 
3995c3fac113SEmilio G. Cota     tcg_profile_snapshot_table(&prof);
3996c3fac113SEmilio G. Cota     for (i = 0; i < NB_OPS; i++) {
3997d4c51a0aSMarkus Armbruster         qemu_printf("%s %" PRId64 "\n", tcg_op_defs[i].name,
3998c3fac113SEmilio G. Cota                     prof.table_op_count[i]);
3999c896fe29Sbellard     }
4000c896fe29Sbellard }
400172fd2efbSEmilio G. Cota 
400272fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
400372fd2efbSEmilio G. Cota {
40040e2d61cfSRichard Henderson     unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
400572fd2efbSEmilio G. Cota     unsigned int i;
400672fd2efbSEmilio G. Cota     int64_t ret = 0;
400772fd2efbSEmilio G. Cota 
400872fd2efbSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4009d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
401072fd2efbSEmilio G. Cota         const TCGProfile *prof = &s->prof;
401172fd2efbSEmilio G. Cota 
4012d73415a3SStefan Hajnoczi         ret += qatomic_read(&prof->cpu_exec_time);
401372fd2efbSEmilio G. Cota     }
401472fd2efbSEmilio G. Cota     return ret;
401572fd2efbSEmilio G. Cota }
4016246ae24dSMax Filippov #else
4017d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
4018246ae24dSMax Filippov {
4019d4c51a0aSMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4020246ae24dSMax Filippov }
402172fd2efbSEmilio G. Cota 
402272fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
402372fd2efbSEmilio G. Cota {
402472fd2efbSEmilio G. Cota     error_report("%s: TCG profiler not compiled", __func__);
402572fd2efbSEmilio G. Cota     exit(EXIT_FAILURE);
402672fd2efbSEmilio G. Cota }
4027c896fe29Sbellard #endif
4028c896fe29Sbellard 
4029c896fe29Sbellard 
40305bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
4031c896fe29Sbellard {
4032c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER
4033c3fac113SEmilio G. Cota     TCGProfile *prof = &s->prof;
4034c3fac113SEmilio G. Cota #endif
403515fa08f8SRichard Henderson     int i, num_insns;
403615fa08f8SRichard Henderson     TCGOp *op;
4037c896fe29Sbellard 
403804fe6400SRichard Henderson #ifdef CONFIG_PROFILER
403904fe6400SRichard Henderson     {
4040c1f543b7SEmilio G. Cota         int n = 0;
404104fe6400SRichard Henderson 
404215fa08f8SRichard Henderson         QTAILQ_FOREACH(op, &s->ops, link) {
404315fa08f8SRichard Henderson             n++;
404415fa08f8SRichard Henderson         }
4045d73415a3SStefan Hajnoczi         qatomic_set(&prof->op_count, prof->op_count + n);
4046c3fac113SEmilio G. Cota         if (n > prof->op_count_max) {
4047d73415a3SStefan Hajnoczi             qatomic_set(&prof->op_count_max, n);
404804fe6400SRichard Henderson         }
404904fe6400SRichard Henderson 
405004fe6400SRichard Henderson         n = s->nb_temps;
4051d73415a3SStefan Hajnoczi         qatomic_set(&prof->temp_count, prof->temp_count + n);
4052c3fac113SEmilio G. Cota         if (n > prof->temp_count_max) {
4053d73415a3SStefan Hajnoczi             qatomic_set(&prof->temp_count_max, n);
405404fe6400SRichard Henderson         }
405504fe6400SRichard Henderson     }
405604fe6400SRichard Henderson #endif
405704fe6400SRichard Henderson 
4058c896fe29Sbellard #ifdef DEBUG_DISAS
4059d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
4060d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
4061fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
406293fcfe39Saliguori         qemu_log("OP:\n");
40631894f69aSRichard Henderson         tcg_dump_ops(s, false);
406493fcfe39Saliguori         qemu_log("\n");
4065fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
4066c896fe29Sbellard     }
4067c896fe29Sbellard #endif
4068c896fe29Sbellard 
4069bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
4070bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
4071bef16ab4SRichard Henderson     {
4072bef16ab4SRichard Henderson         TCGLabel *l;
4073bef16ab4SRichard Henderson         bool error = false;
4074bef16ab4SRichard Henderson 
4075bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
4076bef16ab4SRichard Henderson             if (unlikely(!l->present) && l->refs) {
4077bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
4078bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
4079bef16ab4SRichard Henderson                 error = true;
4080bef16ab4SRichard Henderson             }
4081bef16ab4SRichard Henderson         }
4082bef16ab4SRichard Henderson         assert(!error);
4083bef16ab4SRichard Henderson     }
4084bef16ab4SRichard Henderson #endif
4085bef16ab4SRichard Henderson 
4086c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
4087d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
4088c5cc28ffSAurelien Jarno #endif
4089c5cc28ffSAurelien Jarno 
40908f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
4091c45cb8bbSRichard Henderson     tcg_optimize(s);
40928f2e8c07SKirill Batuzov #endif
40938f2e8c07SKirill Batuzov 
4094a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4095d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
4096d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time - profile_getclock());
4097a23a9ec6Sbellard #endif
4098c5cc28ffSAurelien Jarno 
4099b4fc67c7SRichard Henderson     reachable_code_pass(s);
4100b83eabeaSRichard Henderson     liveness_pass_1(s);
41015a18407fSRichard Henderson 
41025a18407fSRichard Henderson     if (s->nb_indirects > 0) {
41035a18407fSRichard Henderson #ifdef DEBUG_DISAS
41045a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
41055a18407fSRichard Henderson                      && qemu_log_in_addr_range(tb->pc))) {
4106fc59d2d8SRobert Foley             FILE *logfile = qemu_log_lock();
41075a18407fSRichard Henderson             qemu_log("OP before indirect lowering:\n");
41081894f69aSRichard Henderson             tcg_dump_ops(s, false);
41095a18407fSRichard Henderson             qemu_log("\n");
4110fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
41115a18407fSRichard Henderson         }
41125a18407fSRichard Henderson #endif
41135a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
4114b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
41155a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
4116b83eabeaSRichard Henderson             liveness_pass_1(s);
41175a18407fSRichard Henderson         }
41185a18407fSRichard Henderson     }
4119c5cc28ffSAurelien Jarno 
4120a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4121d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time + profile_getclock());
4122a23a9ec6Sbellard #endif
4123c896fe29Sbellard 
4124c896fe29Sbellard #ifdef DEBUG_DISAS
4125d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
4126d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
4127fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
4128c5cc28ffSAurelien Jarno         qemu_log("OP after optimization and liveness analysis:\n");
41291894f69aSRichard Henderson         tcg_dump_ops(s, true);
413093fcfe39Saliguori         qemu_log("\n");
4131fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
4132c896fe29Sbellard     }
4133c896fe29Sbellard #endif
4134c896fe29Sbellard 
4135c896fe29Sbellard     tcg_reg_alloc_start(s);
4136c896fe29Sbellard 
4137db0c51a3SRichard Henderson     /*
4138db0c51a3SRichard Henderson      * Reset the buffer pointers when restarting after overflow.
4139db0c51a3SRichard Henderson      * TODO: Move this into translate-all.c with the rest of the
4140db0c51a3SRichard Henderson      * buffer management.  Having only this done here is confusing.
4141db0c51a3SRichard Henderson      */
4142db0c51a3SRichard Henderson     s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr);
4143db0c51a3SRichard Henderson     s->code_ptr = s->code_buf;
4144c896fe29Sbellard 
4145659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
41466001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
4147659ef5cbSRichard Henderson #endif
414857a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
414957a26946SRichard Henderson     s->pool_labels = NULL;
415057a26946SRichard Henderson #endif
41519ecefc84SRichard Henderson 
4152fca8a500SRichard Henderson     num_insns = -1;
415315fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
4154c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
4155b3db8758Sblueswir1 
4156c896fe29Sbellard #ifdef CONFIG_PROFILER
4157d73415a3SStefan Hajnoczi         qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
4158c896fe29Sbellard #endif
4159c45cb8bbSRichard Henderson 
4160c896fe29Sbellard         switch (opc) {
4161c896fe29Sbellard         case INDEX_op_mov_i32:
4162c896fe29Sbellard         case INDEX_op_mov_i64:
4163d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
4164dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
4165c896fe29Sbellard             break;
4166bab1671fSRichard Henderson         case INDEX_op_dup_vec:
4167bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
4168bab1671fSRichard Henderson             break;
4169765b842aSRichard Henderson         case INDEX_op_insn_start:
4170fca8a500SRichard Henderson             if (num_insns >= 0) {
41719f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
41729f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
41739f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
41749f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
4175fca8a500SRichard Henderson             }
4176fca8a500SRichard Henderson             num_insns++;
4177bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
4178bad729e2SRichard Henderson                 target_ulong a;
4179bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
4180efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
4181bad729e2SRichard Henderson #else
4182efee3746SRichard Henderson                 a = op->args[i];
4183bad729e2SRichard Henderson #endif
4184fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
4185bad729e2SRichard Henderson             }
4186c896fe29Sbellard             break;
41875ff9d6a4Sbellard         case INDEX_op_discard:
418843439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
41895ff9d6a4Sbellard             break;
4190c896fe29Sbellard         case INDEX_op_set_label:
4191e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
419292ab8e7dSRichard Henderson             tcg_out_label(s, arg_label(op->args[0]));
4193c896fe29Sbellard             break;
4194c896fe29Sbellard         case INDEX_op_call:
4195dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
4196c45cb8bbSRichard Henderson             break;
4197efe86b21SRichard Henderson         case INDEX_op_dup2_vec:
4198efe86b21SRichard Henderson             if (tcg_reg_alloc_dup2(s, op)) {
4199efe86b21SRichard Henderson                 break;
4200efe86b21SRichard Henderson             }
4201efe86b21SRichard Henderson             /* fall through */
4202c896fe29Sbellard         default:
420325c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
4204be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
4205c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
4206c896fe29Sbellard                faster to have specialized register allocator functions for
4207c896fe29Sbellard                some common argument patterns */
4208dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
4209c896fe29Sbellard             break;
4210c896fe29Sbellard         }
42118d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
4212c896fe29Sbellard         check_regs(s);
4213c896fe29Sbellard #endif
4214b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
4215b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
4216b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
4217b125f9dcSRichard Henderson            generating code without having to check during generation.  */
4218644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
4219b125f9dcSRichard Henderson             return -1;
4220b125f9dcSRichard Henderson         }
42216e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
42226e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
42236e6c4efeSRichard Henderson             return -2;
42246e6c4efeSRichard Henderson         }
4225c896fe29Sbellard     }
4226fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
4227fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
4228c45cb8bbSRichard Henderson 
4229b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
4230659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
4231aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
4232aeee05f5SRichard Henderson     if (i < 0) {
4233aeee05f5SRichard Henderson         return i;
423423dceda6SRichard Henderson     }
4235659ef5cbSRichard Henderson #endif
423657a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
42371768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
42381768987bSRichard Henderson     if (i < 0) {
42391768987bSRichard Henderson         return i;
424057a26946SRichard Henderson     }
424157a26946SRichard Henderson #endif
42427ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
42437ecd02a0SRichard Henderson         return -2;
42447ecd02a0SRichard Henderson     }
4245c896fe29Sbellard 
4246df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
4247c896fe29Sbellard     /* flush instruction cache */
4248db0c51a3SRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
4249db0c51a3SRichard Henderson                         (uintptr_t)s->code_buf,
42501da8de39SRichard Henderson                         tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
4251df5d2b16SRichard Henderson #endif
42522aeabc08SStefan Weil 
42531813e175SRichard Henderson     return tcg_current_code_size(s);
4254c896fe29Sbellard }
4255c896fe29Sbellard 
4256a23a9ec6Sbellard #ifdef CONFIG_PROFILER
42573de2faa9SMarkus Armbruster void tcg_dump_info(void)
4258a23a9ec6Sbellard {
4259c3fac113SEmilio G. Cota     TCGProfile prof = {};
4260c3fac113SEmilio G. Cota     const TCGProfile *s;
4261c3fac113SEmilio G. Cota     int64_t tb_count;
4262c3fac113SEmilio G. Cota     int64_t tb_div_count;
4263c3fac113SEmilio G. Cota     int64_t tot;
4264c3fac113SEmilio G. Cota 
4265c3fac113SEmilio G. Cota     tcg_profile_snapshot_counters(&prof);
4266c3fac113SEmilio G. Cota     s = &prof;
4267c3fac113SEmilio G. Cota     tb_count = s->tb_count;
4268c3fac113SEmilio G. Cota     tb_div_count = tb_count ? tb_count : 1;
4269c3fac113SEmilio G. Cota     tot = s->interm_time + s->code_time;
4270a23a9ec6Sbellard 
42713de2faa9SMarkus Armbruster     qemu_printf("JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
4272a23a9ec6Sbellard                 tot, tot / 2.4e9);
42733de2faa9SMarkus Armbruster     qemu_printf("translated TBs      %" PRId64 " (aborted=%" PRId64
42743de2faa9SMarkus Armbruster                 " %0.1f%%)\n",
4275fca8a500SRichard Henderson                 tb_count, s->tb_count1 - tb_count,
4276fca8a500SRichard Henderson                 (double)(s->tb_count1 - s->tb_count)
4277fca8a500SRichard Henderson                 / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
42783de2faa9SMarkus Armbruster     qemu_printf("avg ops/TB          %0.1f max=%d\n",
4279fca8a500SRichard Henderson                 (double)s->op_count / tb_div_count, s->op_count_max);
42803de2faa9SMarkus Armbruster     qemu_printf("deleted ops/TB      %0.2f\n",
4281fca8a500SRichard Henderson                 (double)s->del_op_count / tb_div_count);
42823de2faa9SMarkus Armbruster     qemu_printf("avg temps/TB        %0.2f max=%d\n",
4283fca8a500SRichard Henderson                 (double)s->temp_count / tb_div_count, s->temp_count_max);
42843de2faa9SMarkus Armbruster     qemu_printf("avg host code/TB    %0.1f\n",
4285fca8a500SRichard Henderson                 (double)s->code_out_len / tb_div_count);
42863de2faa9SMarkus Armbruster     qemu_printf("avg search data/TB  %0.1f\n",
4287fca8a500SRichard Henderson                 (double)s->search_out_len / tb_div_count);
4288a23a9ec6Sbellard 
42893de2faa9SMarkus Armbruster     qemu_printf("cycles/op           %0.1f\n",
4290a23a9ec6Sbellard                 s->op_count ? (double)tot / s->op_count : 0);
42913de2faa9SMarkus Armbruster     qemu_printf("cycles/in byte      %0.1f\n",
4292a23a9ec6Sbellard                 s->code_in_len ? (double)tot / s->code_in_len : 0);
42933de2faa9SMarkus Armbruster     qemu_printf("cycles/out byte     %0.1f\n",
4294a23a9ec6Sbellard                 s->code_out_len ? (double)tot / s->code_out_len : 0);
42953de2faa9SMarkus Armbruster     qemu_printf("cycles/search byte     %0.1f\n",
4296fca8a500SRichard Henderson                 s->search_out_len ? (double)tot / s->search_out_len : 0);
4297fca8a500SRichard Henderson     if (tot == 0) {
4298a23a9ec6Sbellard         tot = 1;
4299fca8a500SRichard Henderson     }
43003de2faa9SMarkus Armbruster     qemu_printf("  gen_interm time   %0.1f%%\n",
4301a23a9ec6Sbellard                 (double)s->interm_time / tot * 100.0);
43023de2faa9SMarkus Armbruster     qemu_printf("  gen_code time     %0.1f%%\n",
4303a23a9ec6Sbellard                 (double)s->code_time / tot * 100.0);
43043de2faa9SMarkus Armbruster     qemu_printf("optim./code time    %0.1f%%\n",
4305c5cc28ffSAurelien Jarno                 (double)s->opt_time / (s->code_time ? s->code_time : 1)
4306c5cc28ffSAurelien Jarno                 * 100.0);
43073de2faa9SMarkus Armbruster     qemu_printf("liveness/code time  %0.1f%%\n",
4308a23a9ec6Sbellard                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
43093de2faa9SMarkus Armbruster     qemu_printf("cpu_restore count   %" PRId64 "\n",
4310a23a9ec6Sbellard                 s->restore_count);
43113de2faa9SMarkus Armbruster     qemu_printf("  avg cycles        %0.1f\n",
4312a23a9ec6Sbellard                 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
4313a23a9ec6Sbellard }
4314a23a9ec6Sbellard #else
43153de2faa9SMarkus Armbruster void tcg_dump_info(void)
4316a23a9ec6Sbellard {
43173de2faa9SMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4318a23a9ec6Sbellard }
4319a23a9ec6Sbellard #endif
4320813da627SRichard Henderson 
4321813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
43225872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
43235872bbf2SRichard Henderson 
43245872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
43255872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
43265872bbf2SRichard Henderson 
43275872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
43285872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
43295872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
43305872bbf2SRichard Henderson 
43315872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
43325872bbf2SRichard Henderson */
4333813da627SRichard Henderson 
4334813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
4335813da627SRichard Henderson typedef enum {
4336813da627SRichard Henderson     JIT_NOACTION = 0,
4337813da627SRichard Henderson     JIT_REGISTER_FN,
4338813da627SRichard Henderson     JIT_UNREGISTER_FN
4339813da627SRichard Henderson } jit_actions_t;
4340813da627SRichard Henderson 
4341813da627SRichard Henderson struct jit_code_entry {
4342813da627SRichard Henderson     struct jit_code_entry *next_entry;
4343813da627SRichard Henderson     struct jit_code_entry *prev_entry;
4344813da627SRichard Henderson     const void *symfile_addr;
4345813da627SRichard Henderson     uint64_t symfile_size;
4346813da627SRichard Henderson };
4347813da627SRichard Henderson 
4348813da627SRichard Henderson struct jit_descriptor {
4349813da627SRichard Henderson     uint32_t version;
4350813da627SRichard Henderson     uint32_t action_flag;
4351813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
4352813da627SRichard Henderson     struct jit_code_entry *first_entry;
4353813da627SRichard Henderson };
4354813da627SRichard Henderson 
4355813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
4356813da627SRichard Henderson void __jit_debug_register_code(void)
4357813da627SRichard Henderson {
4358813da627SRichard Henderson     asm("");
4359813da627SRichard Henderson }
4360813da627SRichard Henderson 
4361813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
4362813da627SRichard Henderson    the version before we can set it.  */
4363813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
4364813da627SRichard Henderson 
4365813da627SRichard Henderson /* End GDB interface.  */
4366813da627SRichard Henderson 
4367813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
4368813da627SRichard Henderson {
4369813da627SRichard Henderson     const char *p = strtab + 1;
4370813da627SRichard Henderson 
4371813da627SRichard Henderson     while (1) {
4372813da627SRichard Henderson         if (strcmp(p, str) == 0) {
4373813da627SRichard Henderson             return p - strtab;
4374813da627SRichard Henderson         }
4375813da627SRichard Henderson         p += strlen(p) + 1;
4376813da627SRichard Henderson     }
4377813da627SRichard Henderson }
4378813da627SRichard Henderson 
4379755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size,
43802c90784aSRichard Henderson                                  const void *debug_frame,
43812c90784aSRichard Henderson                                  size_t debug_frame_size)
4382813da627SRichard Henderson {
43835872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
43845872bbf2SRichard Henderson         uint32_t  len;
43855872bbf2SRichard Henderson         uint16_t  version;
43865872bbf2SRichard Henderson         uint32_t  abbrev;
43875872bbf2SRichard Henderson         uint8_t   ptr_size;
43885872bbf2SRichard Henderson         uint8_t   cu_die;
43895872bbf2SRichard Henderson         uint16_t  cu_lang;
43905872bbf2SRichard Henderson         uintptr_t cu_low_pc;
43915872bbf2SRichard Henderson         uintptr_t cu_high_pc;
43925872bbf2SRichard Henderson         uint8_t   fn_die;
43935872bbf2SRichard Henderson         char      fn_name[16];
43945872bbf2SRichard Henderson         uintptr_t fn_low_pc;
43955872bbf2SRichard Henderson         uintptr_t fn_high_pc;
43965872bbf2SRichard Henderson         uint8_t   cu_eoc;
43975872bbf2SRichard Henderson     };
4398813da627SRichard Henderson 
4399813da627SRichard Henderson     struct ElfImage {
4400813da627SRichard Henderson         ElfW(Ehdr) ehdr;
4401813da627SRichard Henderson         ElfW(Phdr) phdr;
44025872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
44035872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
44045872bbf2SRichard Henderson         struct DebugInfo di;
44055872bbf2SRichard Henderson         uint8_t    da[24];
44065872bbf2SRichard Henderson         char       str[80];
44075872bbf2SRichard Henderson     };
44085872bbf2SRichard Henderson 
44095872bbf2SRichard Henderson     struct ElfImage *img;
44105872bbf2SRichard Henderson 
44115872bbf2SRichard Henderson     static const struct ElfImage img_template = {
44125872bbf2SRichard Henderson         .ehdr = {
44135872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
44145872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
44155872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
44165872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
44175872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
44185872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
44195872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
44205872bbf2SRichard Henderson             .e_type = ET_EXEC,
44215872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
44225872bbf2SRichard Henderson             .e_version = EV_CURRENT,
44235872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
44245872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
44255872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
44265872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
44275872bbf2SRichard Henderson             .e_phnum = 1,
44285872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
44295872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
44305872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
4431abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
4432abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
4433abbb3eaeSRichard Henderson #endif
4434abbb3eaeSRichard Henderson #ifdef ELF_OSABI
4435abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
4436abbb3eaeSRichard Henderson #endif
44375872bbf2SRichard Henderson         },
44385872bbf2SRichard Henderson         .phdr = {
44395872bbf2SRichard Henderson             .p_type = PT_LOAD,
44405872bbf2SRichard Henderson             .p_flags = PF_X,
44415872bbf2SRichard Henderson         },
44425872bbf2SRichard Henderson         .shdr = {
44435872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
44445872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
44455872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
44465872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
44475872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
44485872bbf2SRichard Henderson             [1] = { /* .text */
44495872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
44505872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
44515872bbf2SRichard Henderson             },
44525872bbf2SRichard Henderson             [2] = { /* .debug_info */
44535872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
44545872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
44555872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
44565872bbf2SRichard Henderson             },
44575872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
44585872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
44595872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
44605872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
44615872bbf2SRichard Henderson             },
44625872bbf2SRichard Henderson             [4] = { /* .debug_frame */
44635872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
44645872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
44655872bbf2SRichard Henderson             },
44665872bbf2SRichard Henderson             [5] = { /* .symtab */
44675872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
44685872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
44695872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
44705872bbf2SRichard Henderson                 .sh_info = 1,
44715872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
44725872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
44735872bbf2SRichard Henderson             },
44745872bbf2SRichard Henderson             [6] = { /* .strtab */
44755872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
44765872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
44775872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
44785872bbf2SRichard Henderson             }
44795872bbf2SRichard Henderson         },
44805872bbf2SRichard Henderson         .sym = {
44815872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
44825872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
44835872bbf2SRichard Henderson                 .st_shndx = 1,
44845872bbf2SRichard Henderson             }
44855872bbf2SRichard Henderson         },
44865872bbf2SRichard Henderson         .di = {
44875872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
44885872bbf2SRichard Henderson             .version = 2,
44895872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
44905872bbf2SRichard Henderson             .cu_die = 1,
44915872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
44925872bbf2SRichard Henderson             .fn_die = 2,
44935872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
44945872bbf2SRichard Henderson         },
44955872bbf2SRichard Henderson         .da = {
44965872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
44975872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
44985872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
44995872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
45005872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
45015872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
45025872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
45035872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
45045872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
45055872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
45065872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
45075872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
45085872bbf2SRichard Henderson             0           /* no more abbrev */
45095872bbf2SRichard Henderson         },
45105872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
45115872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
4512813da627SRichard Henderson     };
4513813da627SRichard Henderson 
4514813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
4515813da627SRichard Henderson     static struct jit_code_entry one_entry;
4516813da627SRichard Henderson 
45175872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
4518813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
45192c90784aSRichard Henderson     DebugFrameHeader *dfh;
4520813da627SRichard Henderson 
45215872bbf2SRichard Henderson     img = g_malloc(img_size);
45225872bbf2SRichard Henderson     *img = img_template;
4523813da627SRichard Henderson 
45245872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
45255872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
45265872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
4527813da627SRichard Henderson 
45285872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
45295872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
45305872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
4531813da627SRichard Henderson 
45325872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
45335872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
45345872bbf2SRichard Henderson 
45355872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
45365872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
45375872bbf2SRichard Henderson 
45385872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
45395872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
45405872bbf2SRichard Henderson 
45415872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
45425872bbf2SRichard Henderson     img->sym[1].st_value = buf;
45435872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
45445872bbf2SRichard Henderson 
45455872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
454645aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
45475872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
454845aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
4549813da627SRichard Henderson 
45502c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
45512c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
45522c90784aSRichard Henderson     dfh->fde.func_start = buf;
45532c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
45542c90784aSRichard Henderson 
4555813da627SRichard Henderson #ifdef DEBUG_JIT
4556813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
4557813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
4558813da627SRichard Henderson     {
4559813da627SRichard Henderson         FILE *f = fopen("/tmp/qemu.jit", "w+b");
4560813da627SRichard Henderson         if (f) {
45615872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
4562813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
4563813da627SRichard Henderson             }
4564813da627SRichard Henderson             fclose(f);
4565813da627SRichard Henderson         }
4566813da627SRichard Henderson     }
4567813da627SRichard Henderson #endif
4568813da627SRichard Henderson 
4569813da627SRichard Henderson     one_entry.symfile_addr = img;
4570813da627SRichard Henderson     one_entry.symfile_size = img_size;
4571813da627SRichard Henderson 
4572813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
4573813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
4574813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
4575813da627SRichard Henderson     __jit_debug_register_code();
4576813da627SRichard Henderson }
4577813da627SRichard Henderson #else
45785872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
45795872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
4580813da627SRichard Henderson 
4581755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
45822c90784aSRichard Henderson                                  const void *debug_frame,
45832c90784aSRichard Henderson                                  size_t debug_frame_size)
4584813da627SRichard Henderson {
4585813da627SRichard Henderson }
4586813da627SRichard Henderson 
4587755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size)
4588813da627SRichard Henderson {
4589813da627SRichard Henderson }
4590813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
4591db432672SRichard Henderson 
4592db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
4593db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
4594db432672SRichard Henderson {
4595db432672SRichard Henderson     g_assert_not_reached();
4596db432672SRichard Henderson }
4597db432672SRichard Henderson #endif
4598