xref: /qemu/tcg/tcg.c (revision 0c22e17658a583c3d37cd928653caebf6406abd4)
1c896fe29Sbellard /*
2c896fe29Sbellard  * Tiny Code Generator for QEMU
3c896fe29Sbellard  *
4c896fe29Sbellard  * Copyright (c) 2008 Fabrice Bellard
5c896fe29Sbellard  *
6c896fe29Sbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
7c896fe29Sbellard  * of this software and associated documentation files (the "Software"), to deal
8c896fe29Sbellard  * in the Software without restriction, including without limitation the rights
9c896fe29Sbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10c896fe29Sbellard  * copies of the Software, and to permit persons to whom the Software is
11c896fe29Sbellard  * furnished to do so, subject to the following conditions:
12c896fe29Sbellard  *
13c896fe29Sbellard  * The above copyright notice and this permission notice shall be included in
14c896fe29Sbellard  * all copies or substantial portions of the Software.
15c896fe29Sbellard  *
16c896fe29Sbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17c896fe29Sbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18c896fe29Sbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19c896fe29Sbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20c896fe29Sbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21c896fe29Sbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22c896fe29Sbellard  * THE SOFTWARE.
23c896fe29Sbellard  */
24c896fe29Sbellard 
25c896fe29Sbellard /* define it to use liveness analysis (better code) */
268f2e8c07SKirill Batuzov #define USE_TCG_OPTIMIZATIONS
27c896fe29Sbellard 
28757e725bSPeter Maydell #include "qemu/osdep.h"
29cca82982Saurel32 
30813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB.  */
31813da627SRichard Henderson #undef DEBUG_JIT
32813da627SRichard Henderson 
3372fd2efbSEmilio G. Cota #include "qemu/error-report.h"
34f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
351de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
36d4c51a0aSMarkus Armbruster #include "qemu/qemu-print.h"
371de7afc9SPaolo Bonzini #include "qemu/timer.h"
38084cfca1SRichard Henderson #include "qemu/cacheflush.h"
39ad768e6fSPeter Maydell #include "qemu/cacheinfo.h"
40c896fe29Sbellard 
41c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU
42c896fe29Sbellard    CPU definitions. Currently they are used for qemu_ld/st
43c896fe29Sbellard    instructions */
44c896fe29Sbellard #define NO_CPU_IO_DEFS
45c896fe29Sbellard 
4663c91552SPaolo Bonzini #include "exec/exec-all.h"
47dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
48813da627SRichard Henderson 
49edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX
50813da627SRichard Henderson # define ELF_CLASS  ELFCLASS32
51edee2579SRichard Henderson #else
52edee2579SRichard Henderson # define ELF_CLASS  ELFCLASS64
53813da627SRichard Henderson #endif
54e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
55813da627SRichard Henderson # define ELF_DATA   ELFDATA2MSB
56813da627SRichard Henderson #else
57813da627SRichard Henderson # define ELF_DATA   ELFDATA2LSB
58813da627SRichard Henderson #endif
59813da627SRichard Henderson 
60c896fe29Sbellard #include "elf.h"
61508127e2SPaolo Bonzini #include "exec/log.h"
62d2ba8026SRichard Henderson #include "tcg/tcg-ldst.h"
635ff7258cSRichard Henderson #include "tcg-internal.h"
64c896fe29Sbellard 
6522f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
6622f15579SRichard Henderson #include <ffi.h>
6722f15579SRichard Henderson #endif
6822f15579SRichard Henderson 
69139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and
70ce151109SPeter Maydell    used here. */
71e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s);
72e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
736ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
742ba7fae2SRichard Henderson                         intptr_t value, intptr_t addend);
75c896fe29Sbellard 
76497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts.  */
77497a22ebSRichard Henderson typedef struct {
78497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
79497a22ebSRichard Henderson     uint32_t id;
80497a22ebSRichard Henderson     uint8_t version;
81497a22ebSRichard Henderson     char augmentation[1];
82497a22ebSRichard Henderson     uint8_t code_align;
83497a22ebSRichard Henderson     uint8_t data_align;
84497a22ebSRichard Henderson     uint8_t return_column;
85497a22ebSRichard Henderson } DebugFrameCIE;
86497a22ebSRichard Henderson 
87497a22ebSRichard Henderson typedef struct QEMU_PACKED {
88497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
89497a22ebSRichard Henderson     uint32_t cie_offset;
90edee2579SRichard Henderson     uintptr_t func_start;
91edee2579SRichard Henderson     uintptr_t func_len;
92497a22ebSRichard Henderson } DebugFrameFDEHeader;
93497a22ebSRichard Henderson 
942c90784aSRichard Henderson typedef struct QEMU_PACKED {
952c90784aSRichard Henderson     DebugFrameCIE cie;
962c90784aSRichard Henderson     DebugFrameFDEHeader fde;
972c90784aSRichard Henderson } DebugFrameHeader;
982c90784aSRichard Henderson 
99755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
1002c90784aSRichard Henderson                                  const void *debug_frame,
1012c90784aSRichard Henderson                                  size_t debug_frame_size)
102813da627SRichard Henderson     __attribute__((unused));
103813da627SRichard Henderson 
104139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */
1052a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
106a05b5b9bSRichard Henderson                        intptr_t arg2);
10778113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
108c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1092a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
1105e8892dbSMiroslav Rezanina static void tcg_out_op(TCGContext *s, TCGOpcode opc,
1115e8892dbSMiroslav Rezanina                        const TCGArg args[TCG_MAX_OP_ARGS],
1125e8892dbSMiroslav Rezanina                        const int const_args[TCG_MAX_OP_ARGS]);
113d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec
114e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
115e7632cfaSRichard Henderson                             TCGReg dst, TCGReg src);
116d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
117d6ecb4a9SRichard Henderson                              TCGReg dst, TCGReg base, intptr_t offset);
1184e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1194e186175SRichard Henderson                              TCGReg dst, int64_t arg);
1205e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1215e8892dbSMiroslav Rezanina                            unsigned vecl, unsigned vece,
1225e8892dbSMiroslav Rezanina                            const TCGArg args[TCG_MAX_OP_ARGS],
1235e8892dbSMiroslav Rezanina                            const int const_args[TCG_MAX_OP_ARGS]);
124d2fd745fSRichard Henderson #else
125e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
126e7632cfaSRichard Henderson                                    TCGReg dst, TCGReg src)
127e7632cfaSRichard Henderson {
128e7632cfaSRichard Henderson     g_assert_not_reached();
129e7632cfaSRichard Henderson }
130d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
131d6ecb4a9SRichard Henderson                                     TCGReg dst, TCGReg base, intptr_t offset)
132d6ecb4a9SRichard Henderson {
133d6ecb4a9SRichard Henderson     g_assert_not_reached();
134d6ecb4a9SRichard Henderson }
1354e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1364e186175SRichard Henderson                                     TCGReg dst, int64_t arg)
137e7632cfaSRichard Henderson {
138e7632cfaSRichard Henderson     g_assert_not_reached();
139e7632cfaSRichard Henderson }
1405e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1415e8892dbSMiroslav Rezanina                                   unsigned vecl, unsigned vece,
1425e8892dbSMiroslav Rezanina                                   const TCGArg args[TCG_MAX_OP_ARGS],
1435e8892dbSMiroslav Rezanina                                   const int const_args[TCG_MAX_OP_ARGS])
144d2fd745fSRichard Henderson {
145d2fd745fSRichard Henderson     g_assert_not_reached();
146d2fd745fSRichard Henderson }
147d2fd745fSRichard Henderson #endif
1482a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
149a05b5b9bSRichard Henderson                        intptr_t arg2);
15059d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
15159d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
1527b7d8b2dSRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
1537b7d8b2dSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target,
1547b7d8b2dSRichard Henderson                          ffi_cif *cif);
1557b7d8b2dSRichard Henderson #else
1562be7d76bSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target);
1577b7d8b2dSRichard Henderson #endif
158a4fbbd77SRichard Henderson static bool tcg_target_const_match(int64_t val, TCGType type, int ct);
159659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
160aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s);
161659ef5cbSRichard Henderson #endif
162c896fe29Sbellard 
16342eb6dfcSRichard Henderson TCGContext tcg_init_ctx;
16442eb6dfcSRichard Henderson __thread TCGContext *tcg_ctx;
16542eb6dfcSRichard Henderson 
1665ff7258cSRichard Henderson TCGContext **tcg_ctxs;
1670e2d61cfSRichard Henderson unsigned int tcg_cur_ctxs;
1680e2d61cfSRichard Henderson unsigned int tcg_max_ctxs;
1691c2adb95SRichard Henderson TCGv_env cpu_env = 0;
170c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue;
171db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff;
172df2cce29SEmilio G. Cota 
173b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
174b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec;
175b91ccb31SRichard Henderson #endif
176b91ccb31SRichard Henderson 
177d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
178b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
179c896fe29Sbellard 
1801813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
1814196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
182c896fe29Sbellard {
183c896fe29Sbellard     *s->code_ptr++ = v;
184c896fe29Sbellard }
185c896fe29Sbellard 
1864196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
1874196dca6SPeter Maydell                                                       uint8_t v)
1885c53bb81SPeter Maydell {
1891813e175SRichard Henderson     *p = v;
1905c53bb81SPeter Maydell }
1911813e175SRichard Henderson #endif
1925c53bb81SPeter Maydell 
1931813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
1944196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
195c896fe29Sbellard {
1961813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
1971813e175SRichard Henderson         *s->code_ptr++ = v;
1981813e175SRichard Henderson     } else {
1991813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2004387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2011813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
2021813e175SRichard Henderson     }
203c896fe29Sbellard }
204c896fe29Sbellard 
2054196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2064196dca6SPeter Maydell                                                        uint16_t v)
2075c53bb81SPeter Maydell {
2081813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2091813e175SRichard Henderson         *p = v;
2101813e175SRichard Henderson     } else {
2115c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2125c53bb81SPeter Maydell     }
2131813e175SRichard Henderson }
2141813e175SRichard Henderson #endif
2155c53bb81SPeter Maydell 
2161813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
2174196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
218c896fe29Sbellard {
2191813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2201813e175SRichard Henderson         *s->code_ptr++ = v;
2211813e175SRichard Henderson     } else {
2221813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2234387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2241813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
2251813e175SRichard Henderson     }
226c896fe29Sbellard }
227c896fe29Sbellard 
2284196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
2294196dca6SPeter Maydell                                                        uint32_t v)
2305c53bb81SPeter Maydell {
2311813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2321813e175SRichard Henderson         *p = v;
2331813e175SRichard Henderson     } else {
2345c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2355c53bb81SPeter Maydell     }
2361813e175SRichard Henderson }
2371813e175SRichard Henderson #endif
2385c53bb81SPeter Maydell 
2391813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
2404196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
241ac26eb69SRichard Henderson {
2421813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2431813e175SRichard Henderson         *s->code_ptr++ = v;
2441813e175SRichard Henderson     } else {
2451813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2464387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2471813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
2481813e175SRichard Henderson     }
249ac26eb69SRichard Henderson }
250ac26eb69SRichard Henderson 
2514196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
2524196dca6SPeter Maydell                                                        uint64_t v)
2535c53bb81SPeter Maydell {
2541813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2551813e175SRichard Henderson         *p = v;
2561813e175SRichard Henderson     } else {
2575c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2585c53bb81SPeter Maydell     }
2591813e175SRichard Henderson }
2601813e175SRichard Henderson #endif
2615c53bb81SPeter Maydell 
262c896fe29Sbellard /* label relocation processing */
263c896fe29Sbellard 
2641813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
265bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
266c896fe29Sbellard {
2677ecd02a0SRichard Henderson     TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation));
268c896fe29Sbellard 
269c896fe29Sbellard     r->type = type;
270c896fe29Sbellard     r->ptr = code_ptr;
271c896fe29Sbellard     r->addend = addend;
2727ecd02a0SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
273c896fe29Sbellard }
274c896fe29Sbellard 
27592ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l)
276c896fe29Sbellard {
277eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
278c896fe29Sbellard     l->has_value = 1;
27992ab8e7dSRichard Henderson     l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr);
280c896fe29Sbellard }
281c896fe29Sbellard 
28242a268c2SRichard Henderson TCGLabel *gen_new_label(void)
283c896fe29Sbellard {
284b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
28551e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
286c896fe29Sbellard 
2877ecd02a0SRichard Henderson     memset(l, 0, sizeof(TCGLabel));
2887ecd02a0SRichard Henderson     l->id = s->nb_labels++;
2897ecd02a0SRichard Henderson     QSIMPLEQ_INIT(&l->relocs);
2907ecd02a0SRichard Henderson 
291bef16ab4SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
29242a268c2SRichard Henderson 
29342a268c2SRichard Henderson     return l;
294c896fe29Sbellard }
295c896fe29Sbellard 
2967ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s)
2977ecd02a0SRichard Henderson {
2987ecd02a0SRichard Henderson     TCGLabel *l;
2997ecd02a0SRichard Henderson 
3007ecd02a0SRichard Henderson     QSIMPLEQ_FOREACH(l, &s->labels, next) {
3017ecd02a0SRichard Henderson         TCGRelocation *r;
3027ecd02a0SRichard Henderson         uintptr_t value = l->u.value;
3037ecd02a0SRichard Henderson 
3047ecd02a0SRichard Henderson         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
3057ecd02a0SRichard Henderson             if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
3067ecd02a0SRichard Henderson                 return false;
3077ecd02a0SRichard Henderson             }
3087ecd02a0SRichard Henderson         }
3097ecd02a0SRichard Henderson     }
3107ecd02a0SRichard Henderson     return true;
3117ecd02a0SRichard Henderson }
3127ecd02a0SRichard Henderson 
3139f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3149f754620SRichard Henderson {
315f14bed3fSRichard Henderson     /*
316f14bed3fSRichard Henderson      * We will check for overflow at the end of the opcode loop in
317f14bed3fSRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
318f14bed3fSRichard Henderson      */
319f14bed3fSRichard Henderson     s->tb_jmp_reset_offset[which] = tcg_current_code_size(s);
3209f754620SRichard Henderson }
3219f754620SRichard Henderson 
322db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */
3238905770bSMarc-André Lureau static G_NORETURN
3248905770bSMarc-André Lureau void tcg_raise_tb_overflow(TCGContext *s)
325db6b7d0cSRichard Henderson {
326db6b7d0cSRichard Henderson     siglongjmp(s->jmp_trans, -2);
327db6b7d0cSRichard Henderson }
328db6b7d0cSRichard Henderson 
3294c22e840SRichard Henderson #define C_PFX1(P, A)                    P##A
3304c22e840SRichard Henderson #define C_PFX2(P, A, B)                 P##A##_##B
3314c22e840SRichard Henderson #define C_PFX3(P, A, B, C)              P##A##_##B##_##C
3324c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D)           P##A##_##B##_##C##_##D
3334c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E)        P##A##_##B##_##C##_##D##_##E
3344c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F)     P##A##_##B##_##C##_##D##_##E##_##F
3354c22e840SRichard Henderson 
3364c22e840SRichard Henderson /* Define an enumeration for the various combinations. */
3374c22e840SRichard Henderson 
3384c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1),
3394c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2),
3404c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3),
3414c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4),
3424c22e840SRichard Henderson 
3434c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1),
3444c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2),
3454c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3),
3464c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4),
3474c22e840SRichard Henderson 
3484c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2),
3494c22e840SRichard Henderson 
3504c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1),
3514c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2),
3524c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3),
3534c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4),
3544c22e840SRichard Henderson 
3554c22e840SRichard Henderson typedef enum {
3564c22e840SRichard Henderson #include "tcg-target-con-set.h"
3574c22e840SRichard Henderson } TCGConstraintSetIndex;
3584c22e840SRichard Henderson 
3594c22e840SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode);
3604c22e840SRichard Henderson 
3614c22e840SRichard Henderson #undef C_O0_I1
3624c22e840SRichard Henderson #undef C_O0_I2
3634c22e840SRichard Henderson #undef C_O0_I3
3644c22e840SRichard Henderson #undef C_O0_I4
3654c22e840SRichard Henderson #undef C_O1_I1
3664c22e840SRichard Henderson #undef C_O1_I2
3674c22e840SRichard Henderson #undef C_O1_I3
3684c22e840SRichard Henderson #undef C_O1_I4
3694c22e840SRichard Henderson #undef C_N1_I2
3704c22e840SRichard Henderson #undef C_O2_I1
3714c22e840SRichard Henderson #undef C_O2_I2
3724c22e840SRichard Henderson #undef C_O2_I3
3734c22e840SRichard Henderson #undef C_O2_I4
3744c22e840SRichard Henderson 
3754c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */
3764c22e840SRichard Henderson 
3774c22e840SRichard Henderson #define C_O0_I1(I1)                     { .args_ct_str = { #I1 } },
3784c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 { .args_ct_str = { #I1, #I2 } },
3794c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             { .args_ct_str = { #I1, #I2, #I3 } },
3804c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         { .args_ct_str = { #I1, #I2, #I3, #I4 } },
3814c22e840SRichard Henderson 
3824c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 { .args_ct_str = { #O1, #I1 } },
3834c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             { .args_ct_str = { #O1, #I1, #I2 } },
3844c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         { .args_ct_str = { #O1, #I1, #I2, #I3 } },
3854c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } },
3864c22e840SRichard Henderson 
3874c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             { .args_ct_str = { "&" #O1, #I1, #I2 } },
3884c22e840SRichard Henderson 
3894c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             { .args_ct_str = { #O1, #O2, #I1 } },
3904c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         { .args_ct_str = { #O1, #O2, #I1, #I2 } },
3914c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } },
3924c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } },
3934c22e840SRichard Henderson 
3944c22e840SRichard Henderson static const TCGTargetOpDef constraint_sets[] = {
3954c22e840SRichard Henderson #include "tcg-target-con-set.h"
3964c22e840SRichard Henderson };
3974c22e840SRichard Henderson 
3984c22e840SRichard Henderson 
3994c22e840SRichard Henderson #undef C_O0_I1
4004c22e840SRichard Henderson #undef C_O0_I2
4014c22e840SRichard Henderson #undef C_O0_I3
4024c22e840SRichard Henderson #undef C_O0_I4
4034c22e840SRichard Henderson #undef C_O1_I1
4044c22e840SRichard Henderson #undef C_O1_I2
4054c22e840SRichard Henderson #undef C_O1_I3
4064c22e840SRichard Henderson #undef C_O1_I4
4074c22e840SRichard Henderson #undef C_N1_I2
4084c22e840SRichard Henderson #undef C_O2_I1
4094c22e840SRichard Henderson #undef C_O2_I2
4104c22e840SRichard Henderson #undef C_O2_I3
4114c22e840SRichard Henderson #undef C_O2_I4
4124c22e840SRichard Henderson 
4134c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */
4144c22e840SRichard Henderson 
4154c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1)
4164c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2)
4174c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3)
4184c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4)
4194c22e840SRichard Henderson 
4204c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1)
4214c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2)
4224c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3)
4234c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4)
4244c22e840SRichard Henderson 
4254c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2)
4264c22e840SRichard Henderson 
4274c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1)
4284c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2)
4294c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3)
4304c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4)
4314c22e840SRichard Henderson 
432139c1837SPaolo Bonzini #include "tcg-target.c.inc"
433c896fe29Sbellard 
43438b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s)
43538b47b19SEmilio G. Cota {
43638b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
43738b47b19SEmilio G. Cota     s->plugin_tb = g_new0(struct qemu_plugin_tb, 1);
43838b47b19SEmilio G. Cota     s->plugin_tb->insns =
43938b47b19SEmilio G. Cota         g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn);
44038b47b19SEmilio G. Cota #endif
44138b47b19SEmilio G. Cota }
44238b47b19SEmilio G. Cota 
443e8feb96fSEmilio G. Cota /*
4443468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
4453468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
4463468b59eSEmilio G. Cota  * before initiating translation.
4473468b59eSEmilio G. Cota  *
4483468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
4493468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
4503468b59eSEmilio G. Cota  *
4513468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
4523468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
4533468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
4543468b59eSEmilio G. Cota  *
4553468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
4563468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
4573468b59eSEmilio G. Cota  */
4583468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
4593468b59eSEmilio G. Cota void tcg_register_thread(void)
4603468b59eSEmilio G. Cota {
4613468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
4623468b59eSEmilio G. Cota }
4633468b59eSEmilio G. Cota #else
4643468b59eSEmilio G. Cota void tcg_register_thread(void)
4653468b59eSEmilio G. Cota {
4663468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
4673468b59eSEmilio G. Cota     unsigned int i, n;
4683468b59eSEmilio G. Cota 
4693468b59eSEmilio G. Cota     *s = tcg_init_ctx;
4703468b59eSEmilio G. Cota 
4713468b59eSEmilio G. Cota     /* Relink mem_base.  */
4723468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
4733468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
4743468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
4753468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
4763468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
4773468b59eSEmilio G. Cota         }
4783468b59eSEmilio G. Cota     }
4793468b59eSEmilio G. Cota 
4803468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
4810e2d61cfSRichard Henderson     n = qatomic_fetch_inc(&tcg_cur_ctxs);
4820e2d61cfSRichard Henderson     g_assert(n < tcg_max_ctxs);
483d73415a3SStefan Hajnoczi     qatomic_set(&tcg_ctxs[n], s);
4843468b59eSEmilio G. Cota 
48538b47b19SEmilio G. Cota     if (n > 0) {
48638b47b19SEmilio G. Cota         alloc_tcg_plugin_context(s);
487bf042e8eSRichard Henderson         tcg_region_initial_alloc(s);
48838b47b19SEmilio G. Cota     }
48938b47b19SEmilio G. Cota 
4903468b59eSEmilio G. Cota     tcg_ctx = s;
4913468b59eSEmilio G. Cota }
4923468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
4933468b59eSEmilio G. Cota 
494c896fe29Sbellard /* pool based memory allocation */
495c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
496c896fe29Sbellard {
497c896fe29Sbellard     TCGPool *p;
498c896fe29Sbellard     int pool_size;
499c896fe29Sbellard 
500c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
501c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
5027267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
503c896fe29Sbellard         p->size = size;
5044055299eSKirill Batuzov         p->next = s->pool_first_large;
5054055299eSKirill Batuzov         s->pool_first_large = p;
5064055299eSKirill Batuzov         return p->data;
507c896fe29Sbellard     } else {
508c896fe29Sbellard         p = s->pool_current;
509c896fe29Sbellard         if (!p) {
510c896fe29Sbellard             p = s->pool_first;
511c896fe29Sbellard             if (!p)
512c896fe29Sbellard                 goto new_pool;
513c896fe29Sbellard         } else {
514c896fe29Sbellard             if (!p->next) {
515c896fe29Sbellard             new_pool:
516c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
5177267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
518c896fe29Sbellard                 p->size = pool_size;
519c896fe29Sbellard                 p->next = NULL;
520a813e36fSRichard Henderson                 if (s->pool_current) {
521c896fe29Sbellard                     s->pool_current->next = p;
522a813e36fSRichard Henderson                 } else {
523c896fe29Sbellard                     s->pool_first = p;
524a813e36fSRichard Henderson                 }
525c896fe29Sbellard             } else {
526c896fe29Sbellard                 p = p->next;
527c896fe29Sbellard             }
528c896fe29Sbellard         }
529c896fe29Sbellard     }
530c896fe29Sbellard     s->pool_current = p;
531c896fe29Sbellard     s->pool_cur = p->data + size;
532c896fe29Sbellard     s->pool_end = p->data + p->size;
533c896fe29Sbellard     return p->data;
534c896fe29Sbellard }
535c896fe29Sbellard 
536c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
537c896fe29Sbellard {
5384055299eSKirill Batuzov     TCGPool *p, *t;
5394055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
5404055299eSKirill Batuzov         t = p->next;
5414055299eSKirill Batuzov         g_free(p);
5424055299eSKirill Batuzov     }
5434055299eSKirill Batuzov     s->pool_first_large = NULL;
544c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
545c896fe29Sbellard     s->pool_current = NULL;
546c896fe29Sbellard }
547c896fe29Sbellard 
5482ef6175aSRichard Henderson #include "exec/helper-proto.h"
5492ef6175aSRichard Henderson 
55039004a71SRichard Henderson static TCGHelperInfo all_helpers[] = {
5512ef6175aSRichard Henderson #include "exec/helper-tcg.h"
552100b5e01SRichard Henderson };
553619205fdSEmilio G. Cota static GHashTable *helper_table;
554100b5e01SRichard Henderson 
55522f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
55622f15579SRichard Henderson static GHashTable *ffi_table;
55722f15579SRichard Henderson 
558c6ef8c7bSPhilippe Mathieu-Daudé static ffi_type *typecode_to_ffi(int argmask)
559c6ef8c7bSPhilippe Mathieu-Daudé {
560c6ef8c7bSPhilippe Mathieu-Daudé     switch (argmask) {
561c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_void:
562c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_void;
563c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_i32:
564c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_uint32;
565c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_s32:
566c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_sint32;
567c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_i64:
568c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_uint64;
569c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_s64:
570c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_sint64;
571c6ef8c7bSPhilippe Mathieu-Daudé     case dh_typecode_ptr:
572c6ef8c7bSPhilippe Mathieu-Daudé         return &ffi_type_pointer;
573c6ef8c7bSPhilippe Mathieu-Daudé     }
574c6ef8c7bSPhilippe Mathieu-Daudé     g_assert_not_reached();
575c6ef8c7bSPhilippe Mathieu-Daudé }
576*0c22e176SPhilippe Mathieu-Daudé 
577*0c22e176SPhilippe Mathieu-Daudé static void init_ffi_layouts(void)
578*0c22e176SPhilippe Mathieu-Daudé {
579*0c22e176SPhilippe Mathieu-Daudé     /* g_direct_hash/equal for direct comparisons on uint32_t.  */
580*0c22e176SPhilippe Mathieu-Daudé     ffi_table = g_hash_table_new(NULL, NULL);
581*0c22e176SPhilippe Mathieu-Daudé     for (int i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
582*0c22e176SPhilippe Mathieu-Daudé         uint32_t typemask = all_helpers[i].typemask;
583*0c22e176SPhilippe Mathieu-Daudé         gpointer hash = (gpointer)(uintptr_t)typemask;
584*0c22e176SPhilippe Mathieu-Daudé         struct {
585*0c22e176SPhilippe Mathieu-Daudé             ffi_cif cif;
586*0c22e176SPhilippe Mathieu-Daudé             ffi_type *args[];
587*0c22e176SPhilippe Mathieu-Daudé         } *ca;
588*0c22e176SPhilippe Mathieu-Daudé         ffi_status status;
589*0c22e176SPhilippe Mathieu-Daudé         int nargs;
590*0c22e176SPhilippe Mathieu-Daudé 
591*0c22e176SPhilippe Mathieu-Daudé         if (g_hash_table_lookup(ffi_table, hash)) {
592*0c22e176SPhilippe Mathieu-Daudé             continue;
593*0c22e176SPhilippe Mathieu-Daudé         }
594*0c22e176SPhilippe Mathieu-Daudé 
595*0c22e176SPhilippe Mathieu-Daudé         /* Ignoring the return type, find the last non-zero field. */
596*0c22e176SPhilippe Mathieu-Daudé         nargs = 32 - clz32(typemask >> 3);
597*0c22e176SPhilippe Mathieu-Daudé         nargs = DIV_ROUND_UP(nargs, 3);
598*0c22e176SPhilippe Mathieu-Daudé 
599*0c22e176SPhilippe Mathieu-Daudé         ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *));
600*0c22e176SPhilippe Mathieu-Daudé         ca->cif.rtype = typecode_to_ffi(typemask & 7);
601*0c22e176SPhilippe Mathieu-Daudé         ca->cif.nargs = nargs;
602*0c22e176SPhilippe Mathieu-Daudé 
603*0c22e176SPhilippe Mathieu-Daudé         if (nargs != 0) {
604*0c22e176SPhilippe Mathieu-Daudé             ca->cif.arg_types = ca->args;
605*0c22e176SPhilippe Mathieu-Daudé             for (int j = 0; j < nargs; ++j) {
606*0c22e176SPhilippe Mathieu-Daudé                 int typecode = extract32(typemask, (j + 1) * 3, 3);
607*0c22e176SPhilippe Mathieu-Daudé                 ca->args[j] = typecode_to_ffi(typecode);
608*0c22e176SPhilippe Mathieu-Daudé             }
609*0c22e176SPhilippe Mathieu-Daudé         }
610*0c22e176SPhilippe Mathieu-Daudé 
611*0c22e176SPhilippe Mathieu-Daudé         status = ffi_prep_cif(&ca->cif, FFI_DEFAULT_ABI, nargs,
612*0c22e176SPhilippe Mathieu-Daudé                               ca->cif.rtype, ca->cif.arg_types);
613*0c22e176SPhilippe Mathieu-Daudé         assert(status == FFI_OK);
614*0c22e176SPhilippe Mathieu-Daudé 
615*0c22e176SPhilippe Mathieu-Daudé         g_hash_table_insert(ffi_table, hash, (gpointer)&ca->cif);
616*0c22e176SPhilippe Mathieu-Daudé     }
617*0c22e176SPhilippe Mathieu-Daudé }
618*0c22e176SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG_INTERPRETER */
61922f15579SRichard Henderson 
62039004a71SRichard Henderson typedef struct TCGCumulativeArgs {
62139004a71SRichard Henderson     int arg_idx;                /* tcg_gen_callN args[] */
62239004a71SRichard Henderson     int info_in_idx;            /* TCGHelperInfo in[] */
62339004a71SRichard Henderson     int arg_slot;               /* regs+stack slot */
62439004a71SRichard Henderson     int ref_slot;               /* stack slots for references */
62539004a71SRichard Henderson } TCGCumulativeArgs;
62639004a71SRichard Henderson 
62739004a71SRichard Henderson static void layout_arg_even(TCGCumulativeArgs *cum)
62839004a71SRichard Henderson {
62939004a71SRichard Henderson     cum->arg_slot += cum->arg_slot & 1;
63039004a71SRichard Henderson }
63139004a71SRichard Henderson 
63239004a71SRichard Henderson static void layout_arg_1(TCGCumulativeArgs *cum, TCGHelperInfo *info,
63339004a71SRichard Henderson                          TCGCallArgumentKind kind)
63439004a71SRichard Henderson {
63539004a71SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
63639004a71SRichard Henderson 
63739004a71SRichard Henderson     *loc = (TCGCallArgumentLoc){
63839004a71SRichard Henderson         .kind = kind,
63939004a71SRichard Henderson         .arg_idx = cum->arg_idx,
64039004a71SRichard Henderson         .arg_slot = cum->arg_slot,
64139004a71SRichard Henderson     };
64239004a71SRichard Henderson     cum->info_in_idx++;
64339004a71SRichard Henderson     cum->arg_slot++;
64439004a71SRichard Henderson }
64539004a71SRichard Henderson 
64639004a71SRichard Henderson static void layout_arg_normal_n(TCGCumulativeArgs *cum,
64739004a71SRichard Henderson                                 TCGHelperInfo *info, int n)
64839004a71SRichard Henderson {
64939004a71SRichard Henderson     TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx];
65039004a71SRichard Henderson 
65139004a71SRichard Henderson     for (int i = 0; i < n; ++i) {
65239004a71SRichard Henderson         /* Layout all using the same arg_idx, adjusting the subindex. */
65339004a71SRichard Henderson         loc[i] = (TCGCallArgumentLoc){
65439004a71SRichard Henderson             .kind = TCG_CALL_ARG_NORMAL,
65539004a71SRichard Henderson             .arg_idx = cum->arg_idx,
65639004a71SRichard Henderson             .tmp_subindex = i,
65739004a71SRichard Henderson             .arg_slot = cum->arg_slot + i,
65839004a71SRichard Henderson         };
65939004a71SRichard Henderson     }
66039004a71SRichard Henderson     cum->info_in_idx += n;
66139004a71SRichard Henderson     cum->arg_slot += n;
66239004a71SRichard Henderson }
66339004a71SRichard Henderson 
66439004a71SRichard Henderson static void init_call_layout(TCGHelperInfo *info)
66539004a71SRichard Henderson {
66639004a71SRichard Henderson     int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs);
66739004a71SRichard Henderson     int max_stk_slots = TCG_STATIC_CALL_ARGS_SIZE / sizeof(tcg_target_long);
66839004a71SRichard Henderson     unsigned typemask = info->typemask;
66939004a71SRichard Henderson     unsigned typecode;
67039004a71SRichard Henderson     TCGCumulativeArgs cum = { };
67139004a71SRichard Henderson 
67239004a71SRichard Henderson     /*
67339004a71SRichard Henderson      * Parse and place any function return value.
67439004a71SRichard Henderson      */
67539004a71SRichard Henderson     typecode = typemask & 7;
67639004a71SRichard Henderson     switch (typecode) {
67739004a71SRichard Henderson     case dh_typecode_void:
67839004a71SRichard Henderson         info->nr_out = 0;
67939004a71SRichard Henderson         break;
68039004a71SRichard Henderson     case dh_typecode_i32:
68139004a71SRichard Henderson     case dh_typecode_s32:
68239004a71SRichard Henderson     case dh_typecode_ptr:
68339004a71SRichard Henderson         info->nr_out = 1;
68439004a71SRichard Henderson         info->out_kind = TCG_CALL_RET_NORMAL;
68539004a71SRichard Henderson         break;
68639004a71SRichard Henderson     case dh_typecode_i64:
68739004a71SRichard Henderson     case dh_typecode_s64:
68839004a71SRichard Henderson         info->nr_out = 64 / TCG_TARGET_REG_BITS;
68939004a71SRichard Henderson         info->out_kind = TCG_CALL_RET_NORMAL;
69039004a71SRichard Henderson         break;
69139004a71SRichard Henderson     default:
69239004a71SRichard Henderson         g_assert_not_reached();
69339004a71SRichard Henderson     }
69439004a71SRichard Henderson     assert(info->nr_out <= ARRAY_SIZE(tcg_target_call_oarg_regs));
69539004a71SRichard Henderson 
69639004a71SRichard Henderson     /*
69739004a71SRichard Henderson      * Parse and place function arguments.
69839004a71SRichard Henderson      */
69939004a71SRichard Henderson     for (typemask >>= 3; typemask; typemask >>= 3, cum.arg_idx++) {
70039004a71SRichard Henderson         TCGCallArgumentKind kind;
70139004a71SRichard Henderson         TCGType type;
70239004a71SRichard Henderson 
70339004a71SRichard Henderson         typecode = typemask & 7;
70439004a71SRichard Henderson         switch (typecode) {
70539004a71SRichard Henderson         case dh_typecode_i32:
70639004a71SRichard Henderson         case dh_typecode_s32:
70739004a71SRichard Henderson             type = TCG_TYPE_I32;
70839004a71SRichard Henderson             break;
70939004a71SRichard Henderson         case dh_typecode_i64:
71039004a71SRichard Henderson         case dh_typecode_s64:
71139004a71SRichard Henderson             type = TCG_TYPE_I64;
71239004a71SRichard Henderson             break;
71339004a71SRichard Henderson         case dh_typecode_ptr:
71439004a71SRichard Henderson             type = TCG_TYPE_PTR;
71539004a71SRichard Henderson             break;
71639004a71SRichard Henderson         default:
71739004a71SRichard Henderson             g_assert_not_reached();
71839004a71SRichard Henderson         }
71939004a71SRichard Henderson 
72039004a71SRichard Henderson         switch (type) {
72139004a71SRichard Henderson         case TCG_TYPE_I32:
72239004a71SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I32) {
72339004a71SRichard Henderson             case TCG_CALL_ARG_EVEN:
72439004a71SRichard Henderson                 layout_arg_even(&cum);
72539004a71SRichard Henderson                 /* fall through */
72639004a71SRichard Henderson             case TCG_CALL_ARG_NORMAL:
72739004a71SRichard Henderson                 layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
72839004a71SRichard Henderson                 break;
72939004a71SRichard Henderson             case TCG_CALL_ARG_EXTEND:
73039004a71SRichard Henderson                 kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1);
73139004a71SRichard Henderson                 layout_arg_1(&cum, info, kind);
73239004a71SRichard Henderson                 break;
73339004a71SRichard Henderson             default:
73439004a71SRichard Henderson                 qemu_build_not_reached();
73539004a71SRichard Henderson             }
73639004a71SRichard Henderson             break;
73739004a71SRichard Henderson 
73839004a71SRichard Henderson         case TCG_TYPE_I64:
73939004a71SRichard Henderson             switch (TCG_TARGET_CALL_ARG_I64) {
74039004a71SRichard Henderson             case TCG_CALL_ARG_EVEN:
74139004a71SRichard Henderson                 layout_arg_even(&cum);
74239004a71SRichard Henderson                 /* fall through */
74339004a71SRichard Henderson             case TCG_CALL_ARG_NORMAL:
74439004a71SRichard Henderson                 if (TCG_TARGET_REG_BITS == 32) {
74539004a71SRichard Henderson                     layout_arg_normal_n(&cum, info, 2);
74639004a71SRichard Henderson                 } else {
74739004a71SRichard Henderson                     layout_arg_1(&cum, info, TCG_CALL_ARG_NORMAL);
74839004a71SRichard Henderson                 }
74939004a71SRichard Henderson                 break;
75039004a71SRichard Henderson             default:
75139004a71SRichard Henderson                 qemu_build_not_reached();
75239004a71SRichard Henderson             }
75339004a71SRichard Henderson             break;
75439004a71SRichard Henderson 
75539004a71SRichard Henderson         default:
75639004a71SRichard Henderson             g_assert_not_reached();
75739004a71SRichard Henderson         }
75839004a71SRichard Henderson     }
75939004a71SRichard Henderson     info->nr_in = cum.info_in_idx;
76039004a71SRichard Henderson 
76139004a71SRichard Henderson     /* Validate that we didn't overrun the input array. */
76239004a71SRichard Henderson     assert(cum.info_in_idx <= ARRAY_SIZE(info->in));
76339004a71SRichard Henderson     /* Validate the backend has enough argument space. */
76439004a71SRichard Henderson     assert(cum.arg_slot <= max_reg_slots + max_stk_slots);
76539004a71SRichard Henderson     assert(cum.ref_slot <= max_stk_slots);
76639004a71SRichard Henderson }
76739004a71SRichard Henderson 
76891478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
769f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
7701c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
7711c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
77291478cefSRichard Henderson 
77343b972b7SRichard Henderson static void tcg_context_init(unsigned max_cpus)
774c896fe29Sbellard {
775a76aabd3SRichard Henderson     TCGContext *s = &tcg_init_ctx;
776100b5e01SRichard Henderson     int op, total_args, n, i;
777c896fe29Sbellard     TCGOpDef *def;
778c896fe29Sbellard     TCGArgConstraint *args_ct;
7791c2adb95SRichard Henderson     TCGTemp *ts;
780c896fe29Sbellard 
781c896fe29Sbellard     memset(s, 0, sizeof(*s));
782c896fe29Sbellard     s->nb_globals = 0;
783c896fe29Sbellard 
784c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
785c896fe29Sbellard        space */
786c896fe29Sbellard     total_args = 0;
787c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
788c896fe29Sbellard         def = &tcg_op_defs[op];
789c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
790c896fe29Sbellard         total_args += n;
791c896fe29Sbellard     }
792c896fe29Sbellard 
793bc2b17e6SRichard Henderson     args_ct = g_new0(TCGArgConstraint, total_args);
794c896fe29Sbellard 
795c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
796c896fe29Sbellard         def = &tcg_op_defs[op];
797c896fe29Sbellard         def->args_ct = args_ct;
798c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
799c896fe29Sbellard         args_ct += n;
800c896fe29Sbellard     }
801c896fe29Sbellard 
8025cd8f621SRichard Henderson     /* Register helpers.  */
80384fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
804619205fdSEmilio G. Cota     helper_table = g_hash_table_new(NULL, NULL);
80584fd9dd3SRichard Henderson 
806100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
80739004a71SRichard Henderson         init_call_layout(&all_helpers[i]);
80884fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
80972866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
810100b5e01SRichard Henderson     }
8115cd8f621SRichard Henderson 
81222f15579SRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
813*0c22e176SPhilippe Mathieu-Daudé     init_ffi_layouts();
81422f15579SRichard Henderson #endif
81522f15579SRichard Henderson 
816c896fe29Sbellard     tcg_target_init(s);
817f69d277eSRichard Henderson     process_op_defs(s);
81891478cefSRichard Henderson 
81991478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
82091478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
82191478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
82291478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
82391478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
82491478cefSRichard Henderson             break;
82591478cefSRichard Henderson         }
82691478cefSRichard Henderson     }
82791478cefSRichard Henderson     for (i = 0; i < n; ++i) {
82891478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
82991478cefSRichard Henderson     }
83091478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
83191478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
83291478cefSRichard Henderson     }
833b1311c4aSEmilio G. Cota 
83438b47b19SEmilio G. Cota     alloc_tcg_plugin_context(s);
83538b47b19SEmilio G. Cota 
836b1311c4aSEmilio G. Cota     tcg_ctx = s;
8373468b59eSEmilio G. Cota     /*
8383468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
8393468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
8403468b59eSEmilio G. Cota      * reasoning behind this.
8413468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
8423468b59eSEmilio G. Cota      */
8433468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
844df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
8450e2d61cfSRichard Henderson     tcg_cur_ctxs = 1;
8460e2d61cfSRichard Henderson     tcg_max_ctxs = 1;
8473468b59eSEmilio G. Cota #else
8480e2d61cfSRichard Henderson     tcg_max_ctxs = max_cpus;
8490e2d61cfSRichard Henderson     tcg_ctxs = g_new0(TCGContext *, max_cpus);
8503468b59eSEmilio G. Cota #endif
8511c2adb95SRichard Henderson 
8521c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
8531c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
8541c2adb95SRichard Henderson     cpu_env = temp_tcgv_ptr(ts);
8559002ec79SRichard Henderson }
856b03cce8eSbellard 
85743b972b7SRichard Henderson void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus)
858a76aabd3SRichard Henderson {
85943b972b7SRichard Henderson     tcg_context_init(max_cpus);
86043b972b7SRichard Henderson     tcg_region_init(tb_size, splitwx, max_cpus);
861a76aabd3SRichard Henderson }
862a76aabd3SRichard Henderson 
8636e3b2bfdSEmilio G. Cota /*
8646e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
8656e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
8666e3b2bfdSEmilio G. Cota  */
8676e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
8686e3b2bfdSEmilio G. Cota {
8696e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
8706e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
8716e3b2bfdSEmilio G. Cota     void *next;
8726e3b2bfdSEmilio G. Cota 
873e8feb96fSEmilio G. Cota  retry:
8746e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
8756e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
8766e3b2bfdSEmilio G. Cota 
8776e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
878e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
8796e3b2bfdSEmilio G. Cota             return NULL;
8806e3b2bfdSEmilio G. Cota         }
881e8feb96fSEmilio G. Cota         goto retry;
882e8feb96fSEmilio G. Cota     }
883d73415a3SStefan Hajnoczi     qatomic_set(&s->code_gen_ptr, next);
88457a26946SRichard Henderson     s->data_gen_ptr = NULL;
8856e3b2bfdSEmilio G. Cota     return tb;
8866e3b2bfdSEmilio G. Cota }
8876e3b2bfdSEmilio G. Cota 
8889002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
8899002ec79SRichard Henderson {
890b0a0794aSRichard Henderson     size_t prologue_size;
8918163b749SRichard Henderson 
892b0a0794aSRichard Henderson     s->code_ptr = s->code_gen_ptr;
893b0a0794aSRichard Henderson     s->code_buf = s->code_gen_ptr;
8945b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
895b91ccb31SRichard Henderson 
896b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
897b0a0794aSRichard Henderson     tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr);
898b91ccb31SRichard Henderson #endif
8998163b749SRichard Henderson 
9005b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
9015b38ee31SRichard Henderson     s->pool_labels = NULL;
9025b38ee31SRichard Henderson #endif
9035b38ee31SRichard Henderson 
904653b87ebSRoman Bolshakov     qemu_thread_jit_write();
9058163b749SRichard Henderson     /* Generate the prologue.  */
906b03cce8eSbellard     tcg_target_qemu_prologue(s);
9075b38ee31SRichard Henderson 
9085b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
9095b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
9105b38ee31SRichard Henderson     {
9111768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
9121768987bSRichard Henderson         tcg_debug_assert(result == 0);
9135b38ee31SRichard Henderson     }
9145b38ee31SRichard Henderson #endif
9155b38ee31SRichard Henderson 
916b0a0794aSRichard Henderson     prologue_size = tcg_current_code_size(s);
917b0a0794aSRichard Henderson 
918df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
919b0a0794aSRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
920b0a0794aSRichard Henderson                         (uintptr_t)s->code_buf, prologue_size);
921df5d2b16SRichard Henderson #endif
9228163b749SRichard Henderson 
923d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
924d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
925c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
92678b54858SRichard Henderson         if (logfile) {
92778b54858SRichard Henderson             fprintf(logfile, "PROLOGUE: [size=%zu]\n", prologue_size);
9285b38ee31SRichard Henderson             if (s->data_gen_ptr) {
929b0a0794aSRichard Henderson                 size_t code_size = s->data_gen_ptr - s->code_gen_ptr;
9305b38ee31SRichard Henderson                 size_t data_size = prologue_size - code_size;
9315b38ee31SRichard Henderson                 size_t i;
9325b38ee31SRichard Henderson 
93378b54858SRichard Henderson                 disas(logfile, s->code_gen_ptr, code_size);
9345b38ee31SRichard Henderson 
9355b38ee31SRichard Henderson                 for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
9365b38ee31SRichard Henderson                     if (sizeof(tcg_target_ulong) == 8) {
93778b54858SRichard Henderson                         fprintf(logfile,
93878b54858SRichard Henderson                                 "0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
9395b38ee31SRichard Henderson                                 (uintptr_t)s->data_gen_ptr + i,
9405b38ee31SRichard Henderson                                 *(uint64_t *)(s->data_gen_ptr + i));
9415b38ee31SRichard Henderson                     } else {
94278b54858SRichard Henderson                         fprintf(logfile,
94378b54858SRichard Henderson                                 "0x%08" PRIxPTR ":  .long  0x%08x\n",
9445b38ee31SRichard Henderson                                 (uintptr_t)s->data_gen_ptr + i,
9455b38ee31SRichard Henderson                                 *(uint32_t *)(s->data_gen_ptr + i));
9465b38ee31SRichard Henderson                     }
9475b38ee31SRichard Henderson                 }
9485b38ee31SRichard Henderson             } else {
94978b54858SRichard Henderson                 disas(logfile, s->code_gen_ptr, prologue_size);
9505b38ee31SRichard Henderson             }
95178b54858SRichard Henderson             fprintf(logfile, "\n");
952fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
953d6b64b2bSRichard Henderson         }
95478b54858SRichard Henderson     }
955d6b64b2bSRichard Henderson #endif
956cedbcb01SEmilio G. Cota 
9576eea0434SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
9586eea0434SRichard Henderson     /*
9596eea0434SRichard Henderson      * Assert that goto_ptr is implemented completely, setting an epilogue.
9606eea0434SRichard Henderson      * For tci, we use NULL as the signal to return from the interpreter,
9616eea0434SRichard Henderson      * so skip this check.
9626eea0434SRichard Henderson      */
9638b5c2b62SRichard Henderson     tcg_debug_assert(tcg_code_gen_epilogue != NULL);
9646eea0434SRichard Henderson #endif
965d1c74ab3SRichard Henderson 
966d1c74ab3SRichard Henderson     tcg_region_prologue_set(s);
967c896fe29Sbellard }
968c896fe29Sbellard 
969c896fe29Sbellard void tcg_func_start(TCGContext *s)
970c896fe29Sbellard {
971c896fe29Sbellard     tcg_pool_reset(s);
972c896fe29Sbellard     s->nb_temps = s->nb_globals;
9730ec9eabcSRichard Henderson 
9740ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
9750ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
9760ec9eabcSRichard Henderson 
977c0522136SRichard Henderson     /* No constant temps have been previously allocated. */
978c0522136SRichard Henderson     for (int i = 0; i < TCG_TYPE_COUNT; ++i) {
979c0522136SRichard Henderson         if (s->const_table[i]) {
980c0522136SRichard Henderson             g_hash_table_remove_all(s->const_table[i]);
981c0522136SRichard Henderson         }
982c0522136SRichard Henderson     }
983c0522136SRichard Henderson 
984abebf925SRichard Henderson     s->nb_ops = 0;
985c896fe29Sbellard     s->nb_labels = 0;
986c896fe29Sbellard     s->current_frame_offset = s->frame_start;
987c896fe29Sbellard 
9880a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
9890a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
9900a209d4bSRichard Henderson #endif
9910a209d4bSRichard Henderson 
99215fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
99315fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
994bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
995c896fe29Sbellard }
996c896fe29Sbellard 
997ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s)
9987ca4b752SRichard Henderson {
9997ca4b752SRichard Henderson     int n = s->nb_temps++;
1000ae30e866SRichard Henderson 
1001ae30e866SRichard Henderson     if (n >= TCG_MAX_TEMPS) {
1002db6b7d0cSRichard Henderson         tcg_raise_tb_overflow(s);
1003ae30e866SRichard Henderson     }
10047ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
10057ca4b752SRichard Henderson }
10067ca4b752SRichard Henderson 
1007ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s)
10087ca4b752SRichard Henderson {
1009fa477d25SRichard Henderson     TCGTemp *ts;
1010fa477d25SRichard Henderson 
10117ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
1012ae30e866SRichard Henderson     tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS);
10137ca4b752SRichard Henderson     s->nb_globals++;
1014fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1015ee17db83SRichard Henderson     ts->kind = TEMP_GLOBAL;
1016fa477d25SRichard Henderson 
1017fa477d25SRichard Henderson     return ts;
1018c896fe29Sbellard }
1019c896fe29Sbellard 
1020085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1021b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1022c896fe29Sbellard {
1023c896fe29Sbellard     TCGTemp *ts;
1024c896fe29Sbellard 
1025b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
1026c896fe29Sbellard         tcg_abort();
1027b3a62939SRichard Henderson     }
10287ca4b752SRichard Henderson 
10297ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1030c896fe29Sbellard     ts->base_type = type;
1031c896fe29Sbellard     ts->type = type;
1032ee17db83SRichard Henderson     ts->kind = TEMP_FIXED;
1033c896fe29Sbellard     ts->reg = reg;
1034c896fe29Sbellard     ts->name = name;
1035c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
10367ca4b752SRichard Henderson 
1037085272b3SRichard Henderson     return ts;
1038a7812ae4Spbrook }
1039a7812ae4Spbrook 
1040b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1041a7812ae4Spbrook {
1042b3a62939SRichard Henderson     s->frame_start = start;
1043b3a62939SRichard Henderson     s->frame_end = start + size;
1044085272b3SRichard Henderson     s->frame_temp
1045085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1046b3a62939SRichard Henderson }
1047a7812ae4Spbrook 
1048085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
1049e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
1050c896fe29Sbellard {
1051b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1052dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
10537ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1054aef85402SRichard Henderson     int indirect_reg = 0;
1055c896fe29Sbellard 
1056c0522136SRichard Henderson     switch (base_ts->kind) {
1057c0522136SRichard Henderson     case TEMP_FIXED:
1058c0522136SRichard Henderson         break;
1059c0522136SRichard Henderson     case TEMP_GLOBAL:
10605a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
10615a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1062b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
10635a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
10645a18407fSRichard Henderson                             ? 2 : 1);
10655a18407fSRichard Henderson         indirect_reg = 1;
1066c0522136SRichard Henderson         break;
1067c0522136SRichard Henderson     default:
1068c0522136SRichard Henderson         g_assert_not_reached();
1069b3915dbbSRichard Henderson     }
1070b3915dbbSRichard Henderson 
10717ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
10727ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1073c896fe29Sbellard         char buf[64];
10747ca4b752SRichard Henderson 
10757ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1076c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1077b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1078c896fe29Sbellard         ts->mem_allocated = 1;
1079b3a62939SRichard Henderson         ts->mem_base = base_ts;
1080aef85402SRichard Henderson         ts->mem_offset = offset;
1081c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1082c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1083c896fe29Sbellard         ts->name = strdup(buf);
1084c896fe29Sbellard 
10857ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
10867ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
10877ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1088b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
10897ca4b752SRichard Henderson         ts2->mem_allocated = 1;
10907ca4b752SRichard Henderson         ts2->mem_base = base_ts;
1091aef85402SRichard Henderson         ts2->mem_offset = offset + 4;
1092fac87bd2SRichard Henderson         ts2->temp_subindex = 1;
1093c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1094c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1095120c1084SRichard Henderson         ts2->name = strdup(buf);
10967ca4b752SRichard Henderson     } else {
1097c896fe29Sbellard         ts->base_type = type;
1098c896fe29Sbellard         ts->type = type;
1099b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1100c896fe29Sbellard         ts->mem_allocated = 1;
1101b3a62939SRichard Henderson         ts->mem_base = base_ts;
1102c896fe29Sbellard         ts->mem_offset = offset;
1103c896fe29Sbellard         ts->name = name;
1104c896fe29Sbellard     }
1105085272b3SRichard Henderson     return ts;
1106c896fe29Sbellard }
1107c896fe29Sbellard 
11085bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local)
1109c896fe29Sbellard {
1110b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1111ee17db83SRichard Henderson     TCGTempKind kind = temp_local ? TEMP_LOCAL : TEMP_NORMAL;
1112c896fe29Sbellard     TCGTemp *ts;
1113641d5fbeSbellard     int idx, k;
1114c896fe29Sbellard 
11150ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
11160ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
11170ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
11180ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
11190ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
11200ec9eabcSRichard Henderson 
1121e8996ee0Sbellard         ts = &s->temps[idx];
1122e8996ee0Sbellard         ts->temp_allocated = 1;
11237ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
1124ee17db83SRichard Henderson         tcg_debug_assert(ts->kind == kind);
1125e8996ee0Sbellard     } else {
11267ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
11277ca4b752SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
11287ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
11297ca4b752SRichard Henderson 
1130c896fe29Sbellard             ts->base_type = type;
1131c896fe29Sbellard             ts->type = TCG_TYPE_I32;
1132e8996ee0Sbellard             ts->temp_allocated = 1;
1133ee17db83SRichard Henderson             ts->kind = kind;
11347ca4b752SRichard Henderson 
11357ca4b752SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
11367ca4b752SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
11377ca4b752SRichard Henderson             ts2->type = TCG_TYPE_I32;
11387ca4b752SRichard Henderson             ts2->temp_allocated = 1;
1139fac87bd2SRichard Henderson             ts2->temp_subindex = 1;
1140ee17db83SRichard Henderson             ts2->kind = kind;
11417ca4b752SRichard Henderson         } else {
1142c896fe29Sbellard             ts->base_type = type;
1143c896fe29Sbellard             ts->type = type;
1144e8996ee0Sbellard             ts->temp_allocated = 1;
1145ee17db83SRichard Henderson             ts->kind = kind;
1146c896fe29Sbellard         }
1147e8996ee0Sbellard     }
114827bfd83cSPeter Maydell 
114927bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
115027bfd83cSPeter Maydell     s->temps_in_use++;
115127bfd83cSPeter Maydell #endif
1152085272b3SRichard Henderson     return ts;
1153c896fe29Sbellard }
1154c896fe29Sbellard 
1155d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1156d2fd745fSRichard Henderson {
1157d2fd745fSRichard Henderson     TCGTemp *t;
1158d2fd745fSRichard Henderson 
1159d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1160d2fd745fSRichard Henderson     switch (type) {
1161d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1162d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1163d2fd745fSRichard Henderson         break;
1164d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1165d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1166d2fd745fSRichard Henderson         break;
1167d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1168d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1169d2fd745fSRichard Henderson         break;
1170d2fd745fSRichard Henderson     default:
1171d2fd745fSRichard Henderson         g_assert_not_reached();
1172d2fd745fSRichard Henderson     }
1173d2fd745fSRichard Henderson #endif
1174d2fd745fSRichard Henderson 
1175d2fd745fSRichard Henderson     t = tcg_temp_new_internal(type, 0);
1176d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1177d2fd745fSRichard Henderson }
1178d2fd745fSRichard Henderson 
1179d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1180d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1181d2fd745fSRichard Henderson {
1182d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1183d2fd745fSRichard Henderson 
1184d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1185d2fd745fSRichard Henderson 
1186d2fd745fSRichard Henderson     t = tcg_temp_new_internal(t->base_type, 0);
1187d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1188d2fd745fSRichard Henderson }
1189d2fd745fSRichard Henderson 
11905bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1191c896fe29Sbellard {
1192b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1193085272b3SRichard Henderson     int k, idx;
1194c896fe29Sbellard 
1195c7482438SRichard Henderson     switch (ts->kind) {
1196c7482438SRichard Henderson     case TEMP_CONST:
1197c7482438SRichard Henderson         /*
1198c7482438SRichard Henderson          * In order to simplify users of tcg_constant_*,
1199c7482438SRichard Henderson          * silently ignore free.
1200c7482438SRichard Henderson          */
1201c0522136SRichard Henderson         return;
1202c7482438SRichard Henderson     case TEMP_NORMAL:
1203c7482438SRichard Henderson     case TEMP_LOCAL:
1204c7482438SRichard Henderson         break;
1205c7482438SRichard Henderson     default:
1206c7482438SRichard Henderson         g_assert_not_reached();
1207c0522136SRichard Henderson     }
1208c0522136SRichard Henderson 
120927bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
121027bfd83cSPeter Maydell     s->temps_in_use--;
121127bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
121227bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
121327bfd83cSPeter Maydell     }
121427bfd83cSPeter Maydell #endif
121527bfd83cSPeter Maydell 
1216eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
1217e8996ee0Sbellard     ts->temp_allocated = 0;
12180ec9eabcSRichard Henderson 
1219085272b3SRichard Henderson     idx = temp_idx(ts);
1220ee17db83SRichard Henderson     k = ts->base_type + (ts->kind == TEMP_NORMAL ? 0 : TCG_TYPE_COUNT);
12210ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
1222e8996ee0Sbellard }
1223e8996ee0Sbellard 
1224c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val)
1225c0522136SRichard Henderson {
1226c0522136SRichard Henderson     TCGContext *s = tcg_ctx;
1227c0522136SRichard Henderson     GHashTable *h = s->const_table[type];
1228c0522136SRichard Henderson     TCGTemp *ts;
1229c0522136SRichard Henderson 
1230c0522136SRichard Henderson     if (h == NULL) {
1231c0522136SRichard Henderson         h = g_hash_table_new(g_int64_hash, g_int64_equal);
1232c0522136SRichard Henderson         s->const_table[type] = h;
1233c0522136SRichard Henderson     }
1234c0522136SRichard Henderson 
1235c0522136SRichard Henderson     ts = g_hash_table_lookup(h, &val);
1236c0522136SRichard Henderson     if (ts == NULL) {
1237aef85402SRichard Henderson         int64_t *val_ptr;
1238aef85402SRichard Henderson 
1239c0522136SRichard Henderson         ts = tcg_temp_alloc(s);
1240c0522136SRichard Henderson 
1241c0522136SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
1242c0522136SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
1243c0522136SRichard Henderson 
1244aef85402SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
1245aef85402SRichard Henderson 
1246c0522136SRichard Henderson             ts->base_type = TCG_TYPE_I64;
1247c0522136SRichard Henderson             ts->type = TCG_TYPE_I32;
1248c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1249c0522136SRichard Henderson             ts->temp_allocated = 1;
1250c0522136SRichard Henderson 
1251c0522136SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
1252c0522136SRichard Henderson             ts2->type = TCG_TYPE_I32;
1253c0522136SRichard Henderson             ts2->kind = TEMP_CONST;
1254c0522136SRichard Henderson             ts2->temp_allocated = 1;
1255fac87bd2SRichard Henderson             ts2->temp_subindex = 1;
1256aef85402SRichard Henderson 
1257aef85402SRichard Henderson             /*
1258aef85402SRichard Henderson              * Retain the full value of the 64-bit constant in the low
1259aef85402SRichard Henderson              * part, so that the hash table works.  Actual uses will
1260aef85402SRichard Henderson              * truncate the value to the low part.
1261aef85402SRichard Henderson              */
1262aef85402SRichard Henderson             ts[HOST_BIG_ENDIAN].val = val;
1263aef85402SRichard Henderson             ts[!HOST_BIG_ENDIAN].val = val >> 32;
1264aef85402SRichard Henderson             val_ptr = &ts[HOST_BIG_ENDIAN].val;
1265c0522136SRichard Henderson         } else {
1266c0522136SRichard Henderson             ts->base_type = type;
1267c0522136SRichard Henderson             ts->type = type;
1268c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1269c0522136SRichard Henderson             ts->temp_allocated = 1;
1270c0522136SRichard Henderson             ts->val = val;
1271aef85402SRichard Henderson             val_ptr = &ts->val;
1272c0522136SRichard Henderson         }
1273aef85402SRichard Henderson         g_hash_table_insert(h, val_ptr, ts);
1274c0522136SRichard Henderson     }
1275c0522136SRichard Henderson 
1276c0522136SRichard Henderson     return ts;
1277c0522136SRichard Henderson }
1278c0522136SRichard Henderson 
1279c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val)
1280c0522136SRichard Henderson {
1281c0522136SRichard Henderson     val = dup_const(vece, val);
1282c0522136SRichard Henderson     return temp_tcgv_vec(tcg_constant_internal(type, val));
1283c0522136SRichard Henderson }
1284c0522136SRichard Henderson 
128588d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val)
128688d4005bSRichard Henderson {
128788d4005bSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
128888d4005bSRichard Henderson 
128988d4005bSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
129088d4005bSRichard Henderson     return tcg_constant_vec(t->base_type, vece, val);
129188d4005bSRichard Henderson }
129288d4005bSRichard Henderson 
1293a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
1294a7812ae4Spbrook {
1295a7812ae4Spbrook     TCGv_i32 t0;
1296a7812ae4Spbrook     t0 = tcg_temp_new_i32();
1297e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
1298e8996ee0Sbellard     return t0;
1299c896fe29Sbellard }
1300c896fe29Sbellard 
1301a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
1302c896fe29Sbellard {
1303a7812ae4Spbrook     TCGv_i64 t0;
1304a7812ae4Spbrook     t0 = tcg_temp_new_i64();
1305e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
1306e8996ee0Sbellard     return t0;
1307c896fe29Sbellard }
1308c896fe29Sbellard 
1309a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
1310bdffd4a9Saurel32 {
1311a7812ae4Spbrook     TCGv_i32 t0;
1312a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
1313bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
1314bdffd4a9Saurel32     return t0;
1315bdffd4a9Saurel32 }
1316bdffd4a9Saurel32 
1317a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
1318bdffd4a9Saurel32 {
1319a7812ae4Spbrook     TCGv_i64 t0;
1320a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
1321bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
1322bdffd4a9Saurel32     return t0;
1323bdffd4a9Saurel32 }
1324bdffd4a9Saurel32 
132527bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
132627bfd83cSPeter Maydell void tcg_clear_temp_count(void)
132727bfd83cSPeter Maydell {
1328b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
132927bfd83cSPeter Maydell     s->temps_in_use = 0;
133027bfd83cSPeter Maydell }
133127bfd83cSPeter Maydell 
133227bfd83cSPeter Maydell int tcg_check_temp_count(void)
133327bfd83cSPeter Maydell {
1334b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
133527bfd83cSPeter Maydell     if (s->temps_in_use) {
133627bfd83cSPeter Maydell         /* Clear the count so that we don't give another
133727bfd83cSPeter Maydell          * warning immediately next time around.
133827bfd83cSPeter Maydell          */
133927bfd83cSPeter Maydell         s->temps_in_use = 0;
134027bfd83cSPeter Maydell         return 1;
134127bfd83cSPeter Maydell     }
134227bfd83cSPeter Maydell     return 0;
134327bfd83cSPeter Maydell }
134427bfd83cSPeter Maydell #endif
134527bfd83cSPeter Maydell 
1346be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1347be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1348be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1349be0f34b5SRichard Henderson {
1350d2fd745fSRichard Henderson     const bool have_vec
1351d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1352d2fd745fSRichard Henderson 
1353be0f34b5SRichard Henderson     switch (op) {
1354be0f34b5SRichard Henderson     case INDEX_op_discard:
1355be0f34b5SRichard Henderson     case INDEX_op_set_label:
1356be0f34b5SRichard Henderson     case INDEX_op_call:
1357be0f34b5SRichard Henderson     case INDEX_op_br:
1358be0f34b5SRichard Henderson     case INDEX_op_mb:
1359be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1360be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1361be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1362f4e01e30SRichard Henderson     case INDEX_op_goto_ptr:
1363be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i32:
1364be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i32:
1365be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i64:
1366be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i64:
1367be0f34b5SRichard Henderson         return true;
1368be0f34b5SRichard Henderson 
136907ce0b05SRichard Henderson     case INDEX_op_qemu_st8_i32:
137007ce0b05SRichard Henderson         return TCG_TARGET_HAS_qemu_st8_i32;
137107ce0b05SRichard Henderson 
1372be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1373be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1374be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1375be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1376be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1377be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1378be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1379be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1380be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1381be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1382be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1383be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1384be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1385be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1386be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1387be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1388be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1389be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1390be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1391be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1392be0f34b5SRichard Henderson         return true;
1393be0f34b5SRichard Henderson 
1394be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1395be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1396be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1397be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1398be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1399be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1400be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1401be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1402be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1403be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1404be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1405be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1406be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1407be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1408be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1409be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1410be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1411be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1412be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1413be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1414fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
1415fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
1416be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1417be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1418be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1419be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1420be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1421be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1422be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1423be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1424be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1425be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1426be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1427be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1428be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1429be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1430be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1431be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1432be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1433be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1434be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1435be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1436be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1437be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1438be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1439be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1440be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1441be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1442be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1443be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1444be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1445be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1446be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1447be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1448be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1449be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1450be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1451be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1452be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1453be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1454be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1455be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1456be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1457be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1458be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1459be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1460be0f34b5SRichard Henderson 
1461be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1462be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1463be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1464be0f34b5SRichard Henderson 
1465be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1466be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1467be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1468be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1469be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1470be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1471be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1472be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1473be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1474be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1475be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1476be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1477be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1478be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1479be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1480be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1481be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1482be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1483be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1484be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1485be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1486be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1487be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1488be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1489be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1490be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1491be0f34b5SRichard Henderson 
1492be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1493be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1494be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1495be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1496be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1497be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1498be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1499be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1500be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1501be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
1502be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
1503be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
1504be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
1505be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
1506be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
1507be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
1508be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
1509be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
1510be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
1511be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
1512fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
1513fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
1514be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
1515be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrl_i64_i32;
1516be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
1517be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrh_i64_i32;
1518be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
1519be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
1520be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
1521be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
1522be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
1523be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
1524be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
1525be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
1526be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
1527be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
1528be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
1529be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
1530be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
1531be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
1532be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
1533be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
1534be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
1535be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
1536be0f34b5SRichard Henderson     case INDEX_op_not_i64:
1537be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
1538be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
1539be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
1540be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
1541be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
1542be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
1543be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
1544be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
1545be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
1546be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
1547be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
1548be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
1549be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
1550be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
1551be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
1552be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
1553be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
1554be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
1555be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
1556be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
1557be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
1558be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
1559be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
1560be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
1561be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
1562be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
1563be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
1564be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
1565be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
1566be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
1567be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
1568be0f34b5SRichard Henderson 
1569d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
1570d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
157137ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
1572d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
1573d2fd745fSRichard Henderson     case INDEX_op_st_vec:
1574d2fd745fSRichard Henderson     case INDEX_op_add_vec:
1575d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
1576d2fd745fSRichard Henderson     case INDEX_op_and_vec:
1577d2fd745fSRichard Henderson     case INDEX_op_or_vec:
1578d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
1579212be173SRichard Henderson     case INDEX_op_cmp_vec:
1580d2fd745fSRichard Henderson         return have_vec;
1581d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
1582d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
1583d2fd745fSRichard Henderson     case INDEX_op_not_vec:
1584d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
1585d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
1586d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
1587bcefc902SRichard Henderson     case INDEX_op_abs_vec:
1588bcefc902SRichard Henderson         return have_vec && TCG_TARGET_HAS_abs_vec;
1589d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
1590d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
1591d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
1592d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
1593ed523473SRichard Henderson     case INDEX_op_nand_vec:
1594ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_nand_vec;
1595ed523473SRichard Henderson     case INDEX_op_nor_vec:
1596ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_nor_vec;
1597ed523473SRichard Henderson     case INDEX_op_eqv_vec:
1598ed523473SRichard Henderson         return have_vec && TCG_TARGET_HAS_eqv_vec;
15993774030aSRichard Henderson     case INDEX_op_mul_vec:
16003774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
1601d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
1602d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
1603d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
1604d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
1605d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
1606d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
1607d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
1608d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
1609d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
1610d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
1611d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
1612d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
1613b0f7e744SRichard Henderson     case INDEX_op_rotli_vec:
1614b0f7e744SRichard Henderson         return have_vec && TCG_TARGET_HAS_roti_vec;
161523850a74SRichard Henderson     case INDEX_op_rotls_vec:
161623850a74SRichard Henderson         return have_vec && TCG_TARGET_HAS_rots_vec;
16175d0ceda9SRichard Henderson     case INDEX_op_rotlv_vec:
16185d0ceda9SRichard Henderson     case INDEX_op_rotrv_vec:
16195d0ceda9SRichard Henderson         return have_vec && TCG_TARGET_HAS_rotv_vec;
16208afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
16218afaf050SRichard Henderson     case INDEX_op_usadd_vec:
16228afaf050SRichard Henderson     case INDEX_op_sssub_vec:
16238afaf050SRichard Henderson     case INDEX_op_ussub_vec:
16248afaf050SRichard Henderson         return have_vec && TCG_TARGET_HAS_sat_vec;
1625dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
1626dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
1627dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
1628dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
1629dd0a0fcdSRichard Henderson         return have_vec && TCG_TARGET_HAS_minmax_vec;
163038dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
163138dc1294SRichard Henderson         return have_vec && TCG_TARGET_HAS_bitsel_vec;
1632f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
1633f75da298SRichard Henderson         return have_vec && TCG_TARGET_HAS_cmpsel_vec;
1634d2fd745fSRichard Henderson 
1635db432672SRichard Henderson     default:
1636db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
1637db432672SRichard Henderson         return true;
1638be0f34b5SRichard Henderson     }
1639be0f34b5SRichard Henderson }
1640be0f34b5SRichard Henderson 
164139004a71SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs);
164239004a71SRichard Henderson 
1643ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
1644c896fe29Sbellard {
16453e92aa34SRichard Henderson     const TCGHelperInfo *info;
164639004a71SRichard Henderson     TCGv_i64 extend_free[MAX_CALL_IARGS];
164739004a71SRichard Henderson     int n_extend = 0;
164875e8b9b7SRichard Henderson     TCGOp *op;
164939004a71SRichard Henderson     int i, n, pi = 0, total_args;
1650afb49896SRichard Henderson 
1651619205fdSEmilio G. Cota     info = g_hash_table_lookup(helper_table, (gpointer)func);
165239004a71SRichard Henderson     total_args = info->nr_out + info->nr_in + 2;
165339004a71SRichard Henderson     op = tcg_op_alloc(INDEX_op_call, total_args);
16542bece2c8SRichard Henderson 
165538b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
165638b47b19SEmilio G. Cota     /* detect non-plugin helpers */
165738b47b19SEmilio G. Cota     if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) {
165838b47b19SEmilio G. Cota         tcg_ctx->plugin_insn->calls_helpers = true;
165938b47b19SEmilio G. Cota     }
166038b47b19SEmilio G. Cota #endif
166138b47b19SEmilio G. Cota 
166239004a71SRichard Henderson     TCGOP_CALLO(op) = n = info->nr_out;
166339004a71SRichard Henderson     switch (n) {
166439004a71SRichard Henderson     case 0:
166539004a71SRichard Henderson         tcg_debug_assert(ret == NULL);
166639004a71SRichard Henderson         break;
166739004a71SRichard Henderson     case 1:
166839004a71SRichard Henderson         tcg_debug_assert(ret != NULL);
166939004a71SRichard Henderson         op->args[pi++] = temp_arg(ret);
167039004a71SRichard Henderson         break;
167139004a71SRichard Henderson     case 2:
167239004a71SRichard Henderson         tcg_debug_assert(ret != NULL);
167339004a71SRichard Henderson         tcg_debug_assert(ret->base_type == ret->type + 1);
167439004a71SRichard Henderson         tcg_debug_assert(ret->temp_subindex == 0);
167539004a71SRichard Henderson         op->args[pi++] = temp_arg(ret);
167639004a71SRichard Henderson         op->args[pi++] = temp_arg(ret + 1);
167739004a71SRichard Henderson         break;
167839004a71SRichard Henderson     default:
167939004a71SRichard Henderson         g_assert_not_reached();
168039004a71SRichard Henderson     }
16817319d83aSRichard Henderson 
168239004a71SRichard Henderson     TCGOP_CALLI(op) = n = info->nr_in;
168339004a71SRichard Henderson     for (i = 0; i < n; i++) {
168439004a71SRichard Henderson         const TCGCallArgumentLoc *loc = &info->in[i];
168539004a71SRichard Henderson         TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex;
168639004a71SRichard Henderson 
168739004a71SRichard Henderson         switch (loc->kind) {
168839004a71SRichard Henderson         case TCG_CALL_ARG_NORMAL:
168939004a71SRichard Henderson             op->args[pi++] = temp_arg(ts);
169039004a71SRichard Henderson             break;
169139004a71SRichard Henderson 
169239004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
169339004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
169439004a71SRichard Henderson             {
16952bece2c8SRichard Henderson                 TCGv_i64 temp = tcg_temp_new_i64();
169639004a71SRichard Henderson                 TCGv_i32 orig = temp_tcgv_i32(ts);
169739004a71SRichard Henderson 
169839004a71SRichard Henderson                 if (loc->kind == TCG_CALL_ARG_EXTEND_S) {
169918cf3d07SRichard Henderson                     tcg_gen_ext_i32_i64(temp, orig);
17002bece2c8SRichard Henderson                 } else {
170118cf3d07SRichard Henderson                     tcg_gen_extu_i32_i64(temp, orig);
17022bece2c8SRichard Henderson                 }
170339004a71SRichard Henderson                 op->args[pi++] = tcgv_i64_arg(temp);
170439004a71SRichard Henderson                 extend_free[n_extend++] = temp;
17052bece2c8SRichard Henderson             }
170639004a71SRichard Henderson             break;
17072bece2c8SRichard Henderson 
1708e2a9dd6bSRichard Henderson         default:
1709e2a9dd6bSRichard Henderson             g_assert_not_reached();
1710e2a9dd6bSRichard Henderson         }
1711c896fe29Sbellard     }
171275e8b9b7SRichard Henderson     op->args[pi++] = (uintptr_t)func;
17133e92aa34SRichard Henderson     op->args[pi++] = (uintptr_t)info;
171439004a71SRichard Henderson     tcg_debug_assert(pi == total_args);
1715a7812ae4Spbrook 
171639004a71SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
17172bece2c8SRichard Henderson 
171839004a71SRichard Henderson     tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free));
171939004a71SRichard Henderson     for (i = 0; i < n_extend; ++i) {
172039004a71SRichard Henderson         tcg_temp_free_i64(extend_free[i]);
1721eb8b0224SRichard Henderson     }
1722a7812ae4Spbrook }
1723c896fe29Sbellard 
17248fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
1725c896fe29Sbellard {
1726ac3b8891SRichard Henderson     int i, n;
1727ac3b8891SRichard Henderson 
1728ee17db83SRichard Henderson     for (i = 0, n = s->nb_temps; i < n; i++) {
1729ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
1730ee17db83SRichard Henderson         TCGTempVal val = TEMP_VAL_MEM;
1731ee17db83SRichard Henderson 
1732ee17db83SRichard Henderson         switch (ts->kind) {
1733c0522136SRichard Henderson         case TEMP_CONST:
1734c0522136SRichard Henderson             val = TEMP_VAL_CONST;
1735c0522136SRichard Henderson             break;
1736ee17db83SRichard Henderson         case TEMP_FIXED:
1737ee17db83SRichard Henderson             val = TEMP_VAL_REG;
1738ee17db83SRichard Henderson             break;
1739ee17db83SRichard Henderson         case TEMP_GLOBAL:
1740ee17db83SRichard Henderson             break;
1741ee17db83SRichard Henderson         case TEMP_NORMAL:
1742c7482438SRichard Henderson         case TEMP_EBB:
1743ee17db83SRichard Henderson             val = TEMP_VAL_DEAD;
1744ee17db83SRichard Henderson             /* fall through */
1745ee17db83SRichard Henderson         case TEMP_LOCAL:
1746e8996ee0Sbellard             ts->mem_allocated = 0;
1747ee17db83SRichard Henderson             break;
1748ee17db83SRichard Henderson         default:
1749ee17db83SRichard Henderson             g_assert_not_reached();
1750ee17db83SRichard Henderson         }
1751ee17db83SRichard Henderson         ts->val_type = val;
1752e8996ee0Sbellard     }
1753f8b2f202SRichard Henderson 
1754f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
1755c896fe29Sbellard }
1756c896fe29Sbellard 
1757f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
1758f8b2f202SRichard Henderson                                  TCGTemp *ts)
1759c896fe29Sbellard {
17601807f4c4SRichard Henderson     int idx = temp_idx(ts);
1761ac56dd48Spbrook 
1762ee17db83SRichard Henderson     switch (ts->kind) {
1763ee17db83SRichard Henderson     case TEMP_FIXED:
1764ee17db83SRichard Henderson     case TEMP_GLOBAL:
1765ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
1766ee17db83SRichard Henderson         break;
1767ee17db83SRichard Henderson     case TEMP_LOCAL:
1768641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
1769ee17db83SRichard Henderson         break;
1770c7482438SRichard Henderson     case TEMP_EBB:
1771c7482438SRichard Henderson         snprintf(buf, buf_size, "ebb%d", idx - s->nb_globals);
1772c7482438SRichard Henderson         break;
1773ee17db83SRichard Henderson     case TEMP_NORMAL:
1774ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
1775ee17db83SRichard Henderson         break;
1776c0522136SRichard Henderson     case TEMP_CONST:
1777c0522136SRichard Henderson         switch (ts->type) {
1778c0522136SRichard Henderson         case TCG_TYPE_I32:
1779c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val);
1780c0522136SRichard Henderson             break;
1781c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32
1782c0522136SRichard Henderson         case TCG_TYPE_I64:
1783c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%" PRIx64, ts->val);
1784c0522136SRichard Henderson             break;
1785c0522136SRichard Henderson #endif
1786c0522136SRichard Henderson         case TCG_TYPE_V64:
1787c0522136SRichard Henderson         case TCG_TYPE_V128:
1788c0522136SRichard Henderson         case TCG_TYPE_V256:
1789c0522136SRichard Henderson             snprintf(buf, buf_size, "v%d$0x%" PRIx64,
1790c0522136SRichard Henderson                      64 << (ts->type - TCG_TYPE_V64), ts->val);
1791c0522136SRichard Henderson             break;
1792c0522136SRichard Henderson         default:
1793c0522136SRichard Henderson             g_assert_not_reached();
1794c0522136SRichard Henderson         }
1795c0522136SRichard Henderson         break;
1796c896fe29Sbellard     }
1797c896fe29Sbellard     return buf;
1798c896fe29Sbellard }
1799c896fe29Sbellard 
180043439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
180143439139SRichard Henderson                              int buf_size, TCGArg arg)
1802f8b2f202SRichard Henderson {
180343439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
1804f8b2f202SRichard Henderson }
1805f8b2f202SRichard Henderson 
1806f48f3edeSblueswir1 static const char * const cond_name[] =
1807f48f3edeSblueswir1 {
18080aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
18090aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
1810f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
1811f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
1812f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
1813f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
1814f48f3edeSblueswir1     [TCG_COND_LE] = "le",
1815f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
1816f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
1817f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
1818f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
1819f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
1820f48f3edeSblueswir1 };
1821f48f3edeSblueswir1 
1822f713d6adSRichard Henderson static const char * const ldst_name[] =
1823f713d6adSRichard Henderson {
1824f713d6adSRichard Henderson     [MO_UB]   = "ub",
1825f713d6adSRichard Henderson     [MO_SB]   = "sb",
1826f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
1827f713d6adSRichard Henderson     [MO_LESW] = "lesw",
1828f713d6adSRichard Henderson     [MO_LEUL] = "leul",
1829f713d6adSRichard Henderson     [MO_LESL] = "lesl",
1830fc313c64SFrédéric Pétrot     [MO_LEUQ] = "leq",
1831f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
1832f713d6adSRichard Henderson     [MO_BESW] = "besw",
1833f713d6adSRichard Henderson     [MO_BEUL] = "beul",
1834f713d6adSRichard Henderson     [MO_BESL] = "besl",
1835fc313c64SFrédéric Pétrot     [MO_BEUQ] = "beq",
1836f713d6adSRichard Henderson };
1837f713d6adSRichard Henderson 
18381f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
183952bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY
18401f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
18411f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
18421f00b27fSSergey Sorokin #else
18431f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
18441f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
18451f00b27fSSergey Sorokin #endif
18461f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
18471f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
18481f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
18491f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
18501f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
18511f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
18521f00b27fSSergey Sorokin };
18531f00b27fSSergey Sorokin 
1854587195bdSRichard Henderson static const char bswap_flag_name[][6] = {
1855587195bdSRichard Henderson     [TCG_BSWAP_IZ] = "iz",
1856587195bdSRichard Henderson     [TCG_BSWAP_OZ] = "oz",
1857587195bdSRichard Henderson     [TCG_BSWAP_OS] = "os",
1858587195bdSRichard Henderson     [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz",
1859587195bdSRichard Henderson     [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os",
1860587195bdSRichard Henderson };
1861587195bdSRichard Henderson 
1862b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
1863b016486eSRichard Henderson {
1864b016486eSRichard Henderson     return (d & (d - 1)) == 0;
1865b016486eSRichard Henderson }
1866b016486eSRichard Henderson 
1867b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
1868b016486eSRichard Henderson {
1869b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
1870b016486eSRichard Henderson         return ctz32(d);
1871b016486eSRichard Henderson     } else {
1872b016486eSRichard Henderson         return ctz64(d);
1873b016486eSRichard Henderson     }
1874b016486eSRichard Henderson }
1875b016486eSRichard Henderson 
1876b7a83ff8SRichard Henderson /* Return only the number of characters output -- no error return. */
1877b7a83ff8SRichard Henderson #define ne_fprintf(...) \
1878b7a83ff8SRichard Henderson     ({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; })
1879b7a83ff8SRichard Henderson 
1880b7a83ff8SRichard Henderson static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
1881c896fe29Sbellard {
1882c896fe29Sbellard     char buf[128];
1883c45cb8bbSRichard Henderson     TCGOp *op;
1884c896fe29Sbellard 
188515fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
1886c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
1887c45cb8bbSRichard Henderson         const TCGOpDef *def;
1888c45cb8bbSRichard Henderson         TCGOpcode c;
1889bdfb460eSRichard Henderson         int col = 0;
1890c45cb8bbSRichard Henderson 
1891c45cb8bbSRichard Henderson         c = op->opc;
1892c896fe29Sbellard         def = &tcg_op_defs[c];
1893c45cb8bbSRichard Henderson 
1894765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
1895b016486eSRichard Henderson             nb_oargs = 0;
1896b7a83ff8SRichard Henderson             col += ne_fprintf(f, "\n ----");
18979aef40edSRichard Henderson 
18989aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
18999aef40edSRichard Henderson                 target_ulong a;
19007e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
1901efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
19027e4597d7Sbellard #else
1903efee3746SRichard Henderson                 a = op->args[i];
19047e4597d7Sbellard #endif
1905b7a83ff8SRichard Henderson                 col += ne_fprintf(f, " " TARGET_FMT_lx, a);
1906eeacee4dSBlue Swirl             }
19077e4597d7Sbellard         } else if (c == INDEX_op_call) {
19083e92aa34SRichard Henderson             const TCGHelperInfo *info = tcg_call_info(op);
1909fa52e660SRichard Henderson             void *func = tcg_call_func(op);
19103e92aa34SRichard Henderson 
1911c896fe29Sbellard             /* variable number of arguments */
1912cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
1913cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
1914c896fe29Sbellard             nb_cargs = def->nb_cargs;
1915b03cce8eSbellard 
1916b7a83ff8SRichard Henderson             col += ne_fprintf(f, " %s ", def->name);
19173e92aa34SRichard Henderson 
19183e92aa34SRichard Henderson             /*
19193e92aa34SRichard Henderson              * Print the function name from TCGHelperInfo, if available.
19203e92aa34SRichard Henderson              * Note that plugins have a template function for the info,
19213e92aa34SRichard Henderson              * but the actual function pointer comes from the plugin.
19223e92aa34SRichard Henderson              */
19233e92aa34SRichard Henderson             if (func == info->func) {
1924b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s", info->name);
19253e92aa34SRichard Henderson             } else {
1926b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "plugin(%p)", func);
19273e92aa34SRichard Henderson             }
19283e92aa34SRichard Henderson 
1929b7a83ff8SRichard Henderson             col += ne_fprintf(f, ",$0x%x,$%d", info->flags, nb_oargs);
1930b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
1931b7a83ff8SRichard Henderson                 col += ne_fprintf(f, ",%s", tcg_get_arg_str(s, buf, sizeof(buf),
1932efee3746SRichard Henderson                                                             op->args[i]));
1933b03cce8eSbellard             }
1934cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
1935efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
193639004a71SRichard Henderson                 const char *t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
1937b7a83ff8SRichard Henderson                 col += ne_fprintf(f, ",%s", t);
1938e8996ee0Sbellard             }
1939b03cce8eSbellard         } else {
1940b7a83ff8SRichard Henderson             col += ne_fprintf(f, " %s ", def->name);
1941c45cb8bbSRichard Henderson 
1942c896fe29Sbellard             nb_oargs = def->nb_oargs;
1943c896fe29Sbellard             nb_iargs = def->nb_iargs;
1944c896fe29Sbellard             nb_cargs = def->nb_cargs;
1945c896fe29Sbellard 
1946d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
1947b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "v%d,e%d,", 64 << TCGOP_VECL(op),
1948d2fd745fSRichard Henderson                                   8 << TCGOP_VECE(op));
1949d2fd745fSRichard Henderson             }
1950d2fd745fSRichard Henderson 
1951c896fe29Sbellard             k = 0;
1952c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
1953b7a83ff8SRichard Henderson                 const char *sep =  k ? "," : "";
1954b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s%s", sep,
1955b7a83ff8SRichard Henderson                                   tcg_get_arg_str(s, buf, sizeof(buf),
1956efee3746SRichard Henderson                                                   op->args[k++]));
1957c896fe29Sbellard             }
1958c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
1959b7a83ff8SRichard Henderson                 const char *sep =  k ? "," : "";
1960b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s%s", sep,
1961b7a83ff8SRichard Henderson                                   tcg_get_arg_str(s, buf, sizeof(buf),
1962efee3746SRichard Henderson                                                   op->args[k++]));
1963c896fe29Sbellard             }
1964be210acbSRichard Henderson             switch (c) {
1965be210acbSRichard Henderson             case INDEX_op_brcond_i32:
1966ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
1967ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
1968be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
1969be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
1970ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
1971be210acbSRichard Henderson             case INDEX_op_setcond_i64:
1972ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
1973212be173SRichard Henderson             case INDEX_op_cmp_vec:
1974f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
1975efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
1976efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
1977b7a83ff8SRichard Henderson                     col += ne_fprintf(f, ",%s", cond_name[op->args[k++]]);
1978eeacee4dSBlue Swirl                 } else {
1979b7a83ff8SRichard Henderson                     col += ne_fprintf(f, ",$0x%" TCG_PRIlx, op->args[k++]);
1980eeacee4dSBlue Swirl                 }
1981f48f3edeSblueswir1                 i = 1;
1982be210acbSRichard Henderson                 break;
1983f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
1984f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
198507ce0b05SRichard Henderson             case INDEX_op_qemu_st8_i32:
1986f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
1987f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
198859227d5dSRichard Henderson                 {
19899002ffcbSRichard Henderson                     MemOpIdx oi = op->args[k++];
199014776ab5STony Nguyen                     MemOp op = get_memop(oi);
199159227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
199259227d5dSRichard Henderson 
199359c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
1994b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",$0x%x,%u", op, ix);
199559c4b7e8SRichard Henderson                     } else {
19961f00b27fSSergey Sorokin                         const char *s_al, *s_op;
19971f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
199859c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
1999b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",%s%s,%u", s_al, s_op, ix);
2000f713d6adSRichard Henderson                     }
2001f713d6adSRichard Henderson                     i = 1;
200259227d5dSRichard Henderson                 }
2003f713d6adSRichard Henderson                 break;
2004587195bdSRichard Henderson             case INDEX_op_bswap16_i32:
2005587195bdSRichard Henderson             case INDEX_op_bswap16_i64:
2006587195bdSRichard Henderson             case INDEX_op_bswap32_i32:
2007587195bdSRichard Henderson             case INDEX_op_bswap32_i64:
2008587195bdSRichard Henderson             case INDEX_op_bswap64_i64:
2009587195bdSRichard Henderson                 {
2010587195bdSRichard Henderson                     TCGArg flags = op->args[k];
2011587195bdSRichard Henderson                     const char *name = NULL;
2012587195bdSRichard Henderson 
2013587195bdSRichard Henderson                     if (flags < ARRAY_SIZE(bswap_flag_name)) {
2014587195bdSRichard Henderson                         name = bswap_flag_name[flags];
2015587195bdSRichard Henderson                     }
2016587195bdSRichard Henderson                     if (name) {
2017b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",%s", name);
2018587195bdSRichard Henderson                     } else {
2019b7a83ff8SRichard Henderson                         col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags);
2020587195bdSRichard Henderson                     }
2021587195bdSRichard Henderson                     i = k = 1;
2022587195bdSRichard Henderson                 }
2023587195bdSRichard Henderson                 break;
2024be210acbSRichard Henderson             default:
2025f48f3edeSblueswir1                 i = 0;
2026be210acbSRichard Henderson                 break;
2027be210acbSRichard Henderson             }
202851e3972cSRichard Henderson             switch (c) {
202951e3972cSRichard Henderson             case INDEX_op_set_label:
203051e3972cSRichard Henderson             case INDEX_op_br:
203151e3972cSRichard Henderson             case INDEX_op_brcond_i32:
203251e3972cSRichard Henderson             case INDEX_op_brcond_i64:
203351e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2034b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s$L%d", k ? "," : "",
2035efee3746SRichard Henderson                                   arg_label(op->args[k])->id);
203651e3972cSRichard Henderson                 i++, k++;
203751e3972cSRichard Henderson                 break;
203851e3972cSRichard Henderson             default:
203951e3972cSRichard Henderson                 break;
2040eeacee4dSBlue Swirl             }
204151e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
2042b7a83ff8SRichard Henderson                 col += ne_fprintf(f, "%s$0x%" TCG_PRIlx, k ? "," : "",
2043b7a83ff8SRichard Henderson                                   op->args[k]);
2044bdfb460eSRichard Henderson             }
2045bdfb460eSRichard Henderson         }
2046bdfb460eSRichard Henderson 
20471894f69aSRichard Henderson         if (have_prefs || op->life) {
20481894f69aSRichard Henderson             for (; col < 40; ++col) {
2049b7a83ff8SRichard Henderson                 putc(' ', f);
2050bdfb460eSRichard Henderson             }
20511894f69aSRichard Henderson         }
20521894f69aSRichard Henderson 
20531894f69aSRichard Henderson         if (op->life) {
20541894f69aSRichard Henderson             unsigned life = op->life;
2055bdfb460eSRichard Henderson 
2056bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
2057b7a83ff8SRichard Henderson                 ne_fprintf(f, "  sync:");
2058bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
2059bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
2060b7a83ff8SRichard Henderson                         ne_fprintf(f, " %d", i);
2061bdfb460eSRichard Henderson                     }
2062bdfb460eSRichard Henderson                 }
2063bdfb460eSRichard Henderson             }
2064bdfb460eSRichard Henderson             life /= DEAD_ARG;
2065bdfb460eSRichard Henderson             if (life) {
2066b7a83ff8SRichard Henderson                 ne_fprintf(f, "  dead:");
2067bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
2068bdfb460eSRichard Henderson                     if (life & 1) {
2069b7a83ff8SRichard Henderson                         ne_fprintf(f, " %d", i);
2070bdfb460eSRichard Henderson                     }
2071bdfb460eSRichard Henderson                 }
2072c896fe29Sbellard             }
2073b03cce8eSbellard         }
20741894f69aSRichard Henderson 
20751894f69aSRichard Henderson         if (have_prefs) {
20761894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
207731fd884bSRichard Henderson                 TCGRegSet set = output_pref(op, i);
20781894f69aSRichard Henderson 
20791894f69aSRichard Henderson                 if (i == 0) {
2080b7a83ff8SRichard Henderson                     ne_fprintf(f, "  pref=");
20811894f69aSRichard Henderson                 } else {
2082b7a83ff8SRichard Henderson                     ne_fprintf(f, ",");
20831894f69aSRichard Henderson                 }
20841894f69aSRichard Henderson                 if (set == 0) {
2085b7a83ff8SRichard Henderson                     ne_fprintf(f, "none");
20861894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
2087b7a83ff8SRichard Henderson                     ne_fprintf(f, "all");
20881894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
20891894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
20901894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
2091b7a83ff8SRichard Henderson                     ne_fprintf(f, "%s", tcg_target_reg_names[reg]);
20921894f69aSRichard Henderson #endif
20931894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
2094b7a83ff8SRichard Henderson                     ne_fprintf(f, "0x%x", (uint32_t)set);
20951894f69aSRichard Henderson                 } else {
2096b7a83ff8SRichard Henderson                     ne_fprintf(f, "0x%" PRIx64, (uint64_t)set);
20971894f69aSRichard Henderson                 }
20981894f69aSRichard Henderson             }
20991894f69aSRichard Henderson         }
21001894f69aSRichard Henderson 
2101b7a83ff8SRichard Henderson         putc('\n', f);
2102c896fe29Sbellard     }
2103c896fe29Sbellard }
2104c896fe29Sbellard 
2105c896fe29Sbellard /* we give more priority to constraints with less registers */
2106c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2107c896fe29Sbellard {
210874a11790SRichard Henderson     const TCGArgConstraint *arg_ct = &def->args_ct[k];
210929f5e925SRichard Henderson     int n = ctpop64(arg_ct->regs);
2110c896fe29Sbellard 
211129f5e925SRichard Henderson     /*
211229f5e925SRichard Henderson      * Sort constraints of a single register first, which includes output
211329f5e925SRichard Henderson      * aliases (which must exactly match the input already allocated).
211429f5e925SRichard Henderson      */
211529f5e925SRichard Henderson     if (n == 1 || arg_ct->oalias) {
211629f5e925SRichard Henderson         return INT_MAX;
2117c896fe29Sbellard     }
211829f5e925SRichard Henderson 
211929f5e925SRichard Henderson     /*
212029f5e925SRichard Henderson      * Sort register pairs next, first then second immediately after.
212129f5e925SRichard Henderson      * Arbitrarily sort multiple pairs by the index of the first reg;
212229f5e925SRichard Henderson      * there shouldn't be many pairs.
212329f5e925SRichard Henderson      */
212429f5e925SRichard Henderson     switch (arg_ct->pair) {
212529f5e925SRichard Henderson     case 1:
212629f5e925SRichard Henderson     case 3:
212729f5e925SRichard Henderson         return (k + 1) * 2;
212829f5e925SRichard Henderson     case 2:
212929f5e925SRichard Henderson         return (arg_ct->pair_index + 1) * 2 - 1;
213029f5e925SRichard Henderson     }
213129f5e925SRichard Henderson 
213229f5e925SRichard Henderson     /* Finally, sort by decreasing register count. */
213329f5e925SRichard Henderson     assert(n > 1);
213429f5e925SRichard Henderson     return -n;
2135c896fe29Sbellard }
2136c896fe29Sbellard 
2137c896fe29Sbellard /* sort from highest priority to lowest */
2138c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2139c896fe29Sbellard {
214066792f90SRichard Henderson     int i, j;
214166792f90SRichard Henderson     TCGArgConstraint *a = def->args_ct;
2142c896fe29Sbellard 
214366792f90SRichard Henderson     for (i = 0; i < n; i++) {
214466792f90SRichard Henderson         a[start + i].sort_index = start + i;
214566792f90SRichard Henderson     }
214666792f90SRichard Henderson     if (n <= 1) {
2147c896fe29Sbellard         return;
214866792f90SRichard Henderson     }
2149c896fe29Sbellard     for (i = 0; i < n - 1; i++) {
2150c896fe29Sbellard         for (j = i + 1; j < n; j++) {
215166792f90SRichard Henderson             int p1 = get_constraint_priority(def, a[start + i].sort_index);
215266792f90SRichard Henderson             int p2 = get_constraint_priority(def, a[start + j].sort_index);
2153c896fe29Sbellard             if (p1 < p2) {
215466792f90SRichard Henderson                 int tmp = a[start + i].sort_index;
215566792f90SRichard Henderson                 a[start + i].sort_index = a[start + j].sort_index;
215666792f90SRichard Henderson                 a[start + j].sort_index = tmp;
2157c896fe29Sbellard             }
2158c896fe29Sbellard         }
2159c896fe29Sbellard     }
2160c896fe29Sbellard }
2161c896fe29Sbellard 
2162f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2163c896fe29Sbellard {
2164a9751609SRichard Henderson     TCGOpcode op;
2165c896fe29Sbellard 
2166f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
2167f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
2168f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
216929f5e925SRichard Henderson         bool saw_alias_pair = false;
217029f5e925SRichard Henderson         int i, o, i2, o2, nb_args;
2171f69d277eSRichard Henderson 
2172f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
2173f69d277eSRichard Henderson             continue;
2174f69d277eSRichard Henderson         }
2175f69d277eSRichard Henderson 
2176c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
2177f69d277eSRichard Henderson         if (nb_args == 0) {
2178f69d277eSRichard Henderson             continue;
2179f69d277eSRichard Henderson         }
2180f69d277eSRichard Henderson 
21814c22e840SRichard Henderson         /*
21824c22e840SRichard Henderson          * Macro magic should make it impossible, but double-check that
21834c22e840SRichard Henderson          * the array index is in range.  Since the signness of an enum
21844c22e840SRichard Henderson          * is implementation defined, force the result to unsigned.
21854c22e840SRichard Henderson          */
21864c22e840SRichard Henderson         unsigned con_set = tcg_target_op_def(op);
21874c22e840SRichard Henderson         tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets));
21884c22e840SRichard Henderson         tdefs = &constraint_sets[con_set];
2189f69d277eSRichard Henderson 
2190c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2191f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
21928940ea0dSPhilippe Mathieu-Daudé             bool input_p = i >= def->nb_oargs;
21938940ea0dSPhilippe Mathieu-Daudé 
2194f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2195eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2196f69d277eSRichard Henderson 
219717280ff4SRichard Henderson             switch (*ct_str) {
219817280ff4SRichard Henderson             case '0' ... '9':
21998940ea0dSPhilippe Mathieu-Daudé                 o = *ct_str - '0';
22008940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(input_p);
22018940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(o < def->nb_oargs);
22028940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(def->args_ct[o].regs != 0);
22038940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(!def->args_ct[o].oalias);
22048940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i] = def->args_ct[o];
2205bc2b17e6SRichard Henderson                 /* The output sets oalias.  */
22068940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[o].oalias = 1;
22078940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[o].alias_index = i;
2208bc2b17e6SRichard Henderson                 /* The input sets ialias. */
22098940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i].ialias = 1;
22108940ea0dSPhilippe Mathieu-Daudé                 def->args_ct[i].alias_index = o;
221129f5e925SRichard Henderson                 if (def->args_ct[i].pair) {
221229f5e925SRichard Henderson                     saw_alias_pair = true;
221329f5e925SRichard Henderson                 }
22148940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(ct_str[1] == '\0');
22158940ea0dSPhilippe Mathieu-Daudé                 continue;
22168940ea0dSPhilippe Mathieu-Daudé 
221782790a87SRichard Henderson             case '&':
22188940ea0dSPhilippe Mathieu-Daudé                 tcg_debug_assert(!input_p);
2219bc2b17e6SRichard Henderson                 def->args_ct[i].newreg = true;
222082790a87SRichard Henderson                 ct_str++;
222182790a87SRichard Henderson                 break;
222229f5e925SRichard Henderson 
222329f5e925SRichard Henderson             case 'p': /* plus */
222429f5e925SRichard Henderson                 /* Allocate to the register after the previous. */
222529f5e925SRichard Henderson                 tcg_debug_assert(i > (input_p ? def->nb_oargs : 0));
222629f5e925SRichard Henderson                 o = i - 1;
222729f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].pair);
222829f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].ct);
222929f5e925SRichard Henderson                 def->args_ct[i] = (TCGArgConstraint){
223029f5e925SRichard Henderson                     .pair = 2,
223129f5e925SRichard Henderson                     .pair_index = o,
223229f5e925SRichard Henderson                     .regs = def->args_ct[o].regs << 1,
223329f5e925SRichard Henderson                 };
223429f5e925SRichard Henderson                 def->args_ct[o].pair = 1;
223529f5e925SRichard Henderson                 def->args_ct[o].pair_index = i;
223629f5e925SRichard Henderson                 tcg_debug_assert(ct_str[1] == '\0');
223729f5e925SRichard Henderson                 continue;
223829f5e925SRichard Henderson 
223929f5e925SRichard Henderson             case 'm': /* minus */
224029f5e925SRichard Henderson                 /* Allocate to the register before the previous. */
224129f5e925SRichard Henderson                 tcg_debug_assert(i > (input_p ? def->nb_oargs : 0));
224229f5e925SRichard Henderson                 o = i - 1;
224329f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].pair);
224429f5e925SRichard Henderson                 tcg_debug_assert(!def->args_ct[o].ct);
224529f5e925SRichard Henderson                 def->args_ct[i] = (TCGArgConstraint){
224629f5e925SRichard Henderson                     .pair = 1,
224729f5e925SRichard Henderson                     .pair_index = o,
224829f5e925SRichard Henderson                     .regs = def->args_ct[o].regs >> 1,
224929f5e925SRichard Henderson                 };
225029f5e925SRichard Henderson                 def->args_ct[o].pair = 2;
225129f5e925SRichard Henderson                 def->args_ct[o].pair_index = i;
225229f5e925SRichard Henderson                 tcg_debug_assert(ct_str[1] == '\0');
225329f5e925SRichard Henderson                 continue;
22548940ea0dSPhilippe Mathieu-Daudé             }
22558940ea0dSPhilippe Mathieu-Daudé 
22568940ea0dSPhilippe Mathieu-Daudé             do {
22578940ea0dSPhilippe Mathieu-Daudé                 switch (*ct_str) {
2258c896fe29Sbellard                 case 'i':
2259c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2260c896fe29Sbellard                     break;
2261358b4923SRichard Henderson 
2262358b4923SRichard Henderson                 /* Include all of the target-specific constraints. */
2263358b4923SRichard Henderson 
2264358b4923SRichard Henderson #undef CONST
2265358b4923SRichard Henderson #define CONST(CASE, MASK) \
22668940ea0dSPhilippe Mathieu-Daudé     case CASE: def->args_ct[i].ct |= MASK; break;
2267358b4923SRichard Henderson #define REGS(CASE, MASK) \
22688940ea0dSPhilippe Mathieu-Daudé     case CASE: def->args_ct[i].regs |= MASK; break;
2269358b4923SRichard Henderson 
2270358b4923SRichard Henderson #include "tcg-target-con-str.h"
2271358b4923SRichard Henderson 
2272358b4923SRichard Henderson #undef REGS
2273358b4923SRichard Henderson #undef CONST
2274c896fe29Sbellard                 default:
22758940ea0dSPhilippe Mathieu-Daudé                 case '0' ... '9':
22768940ea0dSPhilippe Mathieu-Daudé                 case '&':
227729f5e925SRichard Henderson                 case 'p':
227829f5e925SRichard Henderson                 case 'm':
2279358b4923SRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2280358b4923SRichard Henderson                     g_assert_not_reached();
2281358b4923SRichard Henderson                 }
22828940ea0dSPhilippe Mathieu-Daudé             } while (*++ct_str != '\0');
2283c896fe29Sbellard         }
2284c896fe29Sbellard 
2285c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2286eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2287c68aaa18SStefan Weil 
228829f5e925SRichard Henderson         /*
228929f5e925SRichard Henderson          * Fix up output pairs that are aliased with inputs.
229029f5e925SRichard Henderson          * When we created the alias, we copied pair from the output.
229129f5e925SRichard Henderson          * There are three cases:
229229f5e925SRichard Henderson          *    (1a) Pairs of inputs alias pairs of outputs.
229329f5e925SRichard Henderson          *    (1b) One input aliases the first of a pair of outputs.
229429f5e925SRichard Henderson          *    (2)  One input aliases the second of a pair of outputs.
229529f5e925SRichard Henderson          *
229629f5e925SRichard Henderson          * Case 1a is handled by making sure that the pair_index'es are
229729f5e925SRichard Henderson          * properly updated so that they appear the same as a pair of inputs.
229829f5e925SRichard Henderson          *
229929f5e925SRichard Henderson          * Case 1b is handled by setting the pair_index of the input to
230029f5e925SRichard Henderson          * itself, simply so it doesn't point to an unrelated argument.
230129f5e925SRichard Henderson          * Since we don't encounter the "second" during the input allocation
230229f5e925SRichard Henderson          * phase, nothing happens with the second half of the input pair.
230329f5e925SRichard Henderson          *
230429f5e925SRichard Henderson          * Case 2 is handled by setting the second input to pair=3, the
230529f5e925SRichard Henderson          * first output to pair=3, and the pair_index'es to match.
230629f5e925SRichard Henderson          */
230729f5e925SRichard Henderson         if (saw_alias_pair) {
230829f5e925SRichard Henderson             for (i = def->nb_oargs; i < nb_args; i++) {
230929f5e925SRichard Henderson                 /*
231029f5e925SRichard Henderson                  * Since [0-9pm] must be alone in the constraint string,
231129f5e925SRichard Henderson                  * the only way they can both be set is if the pair comes
231229f5e925SRichard Henderson                  * from the output alias.
231329f5e925SRichard Henderson                  */
231429f5e925SRichard Henderson                 if (!def->args_ct[i].ialias) {
231529f5e925SRichard Henderson                     continue;
231629f5e925SRichard Henderson                 }
231729f5e925SRichard Henderson                 switch (def->args_ct[i].pair) {
231829f5e925SRichard Henderson                 case 0:
231929f5e925SRichard Henderson                     break;
232029f5e925SRichard Henderson                 case 1:
232129f5e925SRichard Henderson                     o = def->args_ct[i].alias_index;
232229f5e925SRichard Henderson                     o2 = def->args_ct[o].pair_index;
232329f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o].pair == 1);
232429f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o2].pair == 2);
232529f5e925SRichard Henderson                     if (def->args_ct[o2].oalias) {
232629f5e925SRichard Henderson                         /* Case 1a */
232729f5e925SRichard Henderson                         i2 = def->args_ct[o2].alias_index;
232829f5e925SRichard Henderson                         tcg_debug_assert(def->args_ct[i2].pair == 2);
232929f5e925SRichard Henderson                         def->args_ct[i2].pair_index = i;
233029f5e925SRichard Henderson                         def->args_ct[i].pair_index = i2;
233129f5e925SRichard Henderson                     } else {
233229f5e925SRichard Henderson                         /* Case 1b */
233329f5e925SRichard Henderson                         def->args_ct[i].pair_index = i;
233429f5e925SRichard Henderson                     }
233529f5e925SRichard Henderson                     break;
233629f5e925SRichard Henderson                 case 2:
233729f5e925SRichard Henderson                     o = def->args_ct[i].alias_index;
233829f5e925SRichard Henderson                     o2 = def->args_ct[o].pair_index;
233929f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o].pair == 2);
234029f5e925SRichard Henderson                     tcg_debug_assert(def->args_ct[o2].pair == 1);
234129f5e925SRichard Henderson                     if (def->args_ct[o2].oalias) {
234229f5e925SRichard Henderson                         /* Case 1a */
234329f5e925SRichard Henderson                         i2 = def->args_ct[o2].alias_index;
234429f5e925SRichard Henderson                         tcg_debug_assert(def->args_ct[i2].pair == 1);
234529f5e925SRichard Henderson                         def->args_ct[i2].pair_index = i;
234629f5e925SRichard Henderson                         def->args_ct[i].pair_index = i2;
234729f5e925SRichard Henderson                     } else {
234829f5e925SRichard Henderson                         /* Case 2 */
234929f5e925SRichard Henderson                         def->args_ct[i].pair = 3;
235029f5e925SRichard Henderson                         def->args_ct[o2].pair = 3;
235129f5e925SRichard Henderson                         def->args_ct[i].pair_index = o2;
235229f5e925SRichard Henderson                         def->args_ct[o2].pair_index = i;
235329f5e925SRichard Henderson                     }
235429f5e925SRichard Henderson                     break;
235529f5e925SRichard Henderson                 default:
235629f5e925SRichard Henderson                     g_assert_not_reached();
235729f5e925SRichard Henderson                 }
235829f5e925SRichard Henderson             }
235929f5e925SRichard Henderson         }
236029f5e925SRichard Henderson 
2361c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
2362c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
2363c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
2364c896fe29Sbellard     }
2365c896fe29Sbellard }
2366c896fe29Sbellard 
23670c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
23680c627cdcSRichard Henderson {
2369d88a117eSRichard Henderson     TCGLabel *label;
2370d88a117eSRichard Henderson 
2371d88a117eSRichard Henderson     switch (op->opc) {
2372d88a117eSRichard Henderson     case INDEX_op_br:
2373d88a117eSRichard Henderson         label = arg_label(op->args[0]);
2374d88a117eSRichard Henderson         label->refs--;
2375d88a117eSRichard Henderson         break;
2376d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
2377d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
2378d88a117eSRichard Henderson         label = arg_label(op->args[3]);
2379d88a117eSRichard Henderson         label->refs--;
2380d88a117eSRichard Henderson         break;
2381d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
2382d88a117eSRichard Henderson         label = arg_label(op->args[5]);
2383d88a117eSRichard Henderson         label->refs--;
2384d88a117eSRichard Henderson         break;
2385d88a117eSRichard Henderson     default:
2386d88a117eSRichard Henderson         break;
2387d88a117eSRichard Henderson     }
2388d88a117eSRichard Henderson 
238915fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
239015fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
2391abebf925SRichard Henderson     s->nb_ops--;
23920c627cdcSRichard Henderson 
23930c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
2394d73415a3SStefan Hajnoczi     qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
23950c627cdcSRichard Henderson #endif
23960c627cdcSRichard Henderson }
23970c627cdcSRichard Henderson 
2398a80cdd31SRichard Henderson void tcg_remove_ops_after(TCGOp *op)
2399a80cdd31SRichard Henderson {
2400a80cdd31SRichard Henderson     TCGContext *s = tcg_ctx;
2401a80cdd31SRichard Henderson 
2402a80cdd31SRichard Henderson     while (true) {
2403a80cdd31SRichard Henderson         TCGOp *last = tcg_last_op();
2404a80cdd31SRichard Henderson         if (last == op) {
2405a80cdd31SRichard Henderson             return;
2406a80cdd31SRichard Henderson         }
2407a80cdd31SRichard Henderson         tcg_op_remove(s, last);
2408a80cdd31SRichard Henderson     }
2409a80cdd31SRichard Henderson }
2410a80cdd31SRichard Henderson 
2411d4478943SPhilippe Mathieu-Daudé static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs)
241215fa08f8SRichard Henderson {
241315fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
2414cb10bc63SRichard Henderson     TCGOp *op = NULL;
241515fa08f8SRichard Henderson 
2416cb10bc63SRichard Henderson     if (unlikely(!QTAILQ_EMPTY(&s->free_ops))) {
2417cb10bc63SRichard Henderson         QTAILQ_FOREACH(op, &s->free_ops, link) {
2418cb10bc63SRichard Henderson             if (nargs <= op->nargs) {
241915fa08f8SRichard Henderson                 QTAILQ_REMOVE(&s->free_ops, op, link);
2420cb10bc63SRichard Henderson                 nargs = op->nargs;
2421cb10bc63SRichard Henderson                 goto found;
242215fa08f8SRichard Henderson             }
2423cb10bc63SRichard Henderson         }
2424cb10bc63SRichard Henderson     }
2425cb10bc63SRichard Henderson 
2426cb10bc63SRichard Henderson     /* Most opcodes have 3 or 4 operands: reduce fragmentation. */
2427cb10bc63SRichard Henderson     nargs = MAX(4, nargs);
2428cb10bc63SRichard Henderson     op = tcg_malloc(sizeof(TCGOp) + sizeof(TCGArg) * nargs);
2429cb10bc63SRichard Henderson 
2430cb10bc63SRichard Henderson  found:
243115fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
243215fa08f8SRichard Henderson     op->opc = opc;
2433cb10bc63SRichard Henderson     op->nargs = nargs;
243415fa08f8SRichard Henderson 
2435cb10bc63SRichard Henderson     /* Check for bitfield overflow. */
2436cb10bc63SRichard Henderson     tcg_debug_assert(op->nargs == nargs);
2437cb10bc63SRichard Henderson 
2438cb10bc63SRichard Henderson     s->nb_ops++;
243915fa08f8SRichard Henderson     return op;
244015fa08f8SRichard Henderson }
244115fa08f8SRichard Henderson 
2442d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs)
244315fa08f8SRichard Henderson {
2444d4478943SPhilippe Mathieu-Daudé     TCGOp *op = tcg_op_alloc(opc, nargs);
244515fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
244615fa08f8SRichard Henderson     return op;
244715fa08f8SRichard Henderson }
244815fa08f8SRichard Henderson 
2449d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op,
2450d4478943SPhilippe Mathieu-Daudé                             TCGOpcode opc, unsigned nargs)
24515a18407fSRichard Henderson {
2452d4478943SPhilippe Mathieu-Daudé     TCGOp *new_op = tcg_op_alloc(opc, nargs);
245315fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
24545a18407fSRichard Henderson     return new_op;
24555a18407fSRichard Henderson }
24565a18407fSRichard Henderson 
2457d4478943SPhilippe Mathieu-Daudé TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op,
2458d4478943SPhilippe Mathieu-Daudé                            TCGOpcode opc, unsigned nargs)
24595a18407fSRichard Henderson {
2460d4478943SPhilippe Mathieu-Daudé     TCGOp *new_op = tcg_op_alloc(opc, nargs);
246115fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
24625a18407fSRichard Henderson     return new_op;
24635a18407fSRichard Henderson }
24645a18407fSRichard Henderson 
2465b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
2466b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s)
2467b4fc67c7SRichard Henderson {
2468b4fc67c7SRichard Henderson     TCGOp *op, *op_next;
2469b4fc67c7SRichard Henderson     bool dead = false;
2470b4fc67c7SRichard Henderson 
2471b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
2472b4fc67c7SRichard Henderson         bool remove = dead;
2473b4fc67c7SRichard Henderson         TCGLabel *label;
2474b4fc67c7SRichard Henderson 
2475b4fc67c7SRichard Henderson         switch (op->opc) {
2476b4fc67c7SRichard Henderson         case INDEX_op_set_label:
2477b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
2478b4fc67c7SRichard Henderson             if (label->refs == 0) {
2479b4fc67c7SRichard Henderson                 /*
2480b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
2481b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
2482b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
2483b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
2484b4fc67c7SRichard Henderson                  * little to be gained by iterating.
2485b4fc67c7SRichard Henderson                  */
2486b4fc67c7SRichard Henderson                 remove = true;
2487b4fc67c7SRichard Henderson             } else {
2488b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
2489b4fc67c7SRichard Henderson                 dead = false;
2490b4fc67c7SRichard Henderson                 remove = false;
2491b4fc67c7SRichard Henderson 
2492b4fc67c7SRichard Henderson                 /*
2493b4fc67c7SRichard Henderson                  * Optimization can fold conditional branches to unconditional.
2494b4fc67c7SRichard Henderson                  * If we find a label with one reference which is preceded by
2495b4fc67c7SRichard Henderson                  * an unconditional branch to it, remove both.  This needed to
2496b4fc67c7SRichard Henderson                  * wait until the dead code in between them was removed.
2497b4fc67c7SRichard Henderson                  */
2498b4fc67c7SRichard Henderson                 if (label->refs == 1) {
2499eae3eb3eSPaolo Bonzini                     TCGOp *op_prev = QTAILQ_PREV(op, link);
2500b4fc67c7SRichard Henderson                     if (op_prev->opc == INDEX_op_br &&
2501b4fc67c7SRichard Henderson                         label == arg_label(op_prev->args[0])) {
2502b4fc67c7SRichard Henderson                         tcg_op_remove(s, op_prev);
2503b4fc67c7SRichard Henderson                         remove = true;
2504b4fc67c7SRichard Henderson                     }
2505b4fc67c7SRichard Henderson                 }
2506b4fc67c7SRichard Henderson             }
2507b4fc67c7SRichard Henderson             break;
2508b4fc67c7SRichard Henderson 
2509b4fc67c7SRichard Henderson         case INDEX_op_br:
2510b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
2511b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
2512b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
2513b4fc67c7SRichard Henderson             dead = true;
2514b4fc67c7SRichard Henderson             break;
2515b4fc67c7SRichard Henderson 
2516b4fc67c7SRichard Henderson         case INDEX_op_call:
2517b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
251890163900SRichard Henderson             if (tcg_call_flags(op) & TCG_CALL_NO_RETURN) {
2519b4fc67c7SRichard Henderson                 dead = true;
2520b4fc67c7SRichard Henderson             }
2521b4fc67c7SRichard Henderson             break;
2522b4fc67c7SRichard Henderson 
2523b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
2524b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
2525b4fc67c7SRichard Henderson             remove = false;
2526b4fc67c7SRichard Henderson             break;
2527b4fc67c7SRichard Henderson 
2528b4fc67c7SRichard Henderson         default:
2529b4fc67c7SRichard Henderson             break;
2530b4fc67c7SRichard Henderson         }
2531b4fc67c7SRichard Henderson 
2532b4fc67c7SRichard Henderson         if (remove) {
2533b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
2534b4fc67c7SRichard Henderson         }
2535b4fc67c7SRichard Henderson     }
2536b4fc67c7SRichard Henderson }
2537b4fc67c7SRichard Henderson 
2538c70fbf0aSRichard Henderson #define TS_DEAD  1
2539c70fbf0aSRichard Henderson #define TS_MEM   2
2540c70fbf0aSRichard Henderson 
25415a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
25425a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
25435a18407fSRichard Henderson 
254425f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
254525f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
254625f49c5fSRichard Henderson {
254725f49c5fSRichard Henderson     return ts->state_ptr;
254825f49c5fSRichard Henderson }
254925f49c5fSRichard Henderson 
255025f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
255125f49c5fSRichard Henderson  * maximal regset for its type.
255225f49c5fSRichard Henderson  */
255325f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
255425f49c5fSRichard Henderson {
255525f49c5fSRichard Henderson     *la_temp_pref(ts)
255625f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
255725f49c5fSRichard Henderson }
255825f49c5fSRichard Henderson 
25599c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
25609c43b68dSAurelien Jarno    should be in memory. */
25612616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
2562c896fe29Sbellard {
2563b83eabeaSRichard Henderson     int i;
2564b83eabeaSRichard Henderson 
2565b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2566b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
256725f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2568b83eabeaSRichard Henderson     }
2569b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2570b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
257125f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2572b83eabeaSRichard Henderson     }
2573c896fe29Sbellard }
2574c896fe29Sbellard 
25759c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
25769c43b68dSAurelien Jarno    and local temps should be in memory. */
25772616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
2578641d5fbeSbellard {
2579b83eabeaSRichard Henderson     int i;
2580641d5fbeSbellard 
2581ee17db83SRichard Henderson     for (i = 0; i < nt; ++i) {
2582ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2583ee17db83SRichard Henderson         int state;
2584ee17db83SRichard Henderson 
2585ee17db83SRichard Henderson         switch (ts->kind) {
2586ee17db83SRichard Henderson         case TEMP_FIXED:
2587ee17db83SRichard Henderson         case TEMP_GLOBAL:
2588ee17db83SRichard Henderson         case TEMP_LOCAL:
2589ee17db83SRichard Henderson             state = TS_DEAD | TS_MEM;
2590ee17db83SRichard Henderson             break;
2591ee17db83SRichard Henderson         case TEMP_NORMAL:
2592c7482438SRichard Henderson         case TEMP_EBB:
2593c0522136SRichard Henderson         case TEMP_CONST:
2594ee17db83SRichard Henderson             state = TS_DEAD;
2595ee17db83SRichard Henderson             break;
2596ee17db83SRichard Henderson         default:
2597ee17db83SRichard Henderson             g_assert_not_reached();
2598c70fbf0aSRichard Henderson         }
2599ee17db83SRichard Henderson         ts->state = state;
2600ee17db83SRichard Henderson         la_reset_pref(ts);
2601641d5fbeSbellard     }
2602641d5fbeSbellard }
2603641d5fbeSbellard 
2604f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
2605f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
2606f65a061cSRichard Henderson {
2607f65a061cSRichard Henderson     int i;
2608f65a061cSRichard Henderson 
2609f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
261025f49c5fSRichard Henderson         int state = s->temps[i].state;
261125f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
261225f49c5fSRichard Henderson         if (state == TS_DEAD) {
261325f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
261425f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
261525f49c5fSRichard Henderson         }
2616f65a061cSRichard Henderson     }
2617f65a061cSRichard Henderson }
2618f65a061cSRichard Henderson 
2619b4cb76e6SRichard Henderson /*
2620c7482438SRichard Henderson  * liveness analysis: conditional branch: all temps are dead unless
2621c7482438SRichard Henderson  * explicitly live-across-conditional-branch, globals and local temps
2622c7482438SRichard Henderson  * should be synced.
2623b4cb76e6SRichard Henderson  */
2624b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
2625b4cb76e6SRichard Henderson {
2626b4cb76e6SRichard Henderson     la_global_sync(s, ng);
2627b4cb76e6SRichard Henderson 
2628b4cb76e6SRichard Henderson     for (int i = ng; i < nt; ++i) {
2629c0522136SRichard Henderson         TCGTemp *ts = &s->temps[i];
2630c0522136SRichard Henderson         int state;
2631c0522136SRichard Henderson 
2632c0522136SRichard Henderson         switch (ts->kind) {
2633c0522136SRichard Henderson         case TEMP_LOCAL:
2634c0522136SRichard Henderson             state = ts->state;
2635c0522136SRichard Henderson             ts->state = state | TS_MEM;
2636b4cb76e6SRichard Henderson             if (state != TS_DEAD) {
2637b4cb76e6SRichard Henderson                 continue;
2638b4cb76e6SRichard Henderson             }
2639c0522136SRichard Henderson             break;
2640c0522136SRichard Henderson         case TEMP_NORMAL:
2641b4cb76e6SRichard Henderson             s->temps[i].state = TS_DEAD;
2642c0522136SRichard Henderson             break;
2643c7482438SRichard Henderson         case TEMP_EBB:
2644c0522136SRichard Henderson         case TEMP_CONST:
2645c0522136SRichard Henderson             continue;
2646c0522136SRichard Henderson         default:
2647c0522136SRichard Henderson             g_assert_not_reached();
2648b4cb76e6SRichard Henderson         }
2649b4cb76e6SRichard Henderson         la_reset_pref(&s->temps[i]);
2650b4cb76e6SRichard Henderson     }
2651b4cb76e6SRichard Henderson }
2652b4cb76e6SRichard Henderson 
2653f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
2654f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
2655f65a061cSRichard Henderson {
2656f65a061cSRichard Henderson     int i;
2657f65a061cSRichard Henderson 
2658f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
2659f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
266025f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
266125f49c5fSRichard Henderson     }
266225f49c5fSRichard Henderson }
266325f49c5fSRichard Henderson 
266425f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
266525f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
266625f49c5fSRichard Henderson {
266725f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
266825f49c5fSRichard Henderson     int i;
266925f49c5fSRichard Henderson 
267025f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
267125f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
267225f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
267325f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
267425f49c5fSRichard Henderson             TCGRegSet set = *pset;
267525f49c5fSRichard Henderson 
267625f49c5fSRichard Henderson             set &= mask;
267725f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
267825f49c5fSRichard Henderson             if (set == 0) {
267925f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
268025f49c5fSRichard Henderson             }
268125f49c5fSRichard Henderson             *pset = set;
268225f49c5fSRichard Henderson         }
2683f65a061cSRichard Henderson     }
2684f65a061cSRichard Henderson }
2685f65a061cSRichard Henderson 
2686a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
2687c896fe29Sbellard    given input arguments is dead. Instructions updating dead
2688c896fe29Sbellard    temporaries are removed. */
2689b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s)
2690c896fe29Sbellard {
2691c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
26922616c808SRichard Henderson     int nb_temps = s->nb_temps;
269315fa08f8SRichard Henderson     TCGOp *op, *op_prev;
269425f49c5fSRichard Henderson     TCGRegSet *prefs;
269525f49c5fSRichard Henderson     int i;
269625f49c5fSRichard Henderson 
269725f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
269825f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
269925f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
270025f49c5fSRichard Henderson     }
2701c896fe29Sbellard 
2702ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
27032616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
2704c896fe29Sbellard 
2705eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
270625f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
2707c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
2708c45cb8bbSRichard Henderson         bool have_opc_new2;
2709a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
271025f49c5fSRichard Henderson         TCGTemp *ts;
2711c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2712c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2713c45cb8bbSRichard Henderson 
2714c45cb8bbSRichard Henderson         switch (opc) {
2715c896fe29Sbellard         case INDEX_op_call:
2716c6e113f5Sbellard             {
271739004a71SRichard Henderson                 const TCGHelperInfo *info = tcg_call_info(op);
271839004a71SRichard Henderson                 int call_flags = tcg_call_flags(op);
2719c6e113f5Sbellard 
2720cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
2721cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
2722c6e113f5Sbellard 
2723c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
272478505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
2725c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
272625f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
272725f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
2728c6e113f5Sbellard                             goto do_not_remove_call;
2729c6e113f5Sbellard                         }
27309c43b68dSAurelien Jarno                     }
2731c45cb8bbSRichard Henderson                     goto do_remove;
2732152c35aaSRichard Henderson                 }
2733c6e113f5Sbellard             do_not_remove_call:
2734c896fe29Sbellard 
273525f49c5fSRichard Henderson                 /* Output args are dead.  */
2736c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
273725f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
273825f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
2739a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
27406b64b624SAurelien Jarno                     }
274125f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
2742a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
27439c43b68dSAurelien Jarno                     }
274425f49c5fSRichard Henderson                     ts->state = TS_DEAD;
274525f49c5fSRichard Henderson                     la_reset_pref(ts);
2746c896fe29Sbellard                 }
2747c896fe29Sbellard 
274831fd884bSRichard Henderson                 /* Not used -- it will be tcg_target_call_oarg_reg().  */
274931fd884bSRichard Henderson                 memset(op->output_pref, 0, sizeof(op->output_pref));
275031fd884bSRichard Henderson 
275178505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
275278505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
2753f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
2754c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
2755f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
2756b9c18f56Saurel32                 }
2757c896fe29Sbellard 
275825f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
2759866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
276025f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
276139004a71SRichard Henderson                     if (ts->state & TS_DEAD) {
2762a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
2763c896fe29Sbellard                     }
2764c896fe29Sbellard                 }
276525f49c5fSRichard Henderson 
276625f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
276725f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
276825f49c5fSRichard Henderson 
276939004a71SRichard Henderson                 /*
277039004a71SRichard Henderson                  * Input arguments are live for preceding opcodes.
277139004a71SRichard Henderson                  *
277239004a71SRichard Henderson                  * For those arguments that die, and will be allocated in
277339004a71SRichard Henderson                  * registers, clear the register set for that arg, to be
277439004a71SRichard Henderson                  * filled in below.  For args that will be on the stack,
277539004a71SRichard Henderson                  * reset to any available reg.  Process arguments in reverse
277639004a71SRichard Henderson                  * order so that if a temp is used more than once, the stack
277739004a71SRichard Henderson                  * reset to max happens before the register reset to 0.
277825f49c5fSRichard Henderson                  */
277939004a71SRichard Henderson                 for (i = nb_iargs - 1; i >= 0; i--) {
278039004a71SRichard Henderson                     const TCGCallArgumentLoc *loc = &info->in[i];
278139004a71SRichard Henderson                     ts = arg_temp(op->args[nb_oargs + i]);
278239004a71SRichard Henderson 
278339004a71SRichard Henderson                     if (ts->state & TS_DEAD) {
278439004a71SRichard Henderson                         switch (loc->kind) {
278539004a71SRichard Henderson                         case TCG_CALL_ARG_NORMAL:
278639004a71SRichard Henderson                         case TCG_CALL_ARG_EXTEND_U:
278739004a71SRichard Henderson                         case TCG_CALL_ARG_EXTEND_S:
278839004a71SRichard Henderson                             if (REG_P(loc)) {
278939004a71SRichard Henderson                                 *la_temp_pref(ts) = 0;
279039004a71SRichard Henderson                                 break;
279139004a71SRichard Henderson                             }
279239004a71SRichard Henderson                             /* fall through */
279339004a71SRichard Henderson                         default:
279439004a71SRichard Henderson                             *la_temp_pref(ts) =
279539004a71SRichard Henderson                                 tcg_target_available_regs[ts->type];
279639004a71SRichard Henderson                             break;
279739004a71SRichard Henderson                         }
279825f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
279925f49c5fSRichard Henderson                     }
280025f49c5fSRichard Henderson                 }
280125f49c5fSRichard Henderson 
280239004a71SRichard Henderson                 /*
280339004a71SRichard Henderson                  * For each input argument, add its input register to prefs.
280439004a71SRichard Henderson                  * If a temp is used once, this produces a single set bit;
280539004a71SRichard Henderson                  * if a temp is used multiple times, this produces a set.
280639004a71SRichard Henderson                  */
280739004a71SRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
280839004a71SRichard Henderson                     const TCGCallArgumentLoc *loc = &info->in[i];
280939004a71SRichard Henderson                     ts = arg_temp(op->args[nb_oargs + i]);
281039004a71SRichard Henderson 
281139004a71SRichard Henderson                     switch (loc->kind) {
281239004a71SRichard Henderson                     case TCG_CALL_ARG_NORMAL:
281339004a71SRichard Henderson                     case TCG_CALL_ARG_EXTEND_U:
281439004a71SRichard Henderson                     case TCG_CALL_ARG_EXTEND_S:
281539004a71SRichard Henderson                         if (REG_P(loc)) {
281625f49c5fSRichard Henderson                             tcg_regset_set_reg(*la_temp_pref(ts),
281739004a71SRichard Henderson                                 tcg_target_call_iarg_regs[loc->arg_slot]);
281839004a71SRichard Henderson                         }
281939004a71SRichard Henderson                         break;
282039004a71SRichard Henderson                     default:
282139004a71SRichard Henderson                         break;
2822c70fbf0aSRichard Henderson                     }
2823c19f47bfSAurelien Jarno                 }
2824c6e113f5Sbellard             }
2825c896fe29Sbellard             break;
2826765b842aSRichard Henderson         case INDEX_op_insn_start:
2827c896fe29Sbellard             break;
28285ff9d6a4Sbellard         case INDEX_op_discard:
28295ff9d6a4Sbellard             /* mark the temporary as dead */
283025f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
283125f49c5fSRichard Henderson             ts->state = TS_DEAD;
283225f49c5fSRichard Henderson             la_reset_pref(ts);
28335ff9d6a4Sbellard             break;
28341305c451SRichard Henderson 
28351305c451SRichard Henderson         case INDEX_op_add2_i32:
2836c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
2837f1fae40cSRichard Henderson             goto do_addsub2;
28381305c451SRichard Henderson         case INDEX_op_sub2_i32:
2839c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
2840f1fae40cSRichard Henderson             goto do_addsub2;
2841f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
2842c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
2843f1fae40cSRichard Henderson             goto do_addsub2;
2844f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
2845c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
2846f1fae40cSRichard Henderson         do_addsub2:
28471305c451SRichard Henderson             nb_iargs = 4;
28481305c451SRichard Henderson             nb_oargs = 2;
28491305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
28501305c451SRichard Henderson                the low part.  The result can be optimized to a simple
28511305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
28521305c451SRichard Henderson                cpu mode is set to 32 bit.  */
2853b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2854b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
28551305c451SRichard Henderson                     goto do_remove;
28561305c451SRichard Henderson                 }
2857c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
2858c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
2859c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2860efee3746SRichard Henderson                 op->args[1] = op->args[2];
2861efee3746SRichard Henderson                 op->args[2] = op->args[4];
28621305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
28631305c451SRichard Henderson                 nb_iargs = 2;
28641305c451SRichard Henderson                 nb_oargs = 1;
28651305c451SRichard Henderson             }
28661305c451SRichard Henderson             goto do_not_remove;
28671305c451SRichard Henderson 
28681414968aSRichard Henderson         case INDEX_op_mulu2_i32:
2869c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2870c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
2871c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
287203271524SRichard Henderson             goto do_mul2;
2873f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
2874c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2875c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
2876c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
2877f1fae40cSRichard Henderson             goto do_mul2;
2878f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
2879c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2880c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
2881c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
288203271524SRichard Henderson             goto do_mul2;
2883f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
2884c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2885c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
2886c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
288703271524SRichard Henderson             goto do_mul2;
2888f1fae40cSRichard Henderson         do_mul2:
28891414968aSRichard Henderson             nb_iargs = 2;
28901414968aSRichard Henderson             nb_oargs = 2;
2891b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2892b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
289303271524SRichard Henderson                     /* Both parts of the operation are dead.  */
28941414968aSRichard Henderson                     goto do_remove;
28951414968aSRichard Henderson                 }
289603271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
2897c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2898efee3746SRichard Henderson                 op->args[1] = op->args[2];
2899efee3746SRichard Henderson                 op->args[2] = op->args[3];
2900b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
290103271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
2902c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
2903efee3746SRichard Henderson                 op->args[0] = op->args[1];
2904efee3746SRichard Henderson                 op->args[1] = op->args[2];
2905efee3746SRichard Henderson                 op->args[2] = op->args[3];
290603271524SRichard Henderson             } else {
290703271524SRichard Henderson                 goto do_not_remove;
290803271524SRichard Henderson             }
290903271524SRichard Henderson             /* Mark the single-word operation live.  */
29101414968aSRichard Henderson             nb_oargs = 1;
29111414968aSRichard Henderson             goto do_not_remove;
29121414968aSRichard Henderson 
2913c896fe29Sbellard         default:
29141305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
2915c896fe29Sbellard             nb_iargs = def->nb_iargs;
2916c896fe29Sbellard             nb_oargs = def->nb_oargs;
2917c896fe29Sbellard 
2918c896fe29Sbellard             /* Test if the operation can be removed because all
29195ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
29205ff9d6a4Sbellard                implies side effects */
29215ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
2922c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
2923b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
2924c896fe29Sbellard                         goto do_not_remove;
2925c896fe29Sbellard                     }
29269c43b68dSAurelien Jarno                 }
2927152c35aaSRichard Henderson                 goto do_remove;
2928152c35aaSRichard Henderson             }
2929152c35aaSRichard Henderson             goto do_not_remove;
2930152c35aaSRichard Henderson 
29311305c451SRichard Henderson         do_remove:
29320c627cdcSRichard Henderson             tcg_op_remove(s, op);
2933152c35aaSRichard Henderson             break;
2934152c35aaSRichard Henderson 
2935c896fe29Sbellard         do_not_remove:
2936c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
293725f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
293825f49c5fSRichard Henderson 
293925f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
294031fd884bSRichard Henderson                 if (i < ARRAY_SIZE(op->output_pref)) {
294125f49c5fSRichard Henderson                     op->output_pref[i] = *la_temp_pref(ts);
294231fd884bSRichard Henderson                 }
294325f49c5fSRichard Henderson 
294425f49c5fSRichard Henderson                 /* Output args are dead.  */
294525f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2946a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
29476b64b624SAurelien Jarno                 }
294825f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
2949a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
29509c43b68dSAurelien Jarno                 }
295125f49c5fSRichard Henderson                 ts->state = TS_DEAD;
295225f49c5fSRichard Henderson                 la_reset_pref(ts);
2953c896fe29Sbellard             }
2954c896fe29Sbellard 
295525f49c5fSRichard Henderson             /* If end of basic block, update.  */
2956ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
2957ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
2958b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_COND_BRANCH) {
2959b4cb76e6SRichard Henderson                 la_bb_sync(s, nb_globals, nb_temps);
2960ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
29612616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
29623d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
2963f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
296425f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
296525f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
296625f49c5fSRichard Henderson                 }
2967c896fe29Sbellard             }
2968c896fe29Sbellard 
296925f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
2970866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
297125f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
297225f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2973a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
2974c896fe29Sbellard                 }
2975c19f47bfSAurelien Jarno             }
297625f49c5fSRichard Henderson 
297725f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
2978c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
297925f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
298025f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
298125f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
298225f49c5fSRichard Henderson                        all regs for the type.  */
298325f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
298425f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
298525f49c5fSRichard Henderson                 }
298625f49c5fSRichard Henderson             }
298725f49c5fSRichard Henderson 
298825f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
298925f49c5fSRichard Henderson             switch (opc) {
299025f49c5fSRichard Henderson             case INDEX_op_mov_i32:
299125f49c5fSRichard Henderson             case INDEX_op_mov_i64:
299225f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
299325f49c5fSRichard Henderson                    have proper constraints.  That said, special case
299425f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
299525f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
299625f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
299725f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
299825f49c5fSRichard Henderson                 }
299925f49c5fSRichard Henderson                 break;
300025f49c5fSRichard Henderson 
300125f49c5fSRichard Henderson             default:
300225f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
300325f49c5fSRichard Henderson                     const TCGArgConstraint *ct = &def->args_ct[i];
300425f49c5fSRichard Henderson                     TCGRegSet set, *pset;
300525f49c5fSRichard Henderson 
300625f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
300725f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
300825f49c5fSRichard Henderson                     set = *pset;
300925f49c5fSRichard Henderson 
30109be0d080SRichard Henderson                     set &= ct->regs;
3011bc2b17e6SRichard Henderson                     if (ct->ialias) {
301231fd884bSRichard Henderson                         set &= output_pref(op, ct->alias_index);
301325f49c5fSRichard Henderson                     }
301425f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
301525f49c5fSRichard Henderson                     if (set == 0) {
30169be0d080SRichard Henderson                         set = ct->regs;
301725f49c5fSRichard Henderson                     }
301825f49c5fSRichard Henderson                     *pset = set;
301925f49c5fSRichard Henderson                 }
302025f49c5fSRichard Henderson                 break;
3021c896fe29Sbellard             }
3022c896fe29Sbellard             break;
3023c896fe29Sbellard         }
3024bee158cbSRichard Henderson         op->life = arg_life;
3025c896fe29Sbellard     }
30261ff0a2c5SEvgeny Voevodin }
3027c896fe29Sbellard 
30285a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
3029b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s)
30305a18407fSRichard Henderson {
30315a18407fSRichard Henderson     int nb_globals = s->nb_globals;
303215fa08f8SRichard Henderson     int nb_temps, i;
30335a18407fSRichard Henderson     bool changes = false;
303415fa08f8SRichard Henderson     TCGOp *op, *op_next;
30355a18407fSRichard Henderson 
30365a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
30375a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
30385a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
30395a18407fSRichard Henderson         if (its->indirect_reg) {
30405a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
30415a18407fSRichard Henderson             dts->type = its->type;
30425a18407fSRichard Henderson             dts->base_type = its->base_type;
3043c7482438SRichard Henderson             dts->kind = TEMP_EBB;
3044b83eabeaSRichard Henderson             its->state_ptr = dts;
3045b83eabeaSRichard Henderson         } else {
3046b83eabeaSRichard Henderson             its->state_ptr = NULL;
30475a18407fSRichard Henderson         }
3048b83eabeaSRichard Henderson         /* All globals begin dead.  */
3049b83eabeaSRichard Henderson         its->state = TS_DEAD;
30505a18407fSRichard Henderson     }
3051b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
3052b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
3053b83eabeaSRichard Henderson         its->state_ptr = NULL;
3054b83eabeaSRichard Henderson         its->state = TS_DEAD;
3055b83eabeaSRichard Henderson     }
30565a18407fSRichard Henderson 
305715fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
30585a18407fSRichard Henderson         TCGOpcode opc = op->opc;
30595a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
30605a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
30615a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
3062b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
30635a18407fSRichard Henderson 
30645a18407fSRichard Henderson         if (opc == INDEX_op_call) {
3065cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
3066cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
306790163900SRichard Henderson             call_flags = tcg_call_flags(op);
30685a18407fSRichard Henderson         } else {
30695a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
30705a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
30715a18407fSRichard Henderson 
30725a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
3073b4cb76e6SRichard Henderson             if (def->flags & TCG_OPF_COND_BRANCH) {
3074b4cb76e6SRichard Henderson                 /* Like reading globals: sync_globals */
3075b4cb76e6SRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
3076b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
30775a18407fSRichard Henderson                 /* Like writing globals: save_globals */
30785a18407fSRichard Henderson                 call_flags = 0;
30795a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
30805a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
30815a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
30825a18407fSRichard Henderson             } else {
30835a18407fSRichard Henderson                 /* No effect on globals.  */
30845a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
30855a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
30865a18407fSRichard Henderson             }
30875a18407fSRichard Henderson         }
30885a18407fSRichard Henderson 
30895a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
30905a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3091b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3092b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
3093b83eabeaSRichard Henderson             if (dir_ts && arg_ts->state == TS_DEAD) {
3094b83eabeaSRichard Henderson                 TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
30955a18407fSRichard Henderson                                   ? INDEX_op_ld_i32
30965a18407fSRichard Henderson                                   : INDEX_op_ld_i64);
3097d4478943SPhilippe Mathieu-Daudé                 TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3);
30985a18407fSRichard Henderson 
3099b83eabeaSRichard Henderson                 lop->args[0] = temp_arg(dir_ts);
3100b83eabeaSRichard Henderson                 lop->args[1] = temp_arg(arg_ts->mem_base);
3101b83eabeaSRichard Henderson                 lop->args[2] = arg_ts->mem_offset;
31025a18407fSRichard Henderson 
31035a18407fSRichard Henderson                 /* Loaded, but synced with memory.  */
3104b83eabeaSRichard Henderson                 arg_ts->state = TS_MEM;
31055a18407fSRichard Henderson             }
31065a18407fSRichard Henderson         }
31075a18407fSRichard Henderson 
31085a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
31095a18407fSRichard Henderson            No action is required except keeping temp_state up to date
31105a18407fSRichard Henderson            so that we reload when needed.  */
31115a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3112b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3113b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
3114b83eabeaSRichard Henderson             if (dir_ts) {
3115b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
31165a18407fSRichard Henderson                 changes = true;
31175a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3118b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
31195a18407fSRichard Henderson                 }
31205a18407fSRichard Henderson             }
31215a18407fSRichard Henderson         }
31225a18407fSRichard Henderson 
31235a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
31245a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
31255a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
31265a18407fSRichard Henderson             /* Nothing to do */
31275a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
31285a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
31295a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
31305a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
3131b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3132b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3133b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
31345a18407fSRichard Henderson             }
31355a18407fSRichard Henderson         } else {
31365a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
31375a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
31385a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
3139b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3140b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3141b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
31425a18407fSRichard Henderson             }
31435a18407fSRichard Henderson         }
31445a18407fSRichard Henderson 
31455a18407fSRichard Henderson         /* Outputs become available.  */
314661f15c48SRichard Henderson         if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) {
314761f15c48SRichard Henderson             arg_ts = arg_temp(op->args[0]);
314861f15c48SRichard Henderson             dir_ts = arg_ts->state_ptr;
314961f15c48SRichard Henderson             if (dir_ts) {
315061f15c48SRichard Henderson                 op->args[0] = temp_arg(dir_ts);
315161f15c48SRichard Henderson                 changes = true;
315261f15c48SRichard Henderson 
315361f15c48SRichard Henderson                 /* The output is now live and modified.  */
315461f15c48SRichard Henderson                 arg_ts->state = 0;
315561f15c48SRichard Henderson 
315661f15c48SRichard Henderson                 if (NEED_SYNC_ARG(0)) {
315761f15c48SRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
315861f15c48SRichard Henderson                                       ? INDEX_op_st_i32
315961f15c48SRichard Henderson                                       : INDEX_op_st_i64);
3160d4478943SPhilippe Mathieu-Daudé                     TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
316161f15c48SRichard Henderson                     TCGTemp *out_ts = dir_ts;
316261f15c48SRichard Henderson 
316361f15c48SRichard Henderson                     if (IS_DEAD_ARG(0)) {
316461f15c48SRichard Henderson                         out_ts = arg_temp(op->args[1]);
316561f15c48SRichard Henderson                         arg_ts->state = TS_DEAD;
316661f15c48SRichard Henderson                         tcg_op_remove(s, op);
316761f15c48SRichard Henderson                     } else {
316861f15c48SRichard Henderson                         arg_ts->state = TS_MEM;
316961f15c48SRichard Henderson                     }
317061f15c48SRichard Henderson 
317161f15c48SRichard Henderson                     sop->args[0] = temp_arg(out_ts);
317261f15c48SRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
317361f15c48SRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
317461f15c48SRichard Henderson                 } else {
317561f15c48SRichard Henderson                     tcg_debug_assert(!IS_DEAD_ARG(0));
317661f15c48SRichard Henderson                 }
317761f15c48SRichard Henderson             }
317861f15c48SRichard Henderson         } else {
31795a18407fSRichard Henderson             for (i = 0; i < nb_oargs; i++) {
3180b83eabeaSRichard Henderson                 arg_ts = arg_temp(op->args[i]);
3181b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3182b83eabeaSRichard Henderson                 if (!dir_ts) {
31835a18407fSRichard Henderson                     continue;
31845a18407fSRichard Henderson                 }
3185b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
31865a18407fSRichard Henderson                 changes = true;
31875a18407fSRichard Henderson 
31885a18407fSRichard Henderson                 /* The output is now live and modified.  */
3189b83eabeaSRichard Henderson                 arg_ts->state = 0;
31905a18407fSRichard Henderson 
31915a18407fSRichard Henderson                 /* Sync outputs upon their last write.  */
31925a18407fSRichard Henderson                 if (NEED_SYNC_ARG(i)) {
3193b83eabeaSRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
31945a18407fSRichard Henderson                                       ? INDEX_op_st_i32
31955a18407fSRichard Henderson                                       : INDEX_op_st_i64);
3196d4478943SPhilippe Mathieu-Daudé                     TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
31975a18407fSRichard Henderson 
3198b83eabeaSRichard Henderson                     sop->args[0] = temp_arg(dir_ts);
3199b83eabeaSRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
3200b83eabeaSRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
32015a18407fSRichard Henderson 
3202b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
32035a18407fSRichard Henderson                 }
32045a18407fSRichard Henderson                 /* Drop outputs that are dead.  */
32055a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3206b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
32075a18407fSRichard Henderson                 }
32085a18407fSRichard Henderson             }
32095a18407fSRichard Henderson         }
321061f15c48SRichard Henderson     }
32115a18407fSRichard Henderson 
32125a18407fSRichard Henderson     return changes;
32135a18407fSRichard Henderson }
32145a18407fSRichard Henderson 
32152272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
3216c896fe29Sbellard {
321731c96417SRichard Henderson     int size = tcg_type_size(ts->type);
321831c96417SRichard Henderson     int align;
321931c96417SRichard Henderson     intptr_t off;
3220c1c09194SRichard Henderson 
3221c1c09194SRichard Henderson     switch (ts->type) {
3222c1c09194SRichard Henderson     case TCG_TYPE_I32:
322331c96417SRichard Henderson         align = 4;
3224c1c09194SRichard Henderson         break;
3225c1c09194SRichard Henderson     case TCG_TYPE_I64:
3226c1c09194SRichard Henderson     case TCG_TYPE_V64:
322731c96417SRichard Henderson         align = 8;
3228c1c09194SRichard Henderson         break;
3229c1c09194SRichard Henderson     case TCG_TYPE_V128:
3230c1c09194SRichard Henderson     case TCG_TYPE_V256:
3231c1c09194SRichard Henderson         /* Note that we do not require aligned storage for V256. */
323231c96417SRichard Henderson         align = 16;
3233c1c09194SRichard Henderson         break;
3234c1c09194SRichard Henderson     default:
3235c1c09194SRichard Henderson         g_assert_not_reached();
3236b591dc59SBlue Swirl     }
3237c1c09194SRichard Henderson 
3238b9537d59SRichard Henderson     /*
3239b9537d59SRichard Henderson      * Assume the stack is sufficiently aligned.
3240b9537d59SRichard Henderson      * This affects e.g. ARM NEON, where we have 8 byte stack alignment
3241b9537d59SRichard Henderson      * and do not require 16 byte vector alignment.  This seems slightly
3242b9537d59SRichard Henderson      * easier than fully parameterizing the above switch statement.
3243b9537d59SRichard Henderson      */
3244b9537d59SRichard Henderson     align = MIN(TCG_TARGET_STACK_ALIGN, align);
3245c1c09194SRichard Henderson     off = ROUND_UP(s->current_frame_offset, align);
3246732d5897SRichard Henderson 
3247732d5897SRichard Henderson     /* If we've exhausted the stack frame, restart with a smaller TB. */
3248732d5897SRichard Henderson     if (off + size > s->frame_end) {
3249732d5897SRichard Henderson         tcg_raise_tb_overflow(s);
3250732d5897SRichard Henderson     }
3251c1c09194SRichard Henderson     s->current_frame_offset = off + size;
3252c1c09194SRichard Henderson 
3253c1c09194SRichard Henderson     ts->mem_offset = off;
32549defd1bdSRichard Henderson #if defined(__sparc__)
32559defd1bdSRichard Henderson     ts->mem_offset += TCG_TARGET_STACK_BIAS;
32569defd1bdSRichard Henderson #endif
3257b3a62939SRichard Henderson     ts->mem_base = s->frame_temp;
3258c896fe29Sbellard     ts->mem_allocated = 1;
3259c896fe29Sbellard }
3260c896fe29Sbellard 
3261098859f1SRichard Henderson /* Assign @reg to @ts, and update reg_to_temp[]. */
3262098859f1SRichard Henderson static void set_temp_val_reg(TCGContext *s, TCGTemp *ts, TCGReg reg)
3263098859f1SRichard Henderson {
3264098859f1SRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
3265098859f1SRichard Henderson         TCGReg old = ts->reg;
3266098859f1SRichard Henderson         tcg_debug_assert(s->reg_to_temp[old] == ts);
3267098859f1SRichard Henderson         if (old == reg) {
3268098859f1SRichard Henderson             return;
3269098859f1SRichard Henderson         }
3270098859f1SRichard Henderson         s->reg_to_temp[old] = NULL;
3271098859f1SRichard Henderson     }
3272098859f1SRichard Henderson     tcg_debug_assert(s->reg_to_temp[reg] == NULL);
3273098859f1SRichard Henderson     s->reg_to_temp[reg] = ts;
3274098859f1SRichard Henderson     ts->val_type = TEMP_VAL_REG;
3275098859f1SRichard Henderson     ts->reg = reg;
3276098859f1SRichard Henderson }
3277098859f1SRichard Henderson 
3278098859f1SRichard Henderson /* Assign a non-register value type to @ts, and update reg_to_temp[]. */
3279098859f1SRichard Henderson static void set_temp_val_nonreg(TCGContext *s, TCGTemp *ts, TCGTempVal type)
3280098859f1SRichard Henderson {
3281098859f1SRichard Henderson     tcg_debug_assert(type != TEMP_VAL_REG);
3282098859f1SRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
3283098859f1SRichard Henderson         TCGReg reg = ts->reg;
3284098859f1SRichard Henderson         tcg_debug_assert(s->reg_to_temp[reg] == ts);
3285098859f1SRichard Henderson         s->reg_to_temp[reg] = NULL;
3286098859f1SRichard Henderson     }
3287098859f1SRichard Henderson     ts->val_type = type;
3288098859f1SRichard Henderson }
3289098859f1SRichard Henderson 
3290b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
3291b3915dbbSRichard Henderson 
329259d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
329359d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
329459d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
3295c896fe29Sbellard {
3296c0522136SRichard Henderson     TCGTempVal new_type;
3297c0522136SRichard Henderson 
3298c0522136SRichard Henderson     switch (ts->kind) {
3299c0522136SRichard Henderson     case TEMP_FIXED:
330059d7c14eSRichard Henderson         return;
3301c0522136SRichard Henderson     case TEMP_GLOBAL:
3302c0522136SRichard Henderson     case TEMP_LOCAL:
3303c0522136SRichard Henderson         new_type = TEMP_VAL_MEM;
3304c0522136SRichard Henderson         break;
3305c0522136SRichard Henderson     case TEMP_NORMAL:
3306c7482438SRichard Henderson     case TEMP_EBB:
3307c0522136SRichard Henderson         new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD;
3308c0522136SRichard Henderson         break;
3309c0522136SRichard Henderson     case TEMP_CONST:
3310c0522136SRichard Henderson         new_type = TEMP_VAL_CONST;
3311c0522136SRichard Henderson         break;
3312c0522136SRichard Henderson     default:
3313c0522136SRichard Henderson         g_assert_not_reached();
331459d7c14eSRichard Henderson     }
3315098859f1SRichard Henderson     set_temp_val_nonreg(s, ts, new_type);
331659d7c14eSRichard Henderson }
3317c896fe29Sbellard 
331859d7c14eSRichard Henderson /* Mark a temporary as dead.  */
331959d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
332059d7c14eSRichard Henderson {
332159d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
332259d7c14eSRichard Henderson }
332359d7c14eSRichard Henderson 
332459d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
332559d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
332659d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
332759d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
332898b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
332998b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
333059d7c14eSRichard Henderson {
3331c0522136SRichard Henderson     if (!temp_readonly(ts) && !ts->mem_coherent) {
33327f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
33332272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
333459d7c14eSRichard Henderson         }
333559d7c14eSRichard Henderson         switch (ts->val_type) {
333659d7c14eSRichard Henderson         case TEMP_VAL_CONST:
333759d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
333859d7c14eSRichard Henderson                require it later in a register, so attempt to store the
333959d7c14eSRichard Henderson                constant to memory directly.  */
334059d7c14eSRichard Henderson             if (free_or_dead
334159d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
334259d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
334359d7c14eSRichard Henderson                 break;
334459d7c14eSRichard Henderson             }
334559d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
334698b4e186SRichard Henderson                       allocated_regs, preferred_regs);
334759d7c14eSRichard Henderson             /* fallthrough */
334859d7c14eSRichard Henderson 
334959d7c14eSRichard Henderson         case TEMP_VAL_REG:
335059d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
335159d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
335259d7c14eSRichard Henderson             break;
335359d7c14eSRichard Henderson 
335459d7c14eSRichard Henderson         case TEMP_VAL_MEM:
335559d7c14eSRichard Henderson             break;
335659d7c14eSRichard Henderson 
335759d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
335859d7c14eSRichard Henderson         default:
335959d7c14eSRichard Henderson             tcg_abort();
3360c896fe29Sbellard         }
33617f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
33627f6ceedfSAurelien Jarno     }
336359d7c14eSRichard Henderson     if (free_or_dead) {
336459d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
336559d7c14eSRichard Henderson     }
336659d7c14eSRichard Henderson }
33677f6ceedfSAurelien Jarno 
33687f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
3369b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
33707f6ceedfSAurelien Jarno {
3371f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
3372f8b2f202SRichard Henderson     if (ts != NULL) {
337398b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
3374c896fe29Sbellard     }
3375c896fe29Sbellard }
3376c896fe29Sbellard 
3377b016486eSRichard Henderson /**
3378b016486eSRichard Henderson  * tcg_reg_alloc:
3379b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
3380b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
3381b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
3382b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
3383b016486eSRichard Henderson  *
3384b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
3385b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
3386b016486eSRichard Henderson  */
3387b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
3388b016486eSRichard Henderson                             TCGRegSet allocated_regs,
3389b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
3390c896fe29Sbellard {
3391b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
3392b016486eSRichard Henderson     TCGRegSet reg_ct[2];
339391478cefSRichard Henderson     const int *order;
3394c896fe29Sbellard 
3395b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
3396b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
3397b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
3398b016486eSRichard Henderson 
3399b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
3400b016486eSRichard Henderson        or if the preference made no difference.  */
3401b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
3402b016486eSRichard Henderson 
340391478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
3404c896fe29Sbellard 
3405b016486eSRichard Henderson     /* Try free registers, preferences first.  */
3406b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3407b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3408b016486eSRichard Henderson 
3409b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3410b016486eSRichard Henderson             /* One register in the set.  */
3411b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3412b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
3413c896fe29Sbellard                 return reg;
3414c896fe29Sbellard             }
3415b016486eSRichard Henderson         } else {
341691478cefSRichard Henderson             for (i = 0; i < n; i++) {
3417b016486eSRichard Henderson                 TCGReg reg = order[i];
3418b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
3419b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
3420b016486eSRichard Henderson                     return reg;
3421b016486eSRichard Henderson                 }
3422b016486eSRichard Henderson             }
3423b016486eSRichard Henderson         }
3424b016486eSRichard Henderson     }
3425b016486eSRichard Henderson 
3426b016486eSRichard Henderson     /* We must spill something.  */
3427b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3428b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3429b016486eSRichard Henderson 
3430b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3431b016486eSRichard Henderson             /* One register in the set.  */
3432b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3433b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
3434c896fe29Sbellard             return reg;
3435b016486eSRichard Henderson         } else {
3436b016486eSRichard Henderson             for (i = 0; i < n; i++) {
3437b016486eSRichard Henderson                 TCGReg reg = order[i];
3438b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
3439b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
3440b016486eSRichard Henderson                     return reg;
3441b016486eSRichard Henderson                 }
3442b016486eSRichard Henderson             }
3443c896fe29Sbellard         }
3444c896fe29Sbellard     }
3445c896fe29Sbellard 
3446c896fe29Sbellard     tcg_abort();
3447c896fe29Sbellard }
3448c896fe29Sbellard 
344929f5e925SRichard Henderson static TCGReg tcg_reg_alloc_pair(TCGContext *s, TCGRegSet required_regs,
345029f5e925SRichard Henderson                                  TCGRegSet allocated_regs,
345129f5e925SRichard Henderson                                  TCGRegSet preferred_regs, bool rev)
345229f5e925SRichard Henderson {
345329f5e925SRichard Henderson     int i, j, k, fmin, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
345429f5e925SRichard Henderson     TCGRegSet reg_ct[2];
345529f5e925SRichard Henderson     const int *order;
345629f5e925SRichard Henderson 
345729f5e925SRichard Henderson     /* Ensure that if I is not in allocated_regs, I+1 is not either. */
345829f5e925SRichard Henderson     reg_ct[1] = required_regs & ~(allocated_regs | (allocated_regs >> 1));
345929f5e925SRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
346029f5e925SRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
346129f5e925SRichard Henderson 
346229f5e925SRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
346329f5e925SRichard Henderson 
346429f5e925SRichard Henderson     /*
346529f5e925SRichard Henderson      * Skip the preferred_regs option if it cannot be satisfied,
346629f5e925SRichard Henderson      * or if the preference made no difference.
346729f5e925SRichard Henderson      */
346829f5e925SRichard Henderson     k = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
346929f5e925SRichard Henderson 
347029f5e925SRichard Henderson     /*
347129f5e925SRichard Henderson      * Minimize the number of flushes by looking for 2 free registers first,
347229f5e925SRichard Henderson      * then a single flush, then two flushes.
347329f5e925SRichard Henderson      */
347429f5e925SRichard Henderson     for (fmin = 2; fmin >= 0; fmin--) {
347529f5e925SRichard Henderson         for (j = k; j < 2; j++) {
347629f5e925SRichard Henderson             TCGRegSet set = reg_ct[j];
347729f5e925SRichard Henderson 
347829f5e925SRichard Henderson             for (i = 0; i < n; i++) {
347929f5e925SRichard Henderson                 TCGReg reg = order[i];
348029f5e925SRichard Henderson 
348129f5e925SRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
348229f5e925SRichard Henderson                     int f = !s->reg_to_temp[reg] + !s->reg_to_temp[reg + 1];
348329f5e925SRichard Henderson                     if (f >= fmin) {
348429f5e925SRichard Henderson                         tcg_reg_free(s, reg, allocated_regs);
348529f5e925SRichard Henderson                         tcg_reg_free(s, reg + 1, allocated_regs);
348629f5e925SRichard Henderson                         return reg;
348729f5e925SRichard Henderson                     }
348829f5e925SRichard Henderson                 }
348929f5e925SRichard Henderson             }
349029f5e925SRichard Henderson         }
349129f5e925SRichard Henderson     }
349229f5e925SRichard Henderson     tcg_abort();
349329f5e925SRichard Henderson }
349429f5e925SRichard Henderson 
349540ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
349640ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
349740ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
3498b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
349940ae5c62SRichard Henderson {
350040ae5c62SRichard Henderson     TCGReg reg;
350140ae5c62SRichard Henderson 
350240ae5c62SRichard Henderson     switch (ts->val_type) {
350340ae5c62SRichard Henderson     case TEMP_VAL_REG:
350440ae5c62SRichard Henderson         return;
350540ae5c62SRichard Henderson     case TEMP_VAL_CONST:
3506b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3507b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
35080a6a8bc8SRichard Henderson         if (ts->type <= TCG_TYPE_I64) {
350940ae5c62SRichard Henderson             tcg_out_movi(s, ts->type, reg, ts->val);
35100a6a8bc8SRichard Henderson         } else {
35114e186175SRichard Henderson             uint64_t val = ts->val;
35124e186175SRichard Henderson             MemOp vece = MO_64;
35134e186175SRichard Henderson 
35144e186175SRichard Henderson             /*
35154e186175SRichard Henderson              * Find the minimal vector element that matches the constant.
35164e186175SRichard Henderson              * The targets will, in general, have to do this search anyway,
35174e186175SRichard Henderson              * do this generically.
35184e186175SRichard Henderson              */
35194e186175SRichard Henderson             if (val == dup_const(MO_8, val)) {
35204e186175SRichard Henderson                 vece = MO_8;
35214e186175SRichard Henderson             } else if (val == dup_const(MO_16, val)) {
35224e186175SRichard Henderson                 vece = MO_16;
35230b4286ddSRichard Henderson             } else if (val == dup_const(MO_32, val)) {
35244e186175SRichard Henderson                 vece = MO_32;
35254e186175SRichard Henderson             }
35264e186175SRichard Henderson 
35274e186175SRichard Henderson             tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val);
35280a6a8bc8SRichard Henderson         }
352940ae5c62SRichard Henderson         ts->mem_coherent = 0;
353040ae5c62SRichard Henderson         break;
353140ae5c62SRichard Henderson     case TEMP_VAL_MEM:
3532b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3533b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
353440ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
353540ae5c62SRichard Henderson         ts->mem_coherent = 1;
353640ae5c62SRichard Henderson         break;
353740ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
353840ae5c62SRichard Henderson     default:
353940ae5c62SRichard Henderson         tcg_abort();
354040ae5c62SRichard Henderson     }
3541098859f1SRichard Henderson     set_temp_val_reg(s, ts, reg);
354240ae5c62SRichard Henderson }
354340ae5c62SRichard Henderson 
354459d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
3545e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
354659d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
35471ad80729SAurelien Jarno {
35482c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
3549eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
3550e01fa97dSRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts));
35511ad80729SAurelien Jarno }
35521ad80729SAurelien Jarno 
35539814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
3554641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
3555641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
3556641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
3557641d5fbeSbellard {
3558ac3b8891SRichard Henderson     int i, n;
3559641d5fbeSbellard 
3560ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
3561b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
3562641d5fbeSbellard     }
3563e5097dc8Sbellard }
3564e5097dc8Sbellard 
35653d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
35663d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
35673d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
35683d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
35693d5c5f87SAurelien Jarno {
3570ac3b8891SRichard Henderson     int i, n;
35713d5c5f87SAurelien Jarno 
3572ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
357312b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
357412b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
3575ee17db83SRichard Henderson                          || ts->kind == TEMP_FIXED
357612b9b11aSRichard Henderson                          || ts->mem_coherent);
35773d5c5f87SAurelien Jarno     }
35783d5c5f87SAurelien Jarno }
35793d5c5f87SAurelien Jarno 
3580e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
3581e8996ee0Sbellard    all globals are stored at their canonical location. */
3582e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
3583e5097dc8Sbellard {
3584e5097dc8Sbellard     int i;
3585e5097dc8Sbellard 
3586c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
3587b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
3588c0522136SRichard Henderson 
3589c0522136SRichard Henderson         switch (ts->kind) {
3590c0522136SRichard Henderson         case TEMP_LOCAL:
3591b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
3592c0522136SRichard Henderson             break;
3593c0522136SRichard Henderson         case TEMP_NORMAL:
3594c7482438SRichard Henderson         case TEMP_EBB:
35952c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
3596eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
3597eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3598c0522136SRichard Henderson             break;
3599c0522136SRichard Henderson         case TEMP_CONST:
3600c0522136SRichard Henderson             /* Similarly, we should have freed any allocated register. */
3601c0522136SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_CONST);
3602c0522136SRichard Henderson             break;
3603c0522136SRichard Henderson         default:
3604c0522136SRichard Henderson             g_assert_not_reached();
3605c896fe29Sbellard         }
3606641d5fbeSbellard     }
3607e8996ee0Sbellard 
3608e8996ee0Sbellard     save_globals(s, allocated_regs);
3609c896fe29Sbellard }
3610c896fe29Sbellard 
3611bab1671fSRichard Henderson /*
3612c7482438SRichard Henderson  * At a conditional branch, we assume all temporaries are dead unless
3613c7482438SRichard Henderson  * explicitly live-across-conditional-branch; all globals and local
3614c7482438SRichard Henderson  * temps are synced to their location.
3615b4cb76e6SRichard Henderson  */
3616b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
3617b4cb76e6SRichard Henderson {
3618b4cb76e6SRichard Henderson     sync_globals(s, allocated_regs);
3619b4cb76e6SRichard Henderson 
3620b4cb76e6SRichard Henderson     for (int i = s->nb_globals; i < s->nb_temps; i++) {
3621b4cb76e6SRichard Henderson         TCGTemp *ts = &s->temps[i];
3622b4cb76e6SRichard Henderson         /*
3623b4cb76e6SRichard Henderson          * The liveness analysis already ensures that temps are dead.
3624b4cb76e6SRichard Henderson          * Keep tcg_debug_asserts for safety.
3625b4cb76e6SRichard Henderson          */
3626c0522136SRichard Henderson         switch (ts->kind) {
3627c0522136SRichard Henderson         case TEMP_LOCAL:
3628b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
3629c0522136SRichard Henderson             break;
3630c0522136SRichard Henderson         case TEMP_NORMAL:
3631b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3632c0522136SRichard Henderson             break;
3633c7482438SRichard Henderson         case TEMP_EBB:
3634c0522136SRichard Henderson         case TEMP_CONST:
3635c0522136SRichard Henderson             break;
3636c0522136SRichard Henderson         default:
3637c0522136SRichard Henderson             g_assert_not_reached();
3638b4cb76e6SRichard Henderson         }
3639b4cb76e6SRichard Henderson     }
3640b4cb76e6SRichard Henderson }
3641b4cb76e6SRichard Henderson 
3642b4cb76e6SRichard Henderson /*
3643c58f4c97SRichard Henderson  * Specialized code generation for INDEX_op_mov_* with a constant.
3644bab1671fSRichard Henderson  */
36450fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
3646ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
3647ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
3648e8996ee0Sbellard {
3649d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3650e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
365159d7c14eSRichard Henderson 
365259d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
3653098859f1SRichard Henderson     set_temp_val_nonreg(s, ots, TEMP_VAL_CONST);
3654e8996ee0Sbellard     ots->val = val;
365559d7c14eSRichard Henderson     ots->mem_coherent = 0;
3656ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
3657ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
365859d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
3659f8bf00f1SRichard Henderson         temp_dead(s, ots);
36604c4e1ab2SAurelien Jarno     }
3661e8996ee0Sbellard }
3662e8996ee0Sbellard 
3663bab1671fSRichard Henderson /*
3664bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
3665bab1671fSRichard Henderson  */
3666dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
3667c896fe29Sbellard {
3668dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
366969e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
3670c896fe29Sbellard     TCGTemp *ts, *ots;
3671450445d5SRichard Henderson     TCGType otype, itype;
3672098859f1SRichard Henderson     TCGReg oreg, ireg;
3673c896fe29Sbellard 
3674d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
367531fd884bSRichard Henderson     preferred_regs = output_pref(op, 0);
367643439139SRichard Henderson     ots = arg_temp(op->args[0]);
367743439139SRichard Henderson     ts = arg_temp(op->args[1]);
3678450445d5SRichard Henderson 
3679d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3680e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
3681d63e3b6eSRichard Henderson 
3682450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
3683450445d5SRichard Henderson     otype = ots->type;
3684450445d5SRichard Henderson     itype = ts->type;
3685c896fe29Sbellard 
36860fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
36870fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
36880fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
36890fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
36900fe4fca4SPaolo Bonzini             temp_dead(s, ts);
36910fe4fca4SPaolo Bonzini         }
369269e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
36930fe4fca4SPaolo Bonzini         return;
36940fe4fca4SPaolo Bonzini     }
36950fe4fca4SPaolo Bonzini 
36960fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
36970fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
36980fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
36990fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
37000fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
370169e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
370269e3706dSRichard Henderson                   allocated_regs, preferred_regs);
3703c29c1d7eSAurelien Jarno     }
37040fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
3705098859f1SRichard Henderson     ireg = ts->reg;
3706098859f1SRichard Henderson 
3707d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
3708c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
3709c29c1d7eSAurelien Jarno            liveness analysis disabled). */
3710eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
3711c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
37122272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
3713c29c1d7eSAurelien Jarno         }
3714098859f1SRichard Henderson         tcg_out_st(s, otype, ireg, ots->mem_base->reg, ots->mem_offset);
3715c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
3716f8bf00f1SRichard Henderson             temp_dead(s, ts);
3717c29c1d7eSAurelien Jarno         }
3718f8bf00f1SRichard Henderson         temp_dead(s, ots);
3719098859f1SRichard Henderson         return;
3720098859f1SRichard Henderson     }
3721098859f1SRichard Henderson 
3722ee17db83SRichard Henderson     if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) {
3723098859f1SRichard Henderson         /*
3724098859f1SRichard Henderson          * The mov can be suppressed.  Kill input first, so that it
3725098859f1SRichard Henderson          * is unlinked from reg_to_temp, then set the output to the
3726098859f1SRichard Henderson          * reg that we saved from the input.
3727098859f1SRichard Henderson          */
3728f8bf00f1SRichard Henderson         temp_dead(s, ts);
3729098859f1SRichard Henderson         oreg = ireg;
3730c29c1d7eSAurelien Jarno     } else {
3731098859f1SRichard Henderson         if (ots->val_type == TEMP_VAL_REG) {
3732098859f1SRichard Henderson             oreg = ots->reg;
3733098859f1SRichard Henderson         } else {
3734098859f1SRichard Henderson             /* Make sure to not spill the input register during allocation. */
3735098859f1SRichard Henderson             oreg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
3736098859f1SRichard Henderson                                  allocated_regs | ((TCGRegSet)1 << ireg),
3737098859f1SRichard Henderson                                  preferred_regs, ots->indirect_base);
3738c29c1d7eSAurelien Jarno         }
3739098859f1SRichard Henderson         if (!tcg_out_mov(s, otype, oreg, ireg)) {
3740240c08d0SRichard Henderson             /*
3741240c08d0SRichard Henderson              * Cross register class move not supported.
3742240c08d0SRichard Henderson              * Store the source register into the destination slot
3743240c08d0SRichard Henderson              * and leave the destination temp as TEMP_VAL_MEM.
3744240c08d0SRichard Henderson              */
3745e01fa97dSRichard Henderson             assert(!temp_readonly(ots));
3746240c08d0SRichard Henderson             if (!ts->mem_allocated) {
3747240c08d0SRichard Henderson                 temp_allocate_frame(s, ots);
3748240c08d0SRichard Henderson             }
3749098859f1SRichard Henderson             tcg_out_st(s, ts->type, ireg, ots->mem_base->reg, ots->mem_offset);
3750098859f1SRichard Henderson             set_temp_val_nonreg(s, ts, TEMP_VAL_MEM);
3751240c08d0SRichard Henderson             ots->mem_coherent = 1;
3752240c08d0SRichard Henderson             return;
375378113e83SRichard Henderson         }
3754c29c1d7eSAurelien Jarno     }
3755098859f1SRichard Henderson     set_temp_val_reg(s, ots, oreg);
3756c896fe29Sbellard     ots->mem_coherent = 0;
3757098859f1SRichard Henderson 
3758ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
375998b4e186SRichard Henderson         temp_sync(s, ots, allocated_regs, 0, 0);
3760c29c1d7eSAurelien Jarno     }
3761ec7a869dSAurelien Jarno }
3762c896fe29Sbellard 
3763bab1671fSRichard Henderson /*
3764bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
3765bab1671fSRichard Henderson  */
3766bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
3767bab1671fSRichard Henderson {
3768bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
3769bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
3770bab1671fSRichard Henderson     TCGTemp *its, *ots;
3771bab1671fSRichard Henderson     TCGType itype, vtype;
3772bab1671fSRichard Henderson     unsigned vece;
377331c96417SRichard Henderson     int lowpart_ofs;
3774bab1671fSRichard Henderson     bool ok;
3775bab1671fSRichard Henderson 
3776bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
3777bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
3778bab1671fSRichard Henderson 
3779bab1671fSRichard Henderson     /* ENV should not be modified.  */
3780e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
3781bab1671fSRichard Henderson 
3782bab1671fSRichard Henderson     itype = its->type;
3783bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
3784bab1671fSRichard Henderson     vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
3785bab1671fSRichard Henderson 
3786bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
3787bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
3788bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
3789bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
3790bab1671fSRichard Henderson             temp_dead(s, its);
3791bab1671fSRichard Henderson         }
379231fd884bSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, output_pref(op, 0));
3793bab1671fSRichard Henderson         return;
3794bab1671fSRichard Henderson     }
3795bab1671fSRichard Henderson 
37969be0d080SRichard Henderson     dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
37979be0d080SRichard Henderson     dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs;
3798bab1671fSRichard Henderson 
3799bab1671fSRichard Henderson     /* Allocate the output register now.  */
3800bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
3801bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
3802098859f1SRichard Henderson         TCGReg oreg;
3803bab1671fSRichard Henderson 
3804bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
3805bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
3806bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
3807bab1671fSRichard Henderson         }
3808098859f1SRichard Henderson         oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
380931fd884bSRichard Henderson                              output_pref(op, 0), ots->indirect_base);
3810098859f1SRichard Henderson         set_temp_val_reg(s, ots, oreg);
3811bab1671fSRichard Henderson     }
3812bab1671fSRichard Henderson 
3813bab1671fSRichard Henderson     switch (its->val_type) {
3814bab1671fSRichard Henderson     case TEMP_VAL_REG:
3815bab1671fSRichard Henderson         /*
3816bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
3817bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
3818bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
3819bab1671fSRichard Henderson          */
3820bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
3821bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
3822bab1671fSRichard Henderson                 goto done;
3823bab1671fSRichard Henderson             }
3824bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
3825bab1671fSRichard Henderson         }
3826bab1671fSRichard Henderson         if (!its->mem_coherent) {
3827bab1671fSRichard Henderson             /*
3828bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
3829bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
3830bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
3831bab1671fSRichard Henderson              */
3832bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
3833bab1671fSRichard Henderson                 break;
3834bab1671fSRichard Henderson             }
3835bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
3836bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
3837bab1671fSRichard Henderson         }
3838bab1671fSRichard Henderson         /* fall through */
3839bab1671fSRichard Henderson 
3840bab1671fSRichard Henderson     case TEMP_VAL_MEM:
384131c96417SRichard Henderson         lowpart_ofs = 0;
384231c96417SRichard Henderson         if (HOST_BIG_ENDIAN) {
384331c96417SRichard Henderson             lowpart_ofs = tcg_type_size(itype) - (1 << vece);
384431c96417SRichard Henderson         }
3845d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
384631c96417SRichard Henderson                              its->mem_offset + lowpart_ofs)) {
3847d6ecb4a9SRichard Henderson             goto done;
3848d6ecb4a9SRichard Henderson         }
3849098859f1SRichard Henderson         /* Load the input into the destination vector register. */
3850bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
3851bab1671fSRichard Henderson         break;
3852bab1671fSRichard Henderson 
3853bab1671fSRichard Henderson     default:
3854bab1671fSRichard Henderson         g_assert_not_reached();
3855bab1671fSRichard Henderson     }
3856bab1671fSRichard Henderson 
3857bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
3858bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
3859bab1671fSRichard Henderson     tcg_debug_assert(ok);
3860bab1671fSRichard Henderson 
3861bab1671fSRichard Henderson  done:
386236f5539cSRichard Henderson     ots->mem_coherent = 0;
3863bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
3864bab1671fSRichard Henderson         temp_dead(s, its);
3865bab1671fSRichard Henderson     }
3866bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
3867bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
3868bab1671fSRichard Henderson     }
3869bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
3870bab1671fSRichard Henderson         temp_dead(s, ots);
3871bab1671fSRichard Henderson     }
3872bab1671fSRichard Henderson }
3873bab1671fSRichard Henderson 
3874dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
3875c896fe29Sbellard {
3876dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3877dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
387882790a87SRichard Henderson     TCGRegSet i_allocated_regs;
387982790a87SRichard Henderson     TCGRegSet o_allocated_regs;
3880b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
3881b6638662SRichard Henderson     TCGReg reg;
3882c896fe29Sbellard     TCGArg arg;
3883c896fe29Sbellard     const TCGArgConstraint *arg_ct;
3884c896fe29Sbellard     TCGTemp *ts;
3885c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
3886c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
3887c896fe29Sbellard 
3888c896fe29Sbellard     nb_oargs = def->nb_oargs;
3889c896fe29Sbellard     nb_iargs = def->nb_iargs;
3890c896fe29Sbellard 
3891c896fe29Sbellard     /* copy constants */
3892c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
3893dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
3894c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
3895c896fe29Sbellard 
3896d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
3897d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
389882790a87SRichard Henderson 
3899c896fe29Sbellard     /* satisfy input constraints */
3900c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
390129f5e925SRichard Henderson         TCGRegSet i_preferred_regs, i_required_regs;
390229f5e925SRichard Henderson         bool allocate_new_reg, copyto_new_reg;
390329f5e925SRichard Henderson         TCGTemp *ts2;
390429f5e925SRichard Henderson         int i1, i2;
3905d62816f2SRichard Henderson 
390666792f90SRichard Henderson         i = def->args_ct[nb_oargs + k].sort_index;
3907dd186292SRichard Henderson         arg = op->args[i];
3908c896fe29Sbellard         arg_ct = &def->args_ct[i];
390943439139SRichard Henderson         ts = arg_temp(arg);
391040ae5c62SRichard Henderson 
391140ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
3912a4fbbd77SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct->ct)) {
3913c896fe29Sbellard             /* constant is OK for instruction */
3914c896fe29Sbellard             const_args[i] = 1;
3915c896fe29Sbellard             new_args[i] = ts->val;
3916d62816f2SRichard Henderson             continue;
3917c896fe29Sbellard         }
391840ae5c62SRichard Henderson 
39191c1824dcSRichard Henderson         reg = ts->reg;
39201c1824dcSRichard Henderson         i_preferred_regs = 0;
392129f5e925SRichard Henderson         i_required_regs = arg_ct->regs;
39221c1824dcSRichard Henderson         allocate_new_reg = false;
392329f5e925SRichard Henderson         copyto_new_reg = false;
39241c1824dcSRichard Henderson 
392529f5e925SRichard Henderson         switch (arg_ct->pair) {
392629f5e925SRichard Henderson         case 0: /* not paired */
3927bc2b17e6SRichard Henderson             if (arg_ct->ialias) {
392831fd884bSRichard Henderson                 i_preferred_regs = output_pref(op, arg_ct->alias_index);
3929c0522136SRichard Henderson 
3930c0522136SRichard Henderson                 /*
3931c0522136SRichard Henderson                  * If the input is readonly, then it cannot also be an
3932c0522136SRichard Henderson                  * output and aliased to itself.  If the input is not
3933c0522136SRichard Henderson                  * dead after the instruction, we must allocate a new
3934c0522136SRichard Henderson                  * register and move it.
3935c0522136SRichard Henderson                  */
3936c0522136SRichard Henderson                 if (temp_readonly(ts) || !IS_DEAD_ARG(i)) {
39371c1824dcSRichard Henderson                     allocate_new_reg = true;
39381c1824dcSRichard Henderson                 } else if (ts->val_type == TEMP_VAL_REG) {
3939c0522136SRichard Henderson                     /*
39401c1824dcSRichard Henderson                      * Check if the current register has already been
39411c1824dcSRichard Henderson                      * allocated for another input.
3942c0522136SRichard Henderson                      */
394329f5e925SRichard Henderson                     allocate_new_reg =
394429f5e925SRichard Henderson                         tcg_regset_test_reg(i_allocated_regs, reg);
39457e1df267SAurelien Jarno                 }
39467e1df267SAurelien Jarno             }
39471c1824dcSRichard Henderson             if (!allocate_new_reg) {
394829f5e925SRichard Henderson                 temp_load(s, ts, i_required_regs, i_allocated_regs,
394929f5e925SRichard Henderson                           i_preferred_regs);
3950c896fe29Sbellard                 reg = ts->reg;
395129f5e925SRichard Henderson                 allocate_new_reg = !tcg_regset_test_reg(i_required_regs, reg);
39521c1824dcSRichard Henderson             }
39531c1824dcSRichard Henderson             if (allocate_new_reg) {
3954c0522136SRichard Henderson                 /*
3955c0522136SRichard Henderson                  * Allocate a new register matching the constraint
3956c0522136SRichard Henderson                  * and move the temporary register into it.
3957c0522136SRichard Henderson                  */
3958d62816f2SRichard Henderson                 temp_load(s, ts, tcg_target_available_regs[ts->type],
3959d62816f2SRichard Henderson                           i_allocated_regs, 0);
396029f5e925SRichard Henderson                 reg = tcg_reg_alloc(s, i_required_regs, i_allocated_regs,
39611c1824dcSRichard Henderson                                     i_preferred_regs, ts->indirect_base);
396229f5e925SRichard Henderson                 copyto_new_reg = true;
396329f5e925SRichard Henderson             }
396429f5e925SRichard Henderson             break;
396529f5e925SRichard Henderson 
396629f5e925SRichard Henderson         case 1:
396729f5e925SRichard Henderson             /* First of an input pair; if i1 == i2, the second is an output. */
396829f5e925SRichard Henderson             i1 = i;
396929f5e925SRichard Henderson             i2 = arg_ct->pair_index;
397029f5e925SRichard Henderson             ts2 = i1 != i2 ? arg_temp(op->args[i2]) : NULL;
397129f5e925SRichard Henderson 
397229f5e925SRichard Henderson             /*
397329f5e925SRichard Henderson              * It is easier to default to allocating a new pair
397429f5e925SRichard Henderson              * and to identify a few cases where it's not required.
397529f5e925SRichard Henderson              */
397629f5e925SRichard Henderson             if (arg_ct->ialias) {
397731fd884bSRichard Henderson                 i_preferred_regs = output_pref(op, arg_ct->alias_index);
397829f5e925SRichard Henderson                 if (IS_DEAD_ARG(i1) &&
397929f5e925SRichard Henderson                     IS_DEAD_ARG(i2) &&
398029f5e925SRichard Henderson                     !temp_readonly(ts) &&
398129f5e925SRichard Henderson                     ts->val_type == TEMP_VAL_REG &&
398229f5e925SRichard Henderson                     ts->reg < TCG_TARGET_NB_REGS - 1 &&
398329f5e925SRichard Henderson                     tcg_regset_test_reg(i_required_regs, reg) &&
398429f5e925SRichard Henderson                     !tcg_regset_test_reg(i_allocated_regs, reg) &&
398529f5e925SRichard Henderson                     !tcg_regset_test_reg(i_allocated_regs, reg + 1) &&
398629f5e925SRichard Henderson                     (ts2
398729f5e925SRichard Henderson                      ? ts2->val_type == TEMP_VAL_REG &&
398829f5e925SRichard Henderson                        ts2->reg == reg + 1 &&
398929f5e925SRichard Henderson                        !temp_readonly(ts2)
399029f5e925SRichard Henderson                      : s->reg_to_temp[reg + 1] == NULL)) {
399129f5e925SRichard Henderson                     break;
399229f5e925SRichard Henderson                 }
399329f5e925SRichard Henderson             } else {
399429f5e925SRichard Henderson                 /* Without aliasing, the pair must also be an input. */
399529f5e925SRichard Henderson                 tcg_debug_assert(ts2);
399629f5e925SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG &&
399729f5e925SRichard Henderson                     ts2->val_type == TEMP_VAL_REG &&
399829f5e925SRichard Henderson                     ts2->reg == reg + 1 &&
399929f5e925SRichard Henderson                     tcg_regset_test_reg(i_required_regs, reg)) {
400029f5e925SRichard Henderson                     break;
400129f5e925SRichard Henderson                 }
400229f5e925SRichard Henderson             }
400329f5e925SRichard Henderson             reg = tcg_reg_alloc_pair(s, i_required_regs, i_allocated_regs,
400429f5e925SRichard Henderson                                      0, ts->indirect_base);
400529f5e925SRichard Henderson             goto do_pair;
400629f5e925SRichard Henderson 
400729f5e925SRichard Henderson         case 2: /* pair second */
400829f5e925SRichard Henderson             reg = new_args[arg_ct->pair_index] + 1;
400929f5e925SRichard Henderson             goto do_pair;
401029f5e925SRichard Henderson 
401129f5e925SRichard Henderson         case 3: /* ialias with second output, no first input */
401229f5e925SRichard Henderson             tcg_debug_assert(arg_ct->ialias);
401331fd884bSRichard Henderson             i_preferred_regs = output_pref(op, arg_ct->alias_index);
401429f5e925SRichard Henderson 
401529f5e925SRichard Henderson             if (IS_DEAD_ARG(i) &&
401629f5e925SRichard Henderson                 !temp_readonly(ts) &&
401729f5e925SRichard Henderson                 ts->val_type == TEMP_VAL_REG &&
401829f5e925SRichard Henderson                 reg > 0 &&
401929f5e925SRichard Henderson                 s->reg_to_temp[reg - 1] == NULL &&
402029f5e925SRichard Henderson                 tcg_regset_test_reg(i_required_regs, reg) &&
402129f5e925SRichard Henderson                 !tcg_regset_test_reg(i_allocated_regs, reg) &&
402229f5e925SRichard Henderson                 !tcg_regset_test_reg(i_allocated_regs, reg - 1)) {
402329f5e925SRichard Henderson                 tcg_regset_set_reg(i_allocated_regs, reg - 1);
402429f5e925SRichard Henderson                 break;
402529f5e925SRichard Henderson             }
402629f5e925SRichard Henderson             reg = tcg_reg_alloc_pair(s, i_required_regs >> 1,
402729f5e925SRichard Henderson                                      i_allocated_regs, 0,
402829f5e925SRichard Henderson                                      ts->indirect_base);
402929f5e925SRichard Henderson             tcg_regset_set_reg(i_allocated_regs, reg);
403029f5e925SRichard Henderson             reg += 1;
403129f5e925SRichard Henderson             goto do_pair;
403229f5e925SRichard Henderson 
403329f5e925SRichard Henderson         do_pair:
403429f5e925SRichard Henderson             /*
403529f5e925SRichard Henderson              * If an aliased input is not dead after the instruction,
403629f5e925SRichard Henderson              * we must allocate a new register and move it.
403729f5e925SRichard Henderson              */
403829f5e925SRichard Henderson             if (arg_ct->ialias && (!IS_DEAD_ARG(i) || temp_readonly(ts))) {
403929f5e925SRichard Henderson                 TCGRegSet t_allocated_regs = i_allocated_regs;
404029f5e925SRichard Henderson 
404129f5e925SRichard Henderson                 /*
404229f5e925SRichard Henderson                  * Because of the alias, and the continued life, make sure
404329f5e925SRichard Henderson                  * that the temp is somewhere *other* than the reg pair,
404429f5e925SRichard Henderson                  * and we get a copy in reg.
404529f5e925SRichard Henderson                  */
404629f5e925SRichard Henderson                 tcg_regset_set_reg(t_allocated_regs, reg);
404729f5e925SRichard Henderson                 tcg_regset_set_reg(t_allocated_regs, reg + 1);
404829f5e925SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG && ts->reg == reg) {
404929f5e925SRichard Henderson                     /* If ts was already in reg, copy it somewhere else. */
405029f5e925SRichard Henderson                     TCGReg nr;
405129f5e925SRichard Henderson                     bool ok;
405229f5e925SRichard Henderson 
405329f5e925SRichard Henderson                     tcg_debug_assert(ts->kind != TEMP_FIXED);
405429f5e925SRichard Henderson                     nr = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
405529f5e925SRichard Henderson                                        t_allocated_regs, 0, ts->indirect_base);
405629f5e925SRichard Henderson                     ok = tcg_out_mov(s, ts->type, nr, reg);
405729f5e925SRichard Henderson                     tcg_debug_assert(ok);
405829f5e925SRichard Henderson 
405929f5e925SRichard Henderson                     set_temp_val_reg(s, ts, nr);
406029f5e925SRichard Henderson                 } else {
406129f5e925SRichard Henderson                     temp_load(s, ts, tcg_target_available_regs[ts->type],
406229f5e925SRichard Henderson                               t_allocated_regs, 0);
406329f5e925SRichard Henderson                     copyto_new_reg = true;
406429f5e925SRichard Henderson                 }
406529f5e925SRichard Henderson             } else {
406629f5e925SRichard Henderson                 /* Preferably allocate to reg, otherwise copy. */
406729f5e925SRichard Henderson                 i_required_regs = (TCGRegSet)1 << reg;
406829f5e925SRichard Henderson                 temp_load(s, ts, i_required_regs, i_allocated_regs,
406929f5e925SRichard Henderson                           i_preferred_regs);
407029f5e925SRichard Henderson                 copyto_new_reg = ts->reg != reg;
407129f5e925SRichard Henderson             }
407229f5e925SRichard Henderson             break;
407329f5e925SRichard Henderson 
407429f5e925SRichard Henderson         default:
407529f5e925SRichard Henderson             g_assert_not_reached();
407629f5e925SRichard Henderson         }
407729f5e925SRichard Henderson 
407829f5e925SRichard Henderson         if (copyto_new_reg) {
407978113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4080240c08d0SRichard Henderson                 /*
4081240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
4082240c08d0SRichard Henderson                  * temp back to its slot and load from there.
4083240c08d0SRichard Henderson                  */
4084240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
4085240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
4086240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
408778113e83SRichard Henderson             }
4088c896fe29Sbellard         }
4089c896fe29Sbellard         new_args[i] = reg;
4090c896fe29Sbellard         const_args[i] = 0;
409182790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
4092c896fe29Sbellard     }
4093c896fe29Sbellard 
4094c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
4095866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
4096866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
409743439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4098c896fe29Sbellard         }
4099c896fe29Sbellard     }
4100c896fe29Sbellard 
4101b4cb76e6SRichard Henderson     if (def->flags & TCG_OPF_COND_BRANCH) {
4102b4cb76e6SRichard Henderson         tcg_reg_alloc_cbranch(s, i_allocated_regs);
4103b4cb76e6SRichard Henderson     } else if (def->flags & TCG_OPF_BB_END) {
410482790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
4105a52ad07eSAurelien Jarno     } else {
4106c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
4107b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
4108c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4109c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
411082790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
4111c896fe29Sbellard                 }
4112c896fe29Sbellard             }
41133d5c5f87SAurelien Jarno         }
41143d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
41153d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
41163d5c5f87SAurelien Jarno                an exception. */
411782790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
4118c896fe29Sbellard         }
4119c896fe29Sbellard 
4120c896fe29Sbellard         /* satisfy the output constraints */
4121c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
412266792f90SRichard Henderson             i = def->args_ct[k].sort_index;
4123dd186292SRichard Henderson             arg = op->args[i];
4124c896fe29Sbellard             arg_ct = &def->args_ct[i];
412543439139SRichard Henderson             ts = arg_temp(arg);
4126d63e3b6eSRichard Henderson 
4127d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
4128e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
4129d63e3b6eSRichard Henderson 
413029f5e925SRichard Henderson             switch (arg_ct->pair) {
413129f5e925SRichard Henderson             case 0: /* not paired */
4132bc2b17e6SRichard Henderson                 if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
41335ff9d6a4Sbellard                     reg = new_args[arg_ct->alias_index];
4134bc2b17e6SRichard Henderson                 } else if (arg_ct->newreg) {
41359be0d080SRichard Henderson                     reg = tcg_reg_alloc(s, arg_ct->regs,
413682790a87SRichard Henderson                                         i_allocated_regs | o_allocated_regs,
413731fd884bSRichard Henderson                                         output_pref(op, k), ts->indirect_base);
4138c896fe29Sbellard                 } else {
41399be0d080SRichard Henderson                     reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
414031fd884bSRichard Henderson                                         output_pref(op, k), ts->indirect_base);
4141c896fe29Sbellard                 }
414229f5e925SRichard Henderson                 break;
414329f5e925SRichard Henderson 
414429f5e925SRichard Henderson             case 1: /* first of pair */
414529f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
414629f5e925SRichard Henderson                 if (arg_ct->oalias) {
414729f5e925SRichard Henderson                     reg = new_args[arg_ct->alias_index];
414829f5e925SRichard Henderson                     break;
414929f5e925SRichard Henderson                 }
415029f5e925SRichard Henderson                 reg = tcg_reg_alloc_pair(s, arg_ct->regs, o_allocated_regs,
415131fd884bSRichard Henderson                                          output_pref(op, k), ts->indirect_base);
415229f5e925SRichard Henderson                 break;
415329f5e925SRichard Henderson 
415429f5e925SRichard Henderson             case 2: /* second of pair */
415529f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
415629f5e925SRichard Henderson                 if (arg_ct->oalias) {
415729f5e925SRichard Henderson                     reg = new_args[arg_ct->alias_index];
415829f5e925SRichard Henderson                 } else {
415929f5e925SRichard Henderson                     reg = new_args[arg_ct->pair_index] + 1;
416029f5e925SRichard Henderson                 }
416129f5e925SRichard Henderson                 break;
416229f5e925SRichard Henderson 
416329f5e925SRichard Henderson             case 3: /* first of pair, aliasing with a second input */
416429f5e925SRichard Henderson                 tcg_debug_assert(!arg_ct->newreg);
416529f5e925SRichard Henderson                 reg = new_args[arg_ct->pair_index] - 1;
416629f5e925SRichard Henderson                 break;
416729f5e925SRichard Henderson 
416829f5e925SRichard Henderson             default:
416929f5e925SRichard Henderson                 g_assert_not_reached();
417029f5e925SRichard Henderson             }
417182790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
4172098859f1SRichard Henderson             set_temp_val_reg(s, ts, reg);
4173c896fe29Sbellard             ts->mem_coherent = 0;
4174c896fe29Sbellard             new_args[i] = reg;
4175c896fe29Sbellard         }
4176e8996ee0Sbellard     }
4177c896fe29Sbellard 
4178c896fe29Sbellard     /* emit instruction */
4179d2fd745fSRichard Henderson     if (def->flags & TCG_OPF_VECTOR) {
4180d2fd745fSRichard Henderson         tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
4181d2fd745fSRichard Henderson                        new_args, const_args);
4182d2fd745fSRichard Henderson     } else {
4183dd186292SRichard Henderson         tcg_out_op(s, op->opc, new_args, const_args);
4184d2fd745fSRichard Henderson     }
4185c896fe29Sbellard 
4186c896fe29Sbellard     /* move the outputs in the correct register if needed */
4187c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
418843439139SRichard Henderson         ts = arg_temp(op->args[i]);
4189d63e3b6eSRichard Henderson 
4190d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
4191e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
4192d63e3b6eSRichard Henderson 
4193ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
419498b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
419559d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4196f8bf00f1SRichard Henderson             temp_dead(s, ts);
4197ec7a869dSAurelien Jarno         }
4198c896fe29Sbellard     }
4199c896fe29Sbellard }
4200c896fe29Sbellard 
4201efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op)
4202efe86b21SRichard Henderson {
4203efe86b21SRichard Henderson     const TCGLifeData arg_life = op->life;
4204efe86b21SRichard Henderson     TCGTemp *ots, *itsl, *itsh;
4205efe86b21SRichard Henderson     TCGType vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
4206efe86b21SRichard Henderson 
4207efe86b21SRichard Henderson     /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */
4208efe86b21SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 32);
4209efe86b21SRichard Henderson     tcg_debug_assert(TCGOP_VECE(op) == MO_64);
4210efe86b21SRichard Henderson 
4211efe86b21SRichard Henderson     ots = arg_temp(op->args[0]);
4212efe86b21SRichard Henderson     itsl = arg_temp(op->args[1]);
4213efe86b21SRichard Henderson     itsh = arg_temp(op->args[2]);
4214efe86b21SRichard Henderson 
4215efe86b21SRichard Henderson     /* ENV should not be modified.  */
4216efe86b21SRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4217efe86b21SRichard Henderson 
4218efe86b21SRichard Henderson     /* Allocate the output register now.  */
4219efe86b21SRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
4220efe86b21SRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
4221efe86b21SRichard Henderson         TCGRegSet dup_out_regs =
4222efe86b21SRichard Henderson             tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
4223098859f1SRichard Henderson         TCGReg oreg;
4224efe86b21SRichard Henderson 
4225efe86b21SRichard Henderson         /* Make sure to not spill the input registers. */
4226efe86b21SRichard Henderson         if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) {
4227efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsl->reg);
4228efe86b21SRichard Henderson         }
4229efe86b21SRichard Henderson         if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) {
4230efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsh->reg);
4231efe86b21SRichard Henderson         }
4232efe86b21SRichard Henderson 
4233098859f1SRichard Henderson         oreg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
423431fd884bSRichard Henderson                              output_pref(op, 0), ots->indirect_base);
4235098859f1SRichard Henderson         set_temp_val_reg(s, ots, oreg);
4236efe86b21SRichard Henderson     }
4237efe86b21SRichard Henderson 
4238efe86b21SRichard Henderson     /* Promote dup2 of immediates to dupi_vec. */
4239efe86b21SRichard Henderson     if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) {
4240efe86b21SRichard Henderson         uint64_t val = deposit64(itsl->val, 32, 32, itsh->val);
4241efe86b21SRichard Henderson         MemOp vece = MO_64;
4242efe86b21SRichard Henderson 
4243efe86b21SRichard Henderson         if (val == dup_const(MO_8, val)) {
4244efe86b21SRichard Henderson             vece = MO_8;
4245efe86b21SRichard Henderson         } else if (val == dup_const(MO_16, val)) {
4246efe86b21SRichard Henderson             vece = MO_16;
4247efe86b21SRichard Henderson         } else if (val == dup_const(MO_32, val)) {
4248efe86b21SRichard Henderson             vece = MO_32;
4249efe86b21SRichard Henderson         }
4250efe86b21SRichard Henderson 
4251efe86b21SRichard Henderson         tcg_out_dupi_vec(s, vtype, vece, ots->reg, val);
4252efe86b21SRichard Henderson         goto done;
4253efe86b21SRichard Henderson     }
4254efe86b21SRichard Henderson 
4255efe86b21SRichard Henderson     /* If the two inputs form one 64-bit value, try dupm_vec. */
4256aef85402SRichard Henderson     if (itsl->temp_subindex == HOST_BIG_ENDIAN &&
4257aef85402SRichard Henderson         itsh->temp_subindex == !HOST_BIG_ENDIAN &&
4258aef85402SRichard Henderson         itsl == itsh + (HOST_BIG_ENDIAN ? 1 : -1)) {
4259aef85402SRichard Henderson         TCGTemp *its = itsl - HOST_BIG_ENDIAN;
4260aef85402SRichard Henderson 
4261aef85402SRichard Henderson         temp_sync(s, its + 0, s->reserved_regs, 0, 0);
4262aef85402SRichard Henderson         temp_sync(s, its + 1, s->reserved_regs, 0, 0);
4263aef85402SRichard Henderson 
4264efe86b21SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg,
4265efe86b21SRichard Henderson                              its->mem_base->reg, its->mem_offset)) {
4266efe86b21SRichard Henderson             goto done;
4267efe86b21SRichard Henderson         }
4268efe86b21SRichard Henderson     }
4269efe86b21SRichard Henderson 
4270efe86b21SRichard Henderson     /* Fall back to generic expansion. */
4271efe86b21SRichard Henderson     return false;
4272efe86b21SRichard Henderson 
4273efe86b21SRichard Henderson  done:
427436f5539cSRichard Henderson     ots->mem_coherent = 0;
4275efe86b21SRichard Henderson     if (IS_DEAD_ARG(1)) {
4276efe86b21SRichard Henderson         temp_dead(s, itsl);
4277efe86b21SRichard Henderson     }
4278efe86b21SRichard Henderson     if (IS_DEAD_ARG(2)) {
4279efe86b21SRichard Henderson         temp_dead(s, itsh);
4280efe86b21SRichard Henderson     }
4281efe86b21SRichard Henderson     if (NEED_SYNC_ARG(0)) {
4282efe86b21SRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0));
4283efe86b21SRichard Henderson     } else if (IS_DEAD_ARG(0)) {
4284efe86b21SRichard Henderson         temp_dead(s, ots);
4285efe86b21SRichard Henderson     }
4286efe86b21SRichard Henderson     return true;
4287efe86b21SRichard Henderson }
4288efe86b21SRichard Henderson 
428939004a71SRichard Henderson static void load_arg_reg(TCGContext *s, TCGReg reg, TCGTemp *ts,
429039004a71SRichard Henderson                          TCGRegSet allocated_regs)
4291c896fe29Sbellard {
4292c896fe29Sbellard     if (ts->val_type == TEMP_VAL_REG) {
4293c896fe29Sbellard         if (ts->reg != reg) {
42944250da10SRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
429578113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4296240c08d0SRichard Henderson                 /*
4297240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
4298240c08d0SRichard Henderson                  * temp back to its slot and load from there.
4299240c08d0SRichard Henderson                  */
4300240c08d0SRichard Henderson                 temp_sync(s, ts, allocated_regs, 0, 0);
4301240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
4302240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
430378113e83SRichard Henderson             }
4304c896fe29Sbellard         }
4305c896fe29Sbellard     } else {
4306ccb1bb66SRichard Henderson         TCGRegSet arg_set = 0;
430740ae5c62SRichard Henderson 
43084250da10SRichard Henderson         tcg_reg_free(s, reg, allocated_regs);
430940ae5c62SRichard Henderson         tcg_regset_set_reg(arg_set, reg);
4310b722452aSRichard Henderson         temp_load(s, ts, arg_set, allocated_regs, 0);
4311c896fe29Sbellard     }
431239004a71SRichard Henderson }
431340ae5c62SRichard Henderson 
431439004a71SRichard Henderson static void load_arg_stk(TCGContext *s, int stk_slot, TCGTemp *ts,
431539004a71SRichard Henderson                          TCGRegSet allocated_regs)
431639004a71SRichard Henderson {
431739004a71SRichard Henderson     /*
431839004a71SRichard Henderson      * When the destination is on the stack, load up the temp and store.
431939004a71SRichard Henderson      * If there are many call-saved registers, the temp might live to
432039004a71SRichard Henderson      * see another use; otherwise it'll be discarded.
432139004a71SRichard Henderson      */
432239004a71SRichard Henderson     temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs, 0);
432339004a71SRichard Henderson     tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK,
432439004a71SRichard Henderson                TCG_TARGET_CALL_STACK_OFFSET +
432539004a71SRichard Henderson                stk_slot * sizeof(tcg_target_long));
432639004a71SRichard Henderson }
432739004a71SRichard Henderson 
432839004a71SRichard Henderson static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l,
432939004a71SRichard Henderson                             TCGTemp *ts, TCGRegSet *allocated_regs)
433039004a71SRichard Henderson {
433139004a71SRichard Henderson     if (REG_P(l)) {
433239004a71SRichard Henderson         TCGReg reg = tcg_target_call_iarg_regs[l->arg_slot];
433339004a71SRichard Henderson         load_arg_reg(s, reg, ts, *allocated_regs);
433439004a71SRichard Henderson         tcg_regset_set_reg(*allocated_regs, reg);
433539004a71SRichard Henderson     } else {
433639004a71SRichard Henderson         load_arg_stk(s, l->arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs),
433739004a71SRichard Henderson                      ts, *allocated_regs);
4338c896fe29Sbellard     }
433939cf05d3Sbellard }
4340c896fe29Sbellard 
434139004a71SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
434239004a71SRichard Henderson {
434339004a71SRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
434439004a71SRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
434539004a71SRichard Henderson     const TCGLifeData arg_life = op->life;
434639004a71SRichard Henderson     const TCGHelperInfo *info = tcg_call_info(op);
434739004a71SRichard Henderson     TCGRegSet allocated_regs = s->reserved_regs;
434839004a71SRichard Henderson     int i;
434939004a71SRichard Henderson 
435039004a71SRichard Henderson     /*
435139004a71SRichard Henderson      * Move inputs into place in reverse order,
435239004a71SRichard Henderson      * so that we place stacked arguments first.
435339004a71SRichard Henderson      */
435439004a71SRichard Henderson     for (i = nb_iargs - 1; i >= 0; --i) {
435539004a71SRichard Henderson         const TCGCallArgumentLoc *loc = &info->in[i];
435639004a71SRichard Henderson         TCGTemp *ts = arg_temp(op->args[nb_oargs + i]);
435739004a71SRichard Henderson 
435839004a71SRichard Henderson         switch (loc->kind) {
435939004a71SRichard Henderson         case TCG_CALL_ARG_NORMAL:
436039004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_U:
436139004a71SRichard Henderson         case TCG_CALL_ARG_EXTEND_S:
436239004a71SRichard Henderson             load_arg_normal(s, loc, ts, &allocated_regs);
436339004a71SRichard Henderson             break;
436439004a71SRichard Henderson         default:
436539004a71SRichard Henderson             g_assert_not_reached();
436639004a71SRichard Henderson         }
436739004a71SRichard Henderson     }
436839004a71SRichard Henderson 
436939004a71SRichard Henderson     /* Mark dead temporaries and free the associated registers.  */
4370866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4371866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
437243439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4373c896fe29Sbellard         }
4374c896fe29Sbellard     }
4375c896fe29Sbellard 
437639004a71SRichard Henderson     /* Clobber call registers.  */
4377c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4378c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
4379b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
4380c896fe29Sbellard         }
4381c896fe29Sbellard     }
4382c896fe29Sbellard 
438339004a71SRichard Henderson     /*
438439004a71SRichard Henderson      * Save globals if they might be written by the helper,
438539004a71SRichard Henderson      * sync them if they might be read.
438639004a71SRichard Henderson      */
438739004a71SRichard Henderson     if (info->flags & TCG_CALL_NO_READ_GLOBALS) {
438878505279SAurelien Jarno         /* Nothing to do */
438939004a71SRichard Henderson     } else if (info->flags & TCG_CALL_NO_WRITE_GLOBALS) {
439078505279SAurelien Jarno         sync_globals(s, allocated_regs);
439178505279SAurelien Jarno     } else {
4392e8996ee0Sbellard         save_globals(s, allocated_regs);
4393b9c18f56Saurel32     }
4394c896fe29Sbellard 
43957b7d8b2dSRichard Henderson #ifdef CONFIG_TCG_INTERPRETER
43967b7d8b2dSRichard Henderson     {
43977b7d8b2dSRichard Henderson         gpointer hash = (gpointer)(uintptr_t)info->typemask;
43987b7d8b2dSRichard Henderson         ffi_cif *cif = g_hash_table_lookup(ffi_table, hash);
43997b7d8b2dSRichard Henderson         assert(cif != NULL);
440039004a71SRichard Henderson         tcg_out_call(s, tcg_call_func(op), cif);
44017b7d8b2dSRichard Henderson     }
44027b7d8b2dSRichard Henderson #else
440339004a71SRichard Henderson     tcg_out_call(s, tcg_call_func(op));
44047b7d8b2dSRichard Henderson #endif
4405c896fe29Sbellard 
440639004a71SRichard Henderson     /* Assign output registers and emit moves if needed.  */
440739004a71SRichard Henderson     switch (info->out_kind) {
440839004a71SRichard Henderson     case TCG_CALL_RET_NORMAL:
4409c896fe29Sbellard         for (i = 0; i < nb_oargs; i++) {
441039004a71SRichard Henderson             TCGTemp *ts = arg_temp(op->args[i]);
441139004a71SRichard Henderson             TCGReg reg = tcg_target_call_oarg_regs[i];
4412d63e3b6eSRichard Henderson 
4413d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
4414e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
4415d63e3b6eSRichard Henderson 
4416098859f1SRichard Henderson             set_temp_val_reg(s, ts, reg);
4417c896fe29Sbellard             ts->mem_coherent = 0;
441839004a71SRichard Henderson         }
441939004a71SRichard Henderson         break;
442039004a71SRichard Henderson     default:
442139004a71SRichard Henderson         g_assert_not_reached();
442239004a71SRichard Henderson     }
442339004a71SRichard Henderson 
442439004a71SRichard Henderson     /* Flush or discard output registers as needed. */
442539004a71SRichard Henderson     for (i = 0; i < nb_oargs; i++) {
442639004a71SRichard Henderson         TCGTemp *ts = arg_temp(op->args[i]);
4427ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
442839004a71SRichard Henderson             temp_sync(s, ts, s->reserved_regs, 0, IS_DEAD_ARG(i));
442959d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4430f8bf00f1SRichard Henderson             temp_dead(s, ts);
4431c896fe29Sbellard         }
4432c896fe29Sbellard     }
44338c11ad25SAurelien Jarno }
4434c896fe29Sbellard 
4435c896fe29Sbellard #ifdef CONFIG_PROFILER
4436c896fe29Sbellard 
4437c3fac113SEmilio G. Cota /* avoid copy/paste errors */
4438c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field)                       \
4439c3fac113SEmilio G. Cota     do {                                                \
4440d73415a3SStefan Hajnoczi         (to)->field += qatomic_read(&((from)->field));  \
4441c3fac113SEmilio G. Cota     } while (0)
4442c896fe29Sbellard 
4443c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field)                                       \
4444c3fac113SEmilio G. Cota     do {                                                                \
4445d73415a3SStefan Hajnoczi         typeof((from)->field) val__ = qatomic_read(&((from)->field));   \
4446c3fac113SEmilio G. Cota         if (val__ > (to)->field) {                                      \
4447c3fac113SEmilio G. Cota             (to)->field = val__;                                        \
4448c3fac113SEmilio G. Cota         }                                                               \
4449c3fac113SEmilio G. Cota     } while (0)
4450c3fac113SEmilio G. Cota 
4451c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */
4452c3fac113SEmilio G. Cota static inline
4453c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
4454c896fe29Sbellard {
44550e2d61cfSRichard Henderson     unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
4456c3fac113SEmilio G. Cota     unsigned int i;
4457c3fac113SEmilio G. Cota 
44583468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4459d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
44603468b59eSEmilio G. Cota         const TCGProfile *orig = &s->prof;
4461c3fac113SEmilio G. Cota 
4462c3fac113SEmilio G. Cota         if (counters) {
446372fd2efbSEmilio G. Cota             PROF_ADD(prof, orig, cpu_exec_time);
4464c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count1);
4465c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count);
4466c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, op_count);
4467c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, op_count_max);
4468c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, temp_count);
4469c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, temp_count_max);
4470c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, del_op_count);
4471c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_in_len);
4472c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_out_len);
4473c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, search_out_len);
4474c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, interm_time);
4475c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_time);
4476c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, la_time);
4477c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, opt_time);
4478c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_count);
4479c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_time);
4480c3fac113SEmilio G. Cota         }
4481c3fac113SEmilio G. Cota         if (table) {
4482c896fe29Sbellard             int i;
4483d70724ceSzhanghailiang 
448415fc7daaSRichard Henderson             for (i = 0; i < NB_OPS; i++) {
4485c3fac113SEmilio G. Cota                 PROF_ADD(prof, orig, table_op_count[i]);
4486c3fac113SEmilio G. Cota             }
4487c3fac113SEmilio G. Cota         }
4488c3fac113SEmilio G. Cota     }
4489c3fac113SEmilio G. Cota }
4490c3fac113SEmilio G. Cota 
4491c3fac113SEmilio G. Cota #undef PROF_ADD
4492c3fac113SEmilio G. Cota #undef PROF_MAX
4493c3fac113SEmilio G. Cota 
4494c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof)
4495c3fac113SEmilio G. Cota {
4496c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, true, false);
4497c3fac113SEmilio G. Cota }
4498c3fac113SEmilio G. Cota 
4499c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof)
4500c3fac113SEmilio G. Cota {
4501c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, false, true);
4502c3fac113SEmilio G. Cota }
4503c3fac113SEmilio G. Cota 
4504b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf)
4505c3fac113SEmilio G. Cota {
4506c3fac113SEmilio G. Cota     TCGProfile prof = {};
4507c3fac113SEmilio G. Cota     int i;
4508c3fac113SEmilio G. Cota 
4509c3fac113SEmilio G. Cota     tcg_profile_snapshot_table(&prof);
4510c3fac113SEmilio G. Cota     for (i = 0; i < NB_OPS; i++) {
4511b6a7f3e0SDaniel P. Berrangé         g_string_append_printf(buf, "%s %" PRId64 "\n", tcg_op_defs[i].name,
4512c3fac113SEmilio G. Cota                                prof.table_op_count[i]);
4513c896fe29Sbellard     }
4514c896fe29Sbellard }
451572fd2efbSEmilio G. Cota 
451672fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
451772fd2efbSEmilio G. Cota {
45180e2d61cfSRichard Henderson     unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
451972fd2efbSEmilio G. Cota     unsigned int i;
452072fd2efbSEmilio G. Cota     int64_t ret = 0;
452172fd2efbSEmilio G. Cota 
452272fd2efbSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4523d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
452472fd2efbSEmilio G. Cota         const TCGProfile *prof = &s->prof;
452572fd2efbSEmilio G. Cota 
4526d73415a3SStefan Hajnoczi         ret += qatomic_read(&prof->cpu_exec_time);
452772fd2efbSEmilio G. Cota     }
452872fd2efbSEmilio G. Cota     return ret;
452972fd2efbSEmilio G. Cota }
4530246ae24dSMax Filippov #else
4531b6a7f3e0SDaniel P. Berrangé void tcg_dump_op_count(GString *buf)
4532246ae24dSMax Filippov {
4533b6a7f3e0SDaniel P. Berrangé     g_string_append_printf(buf, "[TCG profiler not compiled]\n");
4534246ae24dSMax Filippov }
453572fd2efbSEmilio G. Cota 
453672fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
453772fd2efbSEmilio G. Cota {
453872fd2efbSEmilio G. Cota     error_report("%s: TCG profiler not compiled", __func__);
453972fd2efbSEmilio G. Cota     exit(EXIT_FAILURE);
454072fd2efbSEmilio G. Cota }
4541c896fe29Sbellard #endif
4542c896fe29Sbellard 
4543c896fe29Sbellard 
4544fbf59aadSRichard Henderson int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start)
4545c896fe29Sbellard {
4546c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER
4547c3fac113SEmilio G. Cota     TCGProfile *prof = &s->prof;
4548c3fac113SEmilio G. Cota #endif
454915fa08f8SRichard Henderson     int i, num_insns;
455015fa08f8SRichard Henderson     TCGOp *op;
4551c896fe29Sbellard 
455204fe6400SRichard Henderson #ifdef CONFIG_PROFILER
455304fe6400SRichard Henderson     {
4554c1f543b7SEmilio G. Cota         int n = 0;
455504fe6400SRichard Henderson 
455615fa08f8SRichard Henderson         QTAILQ_FOREACH(op, &s->ops, link) {
455715fa08f8SRichard Henderson             n++;
455815fa08f8SRichard Henderson         }
4559d73415a3SStefan Hajnoczi         qatomic_set(&prof->op_count, prof->op_count + n);
4560c3fac113SEmilio G. Cota         if (n > prof->op_count_max) {
4561d73415a3SStefan Hajnoczi             qatomic_set(&prof->op_count_max, n);
456204fe6400SRichard Henderson         }
456304fe6400SRichard Henderson 
456404fe6400SRichard Henderson         n = s->nb_temps;
4565d73415a3SStefan Hajnoczi         qatomic_set(&prof->temp_count, prof->temp_count + n);
4566c3fac113SEmilio G. Cota         if (n > prof->temp_count_max) {
4567d73415a3SStefan Hajnoczi             qatomic_set(&prof->temp_count_max, n);
456804fe6400SRichard Henderson         }
456904fe6400SRichard Henderson     }
457004fe6400SRichard Henderson #endif
457104fe6400SRichard Henderson 
4572c896fe29Sbellard #ifdef DEBUG_DISAS
4573d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
4574fbf59aadSRichard Henderson                  && qemu_log_in_addr_range(pc_start))) {
4575c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
457678b54858SRichard Henderson         if (logfile) {
457778b54858SRichard Henderson             fprintf(logfile, "OP:\n");
4578b7a83ff8SRichard Henderson             tcg_dump_ops(s, logfile, false);
457978b54858SRichard Henderson             fprintf(logfile, "\n");
4580fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
4581c896fe29Sbellard         }
458278b54858SRichard Henderson     }
4583c896fe29Sbellard #endif
4584c896fe29Sbellard 
4585bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
4586bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
4587bef16ab4SRichard Henderson     {
4588bef16ab4SRichard Henderson         TCGLabel *l;
4589bef16ab4SRichard Henderson         bool error = false;
4590bef16ab4SRichard Henderson 
4591bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
4592bef16ab4SRichard Henderson             if (unlikely(!l->present) && l->refs) {
4593bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
4594bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
4595bef16ab4SRichard Henderson                 error = true;
4596bef16ab4SRichard Henderson             }
4597bef16ab4SRichard Henderson         }
4598bef16ab4SRichard Henderson         assert(!error);
4599bef16ab4SRichard Henderson     }
4600bef16ab4SRichard Henderson #endif
4601bef16ab4SRichard Henderson 
4602c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
4603d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
4604c5cc28ffSAurelien Jarno #endif
4605c5cc28ffSAurelien Jarno 
46068f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
4607c45cb8bbSRichard Henderson     tcg_optimize(s);
46088f2e8c07SKirill Batuzov #endif
46098f2e8c07SKirill Batuzov 
4610a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4611d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
4612d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time - profile_getclock());
4613a23a9ec6Sbellard #endif
4614c5cc28ffSAurelien Jarno 
4615b4fc67c7SRichard Henderson     reachable_code_pass(s);
4616b83eabeaSRichard Henderson     liveness_pass_1(s);
46175a18407fSRichard Henderson 
46185a18407fSRichard Henderson     if (s->nb_indirects > 0) {
46195a18407fSRichard Henderson #ifdef DEBUG_DISAS
46205a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
4621fbf59aadSRichard Henderson                      && qemu_log_in_addr_range(pc_start))) {
4622c60f599bSRichard Henderson             FILE *logfile = qemu_log_trylock();
462378b54858SRichard Henderson             if (logfile) {
462478b54858SRichard Henderson                 fprintf(logfile, "OP before indirect lowering:\n");
4625b7a83ff8SRichard Henderson                 tcg_dump_ops(s, logfile, false);
462678b54858SRichard Henderson                 fprintf(logfile, "\n");
4627fc59d2d8SRobert Foley                 qemu_log_unlock(logfile);
46285a18407fSRichard Henderson             }
462978b54858SRichard Henderson         }
46305a18407fSRichard Henderson #endif
46315a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
4632b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
46335a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
4634b83eabeaSRichard Henderson             liveness_pass_1(s);
46355a18407fSRichard Henderson         }
46365a18407fSRichard Henderson     }
4637c5cc28ffSAurelien Jarno 
4638a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4639d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time + profile_getclock());
4640a23a9ec6Sbellard #endif
4641c896fe29Sbellard 
4642c896fe29Sbellard #ifdef DEBUG_DISAS
4643d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
4644fbf59aadSRichard Henderson                  && qemu_log_in_addr_range(pc_start))) {
4645c60f599bSRichard Henderson         FILE *logfile = qemu_log_trylock();
464678b54858SRichard Henderson         if (logfile) {
464778b54858SRichard Henderson             fprintf(logfile, "OP after optimization and liveness analysis:\n");
4648b7a83ff8SRichard Henderson             tcg_dump_ops(s, logfile, true);
464978b54858SRichard Henderson             fprintf(logfile, "\n");
4650fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
4651c896fe29Sbellard         }
465278b54858SRichard Henderson     }
4653c896fe29Sbellard #endif
4654c896fe29Sbellard 
465535abb009SRichard Henderson     /* Initialize goto_tb jump offsets. */
465635abb009SRichard Henderson     tb->jmp_reset_offset[0] = TB_JMP_RESET_OFFSET_INVALID;
465735abb009SRichard Henderson     tb->jmp_reset_offset[1] = TB_JMP_RESET_OFFSET_INVALID;
465835abb009SRichard Henderson     tcg_ctx->tb_jmp_reset_offset = tb->jmp_reset_offset;
465935abb009SRichard Henderson     if (TCG_TARGET_HAS_direct_jump) {
466035abb009SRichard Henderson         tcg_ctx->tb_jmp_insn_offset = tb->jmp_target_arg;
466135abb009SRichard Henderson         tcg_ctx->tb_jmp_target_addr = NULL;
466235abb009SRichard Henderson     } else {
466335abb009SRichard Henderson         tcg_ctx->tb_jmp_insn_offset = NULL;
466435abb009SRichard Henderson         tcg_ctx->tb_jmp_target_addr = tb->jmp_target_arg;
466535abb009SRichard Henderson     }
466635abb009SRichard Henderson 
4667c896fe29Sbellard     tcg_reg_alloc_start(s);
4668c896fe29Sbellard 
4669db0c51a3SRichard Henderson     /*
4670db0c51a3SRichard Henderson      * Reset the buffer pointers when restarting after overflow.
4671db0c51a3SRichard Henderson      * TODO: Move this into translate-all.c with the rest of the
4672db0c51a3SRichard Henderson      * buffer management.  Having only this done here is confusing.
4673db0c51a3SRichard Henderson      */
4674db0c51a3SRichard Henderson     s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr);
4675db0c51a3SRichard Henderson     s->code_ptr = s->code_buf;
4676c896fe29Sbellard 
4677659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
46786001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
4679659ef5cbSRichard Henderson #endif
468057a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
468157a26946SRichard Henderson     s->pool_labels = NULL;
468257a26946SRichard Henderson #endif
46839ecefc84SRichard Henderson 
4684fca8a500SRichard Henderson     num_insns = -1;
468515fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
4686c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
4687b3db8758Sblueswir1 
4688c896fe29Sbellard #ifdef CONFIG_PROFILER
4689d73415a3SStefan Hajnoczi         qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
4690c896fe29Sbellard #endif
4691c45cb8bbSRichard Henderson 
4692c896fe29Sbellard         switch (opc) {
4693c896fe29Sbellard         case INDEX_op_mov_i32:
4694c896fe29Sbellard         case INDEX_op_mov_i64:
4695d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
4696dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
4697c896fe29Sbellard             break;
4698bab1671fSRichard Henderson         case INDEX_op_dup_vec:
4699bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
4700bab1671fSRichard Henderson             break;
4701765b842aSRichard Henderson         case INDEX_op_insn_start:
4702fca8a500SRichard Henderson             if (num_insns >= 0) {
47039f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
47049f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
47059f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
47069f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
4707fca8a500SRichard Henderson             }
4708fca8a500SRichard Henderson             num_insns++;
4709bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
4710bad729e2SRichard Henderson                 target_ulong a;
4711bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
4712efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
4713bad729e2SRichard Henderson #else
4714efee3746SRichard Henderson                 a = op->args[i];
4715bad729e2SRichard Henderson #endif
4716fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
4717bad729e2SRichard Henderson             }
4718c896fe29Sbellard             break;
47195ff9d6a4Sbellard         case INDEX_op_discard:
472043439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
47215ff9d6a4Sbellard             break;
4722c896fe29Sbellard         case INDEX_op_set_label:
4723e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
472492ab8e7dSRichard Henderson             tcg_out_label(s, arg_label(op->args[0]));
4725c896fe29Sbellard             break;
4726c896fe29Sbellard         case INDEX_op_call:
4727dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
4728c45cb8bbSRichard Henderson             break;
4729efe86b21SRichard Henderson         case INDEX_op_dup2_vec:
4730efe86b21SRichard Henderson             if (tcg_reg_alloc_dup2(s, op)) {
4731efe86b21SRichard Henderson                 break;
4732efe86b21SRichard Henderson             }
4733efe86b21SRichard Henderson             /* fall through */
4734c896fe29Sbellard         default:
473525c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
4736be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
4737c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
4738c896fe29Sbellard                faster to have specialized register allocator functions for
4739c896fe29Sbellard                some common argument patterns */
4740dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
4741c896fe29Sbellard             break;
4742c896fe29Sbellard         }
4743b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
4744b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
4745b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
4746b125f9dcSRichard Henderson            generating code without having to check during generation.  */
4747644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
4748b125f9dcSRichard Henderson             return -1;
4749b125f9dcSRichard Henderson         }
47506e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
47516e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
47526e6c4efeSRichard Henderson             return -2;
47536e6c4efeSRichard Henderson         }
4754c896fe29Sbellard     }
4755fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
4756fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
4757c45cb8bbSRichard Henderson 
4758b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
4759659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
4760aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
4761aeee05f5SRichard Henderson     if (i < 0) {
4762aeee05f5SRichard Henderson         return i;
476323dceda6SRichard Henderson     }
4764659ef5cbSRichard Henderson #endif
476557a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
47661768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
47671768987bSRichard Henderson     if (i < 0) {
47681768987bSRichard Henderson         return i;
476957a26946SRichard Henderson     }
477057a26946SRichard Henderson #endif
47717ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
47727ecd02a0SRichard Henderson         return -2;
47737ecd02a0SRichard Henderson     }
4774c896fe29Sbellard 
4775df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
4776c896fe29Sbellard     /* flush instruction cache */
4777db0c51a3SRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
4778db0c51a3SRichard Henderson                         (uintptr_t)s->code_buf,
47791da8de39SRichard Henderson                         tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
4780df5d2b16SRichard Henderson #endif
47812aeabc08SStefan Weil 
47821813e175SRichard Henderson     return tcg_current_code_size(s);
4783c896fe29Sbellard }
4784c896fe29Sbellard 
4785a23a9ec6Sbellard #ifdef CONFIG_PROFILER
47863a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf)
4787a23a9ec6Sbellard {
4788c3fac113SEmilio G. Cota     TCGProfile prof = {};
4789c3fac113SEmilio G. Cota     const TCGProfile *s;
4790c3fac113SEmilio G. Cota     int64_t tb_count;
4791c3fac113SEmilio G. Cota     int64_t tb_div_count;
4792c3fac113SEmilio G. Cota     int64_t tot;
4793c3fac113SEmilio G. Cota 
4794c3fac113SEmilio G. Cota     tcg_profile_snapshot_counters(&prof);
4795c3fac113SEmilio G. Cota     s = &prof;
4796c3fac113SEmilio G. Cota     tb_count = s->tb_count;
4797c3fac113SEmilio G. Cota     tb_div_count = tb_count ? tb_count : 1;
4798c3fac113SEmilio G. Cota     tot = s->interm_time + s->code_time;
4799a23a9ec6Sbellard 
48003a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "JIT cycles          %" PRId64
48013a841ab5SDaniel P. Berrangé                            " (%0.3f s at 2.4 GHz)\n",
4802a23a9ec6Sbellard                            tot, tot / 2.4e9);
48033a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "translated TBs      %" PRId64
48043a841ab5SDaniel P. Berrangé                            " (aborted=%" PRId64 " %0.1f%%)\n",
4805fca8a500SRichard Henderson                            tb_count, s->tb_count1 - tb_count,
4806fca8a500SRichard Henderson                            (double)(s->tb_count1 - s->tb_count)
4807fca8a500SRichard Henderson                            / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
48083a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg ops/TB          %0.1f max=%d\n",
4809fca8a500SRichard Henderson                            (double)s->op_count / tb_div_count, s->op_count_max);
48103a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "deleted ops/TB      %0.2f\n",
4811fca8a500SRichard Henderson                            (double)s->del_op_count / tb_div_count);
48123a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg temps/TB        %0.2f max=%d\n",
48133a841ab5SDaniel P. Berrangé                            (double)s->temp_count / tb_div_count,
48143a841ab5SDaniel P. Berrangé                            s->temp_count_max);
48153a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg host code/TB    %0.1f\n",
4816fca8a500SRichard Henderson                            (double)s->code_out_len / tb_div_count);
48173a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "avg search data/TB  %0.1f\n",
4818fca8a500SRichard Henderson                            (double)s->search_out_len / tb_div_count);
4819a23a9ec6Sbellard 
48203a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/op           %0.1f\n",
4821a23a9ec6Sbellard                            s->op_count ? (double)tot / s->op_count : 0);
48223a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/in byte      %0.1f\n",
4823a23a9ec6Sbellard                            s->code_in_len ? (double)tot / s->code_in_len : 0);
48243a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/out byte     %0.1f\n",
4825a23a9ec6Sbellard                            s->code_out_len ? (double)tot / s->code_out_len : 0);
48263a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cycles/search byte     %0.1f\n",
48273a841ab5SDaniel P. Berrangé                            s->search_out_len ?
48283a841ab5SDaniel P. Berrangé                            (double)tot / s->search_out_len : 0);
4829fca8a500SRichard Henderson     if (tot == 0) {
4830a23a9ec6Sbellard         tot = 1;
4831fca8a500SRichard Henderson     }
48323a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "  gen_interm time   %0.1f%%\n",
4833a23a9ec6Sbellard                            (double)s->interm_time / tot * 100.0);
48343a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "  gen_code time     %0.1f%%\n",
4835a23a9ec6Sbellard                            (double)s->code_time / tot * 100.0);
48363a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "optim./code time    %0.1f%%\n",
48373a841ab5SDaniel P. Berrangé                            (double)s->opt_time / (s->code_time ?
48383a841ab5SDaniel P. Berrangé                                                   s->code_time : 1)
4839c5cc28ffSAurelien Jarno                            * 100.0);
48403a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "liveness/code time  %0.1f%%\n",
48413a841ab5SDaniel P. Berrangé                            (double)s->la_time / (s->code_time ?
48423a841ab5SDaniel P. Berrangé                                                  s->code_time : 1) * 100.0);
48433a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "cpu_restore count   %" PRId64 "\n",
4844a23a9ec6Sbellard                            s->restore_count);
48453a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "  avg cycles        %0.1f\n",
48463a841ab5SDaniel P. Berrangé                            s->restore_count ?
48473a841ab5SDaniel P. Berrangé                            (double)s->restore_time / s->restore_count : 0);
4848a23a9ec6Sbellard }
4849a23a9ec6Sbellard #else
48503a841ab5SDaniel P. Berrangé void tcg_dump_info(GString *buf)
4851a23a9ec6Sbellard {
48523a841ab5SDaniel P. Berrangé     g_string_append_printf(buf, "[TCG profiler not compiled]\n");
4853a23a9ec6Sbellard }
4854a23a9ec6Sbellard #endif
4855813da627SRichard Henderson 
4856813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
48575872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
48585872bbf2SRichard Henderson 
48595872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
48605872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
48615872bbf2SRichard Henderson 
48625872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
48635872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
48645872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
48655872bbf2SRichard Henderson 
48665872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
48675872bbf2SRichard Henderson */
4868813da627SRichard Henderson 
4869813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
4870813da627SRichard Henderson typedef enum {
4871813da627SRichard Henderson     JIT_NOACTION = 0,
4872813da627SRichard Henderson     JIT_REGISTER_FN,
4873813da627SRichard Henderson     JIT_UNREGISTER_FN
4874813da627SRichard Henderson } jit_actions_t;
4875813da627SRichard Henderson 
4876813da627SRichard Henderson struct jit_code_entry {
4877813da627SRichard Henderson     struct jit_code_entry *next_entry;
4878813da627SRichard Henderson     struct jit_code_entry *prev_entry;
4879813da627SRichard Henderson     const void *symfile_addr;
4880813da627SRichard Henderson     uint64_t symfile_size;
4881813da627SRichard Henderson };
4882813da627SRichard Henderson 
4883813da627SRichard Henderson struct jit_descriptor {
4884813da627SRichard Henderson     uint32_t version;
4885813da627SRichard Henderson     uint32_t action_flag;
4886813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
4887813da627SRichard Henderson     struct jit_code_entry *first_entry;
4888813da627SRichard Henderson };
4889813da627SRichard Henderson 
4890813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
4891813da627SRichard Henderson void __jit_debug_register_code(void)
4892813da627SRichard Henderson {
4893813da627SRichard Henderson     asm("");
4894813da627SRichard Henderson }
4895813da627SRichard Henderson 
4896813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
4897813da627SRichard Henderson    the version before we can set it.  */
4898813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
4899813da627SRichard Henderson 
4900813da627SRichard Henderson /* End GDB interface.  */
4901813da627SRichard Henderson 
4902813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
4903813da627SRichard Henderson {
4904813da627SRichard Henderson     const char *p = strtab + 1;
4905813da627SRichard Henderson 
4906813da627SRichard Henderson     while (1) {
4907813da627SRichard Henderson         if (strcmp(p, str) == 0) {
4908813da627SRichard Henderson             return p - strtab;
4909813da627SRichard Henderson         }
4910813da627SRichard Henderson         p += strlen(p) + 1;
4911813da627SRichard Henderson     }
4912813da627SRichard Henderson }
4913813da627SRichard Henderson 
4914755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size,
49152c90784aSRichard Henderson                                  const void *debug_frame,
49162c90784aSRichard Henderson                                  size_t debug_frame_size)
4917813da627SRichard Henderson {
49185872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
49195872bbf2SRichard Henderson         uint32_t  len;
49205872bbf2SRichard Henderson         uint16_t  version;
49215872bbf2SRichard Henderson         uint32_t  abbrev;
49225872bbf2SRichard Henderson         uint8_t   ptr_size;
49235872bbf2SRichard Henderson         uint8_t   cu_die;
49245872bbf2SRichard Henderson         uint16_t  cu_lang;
49255872bbf2SRichard Henderson         uintptr_t cu_low_pc;
49265872bbf2SRichard Henderson         uintptr_t cu_high_pc;
49275872bbf2SRichard Henderson         uint8_t   fn_die;
49285872bbf2SRichard Henderson         char      fn_name[16];
49295872bbf2SRichard Henderson         uintptr_t fn_low_pc;
49305872bbf2SRichard Henderson         uintptr_t fn_high_pc;
49315872bbf2SRichard Henderson         uint8_t   cu_eoc;
49325872bbf2SRichard Henderson     };
4933813da627SRichard Henderson 
4934813da627SRichard Henderson     struct ElfImage {
4935813da627SRichard Henderson         ElfW(Ehdr) ehdr;
4936813da627SRichard Henderson         ElfW(Phdr) phdr;
49375872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
49385872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
49395872bbf2SRichard Henderson         struct DebugInfo di;
49405872bbf2SRichard Henderson         uint8_t    da[24];
49415872bbf2SRichard Henderson         char       str[80];
49425872bbf2SRichard Henderson     };
49435872bbf2SRichard Henderson 
49445872bbf2SRichard Henderson     struct ElfImage *img;
49455872bbf2SRichard Henderson 
49465872bbf2SRichard Henderson     static const struct ElfImage img_template = {
49475872bbf2SRichard Henderson         .ehdr = {
49485872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
49495872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
49505872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
49515872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
49525872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
49535872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
49545872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
49555872bbf2SRichard Henderson             .e_type = ET_EXEC,
49565872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
49575872bbf2SRichard Henderson             .e_version = EV_CURRENT,
49585872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
49595872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
49605872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
49615872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
49625872bbf2SRichard Henderson             .e_phnum = 1,
49635872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
49645872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
49655872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
4966abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
4967abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
4968abbb3eaeSRichard Henderson #endif
4969abbb3eaeSRichard Henderson #ifdef ELF_OSABI
4970abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
4971abbb3eaeSRichard Henderson #endif
49725872bbf2SRichard Henderson         },
49735872bbf2SRichard Henderson         .phdr = {
49745872bbf2SRichard Henderson             .p_type = PT_LOAD,
49755872bbf2SRichard Henderson             .p_flags = PF_X,
49765872bbf2SRichard Henderson         },
49775872bbf2SRichard Henderson         .shdr = {
49785872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
49795872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
49805872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
49815872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
49825872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
49835872bbf2SRichard Henderson             [1] = { /* .text */
49845872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
49855872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
49865872bbf2SRichard Henderson             },
49875872bbf2SRichard Henderson             [2] = { /* .debug_info */
49885872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
49895872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
49905872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
49915872bbf2SRichard Henderson             },
49925872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
49935872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
49945872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
49955872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
49965872bbf2SRichard Henderson             },
49975872bbf2SRichard Henderson             [4] = { /* .debug_frame */
49985872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
49995872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
50005872bbf2SRichard Henderson             },
50015872bbf2SRichard Henderson             [5] = { /* .symtab */
50025872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
50035872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
50045872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
50055872bbf2SRichard Henderson                 .sh_info = 1,
50065872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
50075872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
50085872bbf2SRichard Henderson             },
50095872bbf2SRichard Henderson             [6] = { /* .strtab */
50105872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
50115872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
50125872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
50135872bbf2SRichard Henderson             }
50145872bbf2SRichard Henderson         },
50155872bbf2SRichard Henderson         .sym = {
50165872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
50175872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
50185872bbf2SRichard Henderson                 .st_shndx = 1,
50195872bbf2SRichard Henderson             }
50205872bbf2SRichard Henderson         },
50215872bbf2SRichard Henderson         .di = {
50225872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
50235872bbf2SRichard Henderson             .version = 2,
50245872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
50255872bbf2SRichard Henderson             .cu_die = 1,
50265872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
50275872bbf2SRichard Henderson             .fn_die = 2,
50285872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
50295872bbf2SRichard Henderson         },
50305872bbf2SRichard Henderson         .da = {
50315872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
50325872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
50335872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
50345872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
50355872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
50365872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
50375872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
50385872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
50395872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
50405872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
50415872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
50425872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
50435872bbf2SRichard Henderson             0           /* no more abbrev */
50445872bbf2SRichard Henderson         },
50455872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
50465872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
5047813da627SRichard Henderson     };
5048813da627SRichard Henderson 
5049813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
5050813da627SRichard Henderson     static struct jit_code_entry one_entry;
5051813da627SRichard Henderson 
50525872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
5053813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
50542c90784aSRichard Henderson     DebugFrameHeader *dfh;
5055813da627SRichard Henderson 
50565872bbf2SRichard Henderson     img = g_malloc(img_size);
50575872bbf2SRichard Henderson     *img = img_template;
5058813da627SRichard Henderson 
50595872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
50605872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
50615872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
5062813da627SRichard Henderson 
50635872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
50645872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
50655872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
5066813da627SRichard Henderson 
50675872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
50685872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
50695872bbf2SRichard Henderson 
50705872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
50715872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
50725872bbf2SRichard Henderson 
50735872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
50745872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
50755872bbf2SRichard Henderson 
50765872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
50775872bbf2SRichard Henderson     img->sym[1].st_value = buf;
50785872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
50795872bbf2SRichard Henderson 
50805872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
508145aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
50825872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
508345aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
5084813da627SRichard Henderson 
50852c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
50862c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
50872c90784aSRichard Henderson     dfh->fde.func_start = buf;
50882c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
50892c90784aSRichard Henderson 
5090813da627SRichard Henderson #ifdef DEBUG_JIT
5091813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
5092813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
5093813da627SRichard Henderson     {
5094eb6b2edfSBin Meng         g_autofree char *jit = g_strdup_printf("%s/qemu.jit", g_get_tmp_dir());
5095eb6b2edfSBin Meng         FILE *f = fopen(jit, "w+b");
5096813da627SRichard Henderson         if (f) {
50975872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
5098813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
5099813da627SRichard Henderson             }
5100813da627SRichard Henderson             fclose(f);
5101813da627SRichard Henderson         }
5102813da627SRichard Henderson     }
5103813da627SRichard Henderson #endif
5104813da627SRichard Henderson 
5105813da627SRichard Henderson     one_entry.symfile_addr = img;
5106813da627SRichard Henderson     one_entry.symfile_size = img_size;
5107813da627SRichard Henderson 
5108813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
5109813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
5110813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
5111813da627SRichard Henderson     __jit_debug_register_code();
5112813da627SRichard Henderson }
5113813da627SRichard Henderson #else
51145872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
51155872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
5116813da627SRichard Henderson 
5117755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
51182c90784aSRichard Henderson                                  const void *debug_frame,
51192c90784aSRichard Henderson                                  size_t debug_frame_size)
5120813da627SRichard Henderson {
5121813da627SRichard Henderson }
5122813da627SRichard Henderson 
5123755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size)
5124813da627SRichard Henderson {
5125813da627SRichard Henderson }
5126813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
5127db432672SRichard Henderson 
5128db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
5129db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
5130db432672SRichard Henderson {
5131db432672SRichard Henderson     g_assert_not_reached();
5132db432672SRichard Henderson }
5133db432672SRichard Henderson #endif
5134