xref: /qemu/tcg/tcg.c (revision b0a0794a0f16e2160d8d35b14cca8f5e81b8b67e)
1c896fe29Sbellard /*
2c896fe29Sbellard  * Tiny Code Generator for QEMU
3c896fe29Sbellard  *
4c896fe29Sbellard  * Copyright (c) 2008 Fabrice Bellard
5c896fe29Sbellard  *
6c896fe29Sbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
7c896fe29Sbellard  * of this software and associated documentation files (the "Software"), to deal
8c896fe29Sbellard  * in the Software without restriction, including without limitation the rights
9c896fe29Sbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10c896fe29Sbellard  * copies of the Software, and to permit persons to whom the Software is
11c896fe29Sbellard  * furnished to do so, subject to the following conditions:
12c896fe29Sbellard  *
13c896fe29Sbellard  * The above copyright notice and this permission notice shall be included in
14c896fe29Sbellard  * all copies or substantial portions of the Software.
15c896fe29Sbellard  *
16c896fe29Sbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17c896fe29Sbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18c896fe29Sbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19c896fe29Sbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20c896fe29Sbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21c896fe29Sbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22c896fe29Sbellard  * THE SOFTWARE.
23c896fe29Sbellard  */
24c896fe29Sbellard 
25c896fe29Sbellard /* define it to use liveness analysis (better code) */
268f2e8c07SKirill Batuzov #define USE_TCG_OPTIMIZATIONS
27c896fe29Sbellard 
28757e725bSPeter Maydell #include "qemu/osdep.h"
29cca82982Saurel32 
30813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB.  */
31813da627SRichard Henderson #undef DEBUG_JIT
32813da627SRichard Henderson 
3372fd2efbSEmilio G. Cota #include "qemu/error-report.h"
34f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
351de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
36d4c51a0aSMarkus Armbruster #include "qemu/qemu-print.h"
371de7afc9SPaolo Bonzini #include "qemu/timer.h"
38084cfca1SRichard Henderson #include "qemu/cacheflush.h"
39c896fe29Sbellard 
40c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU
41c896fe29Sbellard    CPU definitions. Currently they are used for qemu_ld/st
42c896fe29Sbellard    instructions */
43c896fe29Sbellard #define NO_CPU_IO_DEFS
44c896fe29Sbellard 
4563c91552SPaolo Bonzini #include "exec/exec-all.h"
4663c91552SPaolo Bonzini 
475cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY)
485cc8767dSLike Xu #include "hw/boards.h"
495cc8767dSLike Xu #endif
505cc8767dSLike Xu 
51dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
52813da627SRichard Henderson 
53edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX
54813da627SRichard Henderson # define ELF_CLASS  ELFCLASS32
55edee2579SRichard Henderson #else
56edee2579SRichard Henderson # define ELF_CLASS  ELFCLASS64
57813da627SRichard Henderson #endif
58813da627SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
59813da627SRichard Henderson # define ELF_DATA   ELFDATA2MSB
60813da627SRichard Henderson #else
61813da627SRichard Henderson # define ELF_DATA   ELFDATA2LSB
62813da627SRichard Henderson #endif
63813da627SRichard Henderson 
64c896fe29Sbellard #include "elf.h"
65508127e2SPaolo Bonzini #include "exec/log.h"
66c896fe29Sbellard 
67139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and
68ce151109SPeter Maydell    used here. */
69e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s);
70e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
716ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
722ba7fae2SRichard Henderson                         intptr_t value, intptr_t addend);
73c896fe29Sbellard 
74497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts.  */
75497a22ebSRichard Henderson typedef struct {
76497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
77497a22ebSRichard Henderson     uint32_t id;
78497a22ebSRichard Henderson     uint8_t version;
79497a22ebSRichard Henderson     char augmentation[1];
80497a22ebSRichard Henderson     uint8_t code_align;
81497a22ebSRichard Henderson     uint8_t data_align;
82497a22ebSRichard Henderson     uint8_t return_column;
83497a22ebSRichard Henderson } DebugFrameCIE;
84497a22ebSRichard Henderson 
85497a22ebSRichard Henderson typedef struct QEMU_PACKED {
86497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
87497a22ebSRichard Henderson     uint32_t cie_offset;
88edee2579SRichard Henderson     uintptr_t func_start;
89edee2579SRichard Henderson     uintptr_t func_len;
90497a22ebSRichard Henderson } DebugFrameFDEHeader;
91497a22ebSRichard Henderson 
922c90784aSRichard Henderson typedef struct QEMU_PACKED {
932c90784aSRichard Henderson     DebugFrameCIE cie;
942c90784aSRichard Henderson     DebugFrameFDEHeader fde;
952c90784aSRichard Henderson } DebugFrameHeader;
962c90784aSRichard Henderson 
97755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
982c90784aSRichard Henderson                                  const void *debug_frame,
992c90784aSRichard Henderson                                  size_t debug_frame_size)
100813da627SRichard Henderson     __attribute__((unused));
101813da627SRichard Henderson 
102139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */
1032a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
104a05b5b9bSRichard Henderson                        intptr_t arg2);
10578113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
106c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1072a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
1085e8892dbSMiroslav Rezanina static void tcg_out_op(TCGContext *s, TCGOpcode opc,
1095e8892dbSMiroslav Rezanina                        const TCGArg args[TCG_MAX_OP_ARGS],
1105e8892dbSMiroslav Rezanina                        const int const_args[TCG_MAX_OP_ARGS]);
111d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec
112e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
113e7632cfaSRichard Henderson                             TCGReg dst, TCGReg src);
114d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
115d6ecb4a9SRichard Henderson                              TCGReg dst, TCGReg base, intptr_t offset);
1164e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1174e186175SRichard Henderson                              TCGReg dst, int64_t arg);
1185e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1195e8892dbSMiroslav Rezanina                            unsigned vecl, unsigned vece,
1205e8892dbSMiroslav Rezanina                            const TCGArg args[TCG_MAX_OP_ARGS],
1215e8892dbSMiroslav Rezanina                            const int const_args[TCG_MAX_OP_ARGS]);
122d2fd745fSRichard Henderson #else
123e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
124e7632cfaSRichard Henderson                                    TCGReg dst, TCGReg src)
125e7632cfaSRichard Henderson {
126e7632cfaSRichard Henderson     g_assert_not_reached();
127e7632cfaSRichard Henderson }
128d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
129d6ecb4a9SRichard Henderson                                     TCGReg dst, TCGReg base, intptr_t offset)
130d6ecb4a9SRichard Henderson {
131d6ecb4a9SRichard Henderson     g_assert_not_reached();
132d6ecb4a9SRichard Henderson }
1334e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1344e186175SRichard Henderson                                     TCGReg dst, int64_t arg)
135e7632cfaSRichard Henderson {
136e7632cfaSRichard Henderson     g_assert_not_reached();
137e7632cfaSRichard Henderson }
1385e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1395e8892dbSMiroslav Rezanina                                   unsigned vecl, unsigned vece,
1405e8892dbSMiroslav Rezanina                                   const TCGArg args[TCG_MAX_OP_ARGS],
1415e8892dbSMiroslav Rezanina                                   const int const_args[TCG_MAX_OP_ARGS])
142d2fd745fSRichard Henderson {
143d2fd745fSRichard Henderson     g_assert_not_reached();
144d2fd745fSRichard Henderson }
145d2fd745fSRichard Henderson #endif
1462a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
147a05b5b9bSRichard Henderson                        intptr_t arg2);
14859d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
14959d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
1502be7d76bSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target);
151a4fbbd77SRichard Henderson static bool tcg_target_const_match(int64_t val, TCGType type, int ct);
152659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
153aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s);
154659ef5cbSRichard Henderson #endif
155c896fe29Sbellard 
156a505785cSEmilio G. Cota #define TCG_HIGHWATER 1024
157a505785cSEmilio G. Cota 
158df2cce29SEmilio G. Cota static TCGContext **tcg_ctxs;
159df2cce29SEmilio G. Cota static unsigned int n_tcg_ctxs;
1601c2adb95SRichard Henderson TCGv_env cpu_env = 0;
161c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue;
162db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff;
163df2cce29SEmilio G. Cota 
164b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
165b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec;
166b91ccb31SRichard Henderson #endif
167b91ccb31SRichard Henderson 
168be2cdc5eSEmilio G. Cota struct tcg_region_tree {
169be2cdc5eSEmilio G. Cota     QemuMutex lock;
170be2cdc5eSEmilio G. Cota     GTree *tree;
171be2cdc5eSEmilio G. Cota     /* padding to avoid false sharing is computed at run-time */
172be2cdc5eSEmilio G. Cota };
173be2cdc5eSEmilio G. Cota 
174e8feb96fSEmilio G. Cota /*
175e8feb96fSEmilio G. Cota  * We divide code_gen_buffer into equally-sized "regions" that TCG threads
176e8feb96fSEmilio G. Cota  * dynamically allocate from as demand dictates. Given appropriate region
177e8feb96fSEmilio G. Cota  * sizing, this minimizes flushes even when some TCG threads generate a lot
178e8feb96fSEmilio G. Cota  * more code than others.
179e8feb96fSEmilio G. Cota  */
180e8feb96fSEmilio G. Cota struct tcg_region_state {
181e8feb96fSEmilio G. Cota     QemuMutex lock;
182e8feb96fSEmilio G. Cota 
183e8feb96fSEmilio G. Cota     /* fields set at init time */
184e8feb96fSEmilio G. Cota     void *start;
185e8feb96fSEmilio G. Cota     void *start_aligned;
186e8feb96fSEmilio G. Cota     void *end;
187e8feb96fSEmilio G. Cota     size_t n;
188e8feb96fSEmilio G. Cota     size_t size; /* size of one region */
189e8feb96fSEmilio G. Cota     size_t stride; /* .size + guard size */
190e8feb96fSEmilio G. Cota 
191e8feb96fSEmilio G. Cota     /* fields protected by the lock */
192e8feb96fSEmilio G. Cota     size_t current; /* current region index */
193e8feb96fSEmilio G. Cota     size_t agg_size_full; /* aggregate size of full regions */
194e8feb96fSEmilio G. Cota };
195e8feb96fSEmilio G. Cota 
196e8feb96fSEmilio G. Cota static struct tcg_region_state region;
197be2cdc5eSEmilio G. Cota /*
198be2cdc5eSEmilio G. Cota  * This is an array of struct tcg_region_tree's, with padding.
199be2cdc5eSEmilio G. Cota  * We use void * to simplify the computation of region_trees[i]; each
200be2cdc5eSEmilio G. Cota  * struct is found every tree_size bytes.
201be2cdc5eSEmilio G. Cota  */
202be2cdc5eSEmilio G. Cota static void *region_trees;
203be2cdc5eSEmilio G. Cota static size_t tree_size;
204d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
205b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
206c896fe29Sbellard 
2071813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
2084196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
209c896fe29Sbellard {
210c896fe29Sbellard     *s->code_ptr++ = v;
211c896fe29Sbellard }
212c896fe29Sbellard 
2134196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
2144196dca6SPeter Maydell                                                       uint8_t v)
2155c53bb81SPeter Maydell {
2161813e175SRichard Henderson     *p = v;
2175c53bb81SPeter Maydell }
2181813e175SRichard Henderson #endif
2195c53bb81SPeter Maydell 
2201813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
2214196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
222c896fe29Sbellard {
2231813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2241813e175SRichard Henderson         *s->code_ptr++ = v;
2251813e175SRichard Henderson     } else {
2261813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2274387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2281813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
2291813e175SRichard Henderson     }
230c896fe29Sbellard }
231c896fe29Sbellard 
2324196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2334196dca6SPeter Maydell                                                        uint16_t v)
2345c53bb81SPeter Maydell {
2351813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2361813e175SRichard Henderson         *p = v;
2371813e175SRichard Henderson     } else {
2385c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2395c53bb81SPeter Maydell     }
2401813e175SRichard Henderson }
2411813e175SRichard Henderson #endif
2425c53bb81SPeter Maydell 
2431813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
2444196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
245c896fe29Sbellard {
2461813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2471813e175SRichard Henderson         *s->code_ptr++ = v;
2481813e175SRichard Henderson     } else {
2491813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2504387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2511813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
2521813e175SRichard Henderson     }
253c896fe29Sbellard }
254c896fe29Sbellard 
2554196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
2564196dca6SPeter Maydell                                                        uint32_t v)
2575c53bb81SPeter Maydell {
2581813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2591813e175SRichard Henderson         *p = v;
2601813e175SRichard Henderson     } else {
2615c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2625c53bb81SPeter Maydell     }
2631813e175SRichard Henderson }
2641813e175SRichard Henderson #endif
2655c53bb81SPeter Maydell 
2661813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
2674196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
268ac26eb69SRichard Henderson {
2691813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2701813e175SRichard Henderson         *s->code_ptr++ = v;
2711813e175SRichard Henderson     } else {
2721813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2734387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2741813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
2751813e175SRichard Henderson     }
276ac26eb69SRichard Henderson }
277ac26eb69SRichard Henderson 
2784196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
2794196dca6SPeter Maydell                                                        uint64_t v)
2805c53bb81SPeter Maydell {
2811813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2821813e175SRichard Henderson         *p = v;
2831813e175SRichard Henderson     } else {
2845c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2855c53bb81SPeter Maydell     }
2861813e175SRichard Henderson }
2871813e175SRichard Henderson #endif
2885c53bb81SPeter Maydell 
289c896fe29Sbellard /* label relocation processing */
290c896fe29Sbellard 
2911813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
292bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
293c896fe29Sbellard {
2947ecd02a0SRichard Henderson     TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation));
295c896fe29Sbellard 
296c896fe29Sbellard     r->type = type;
297c896fe29Sbellard     r->ptr = code_ptr;
298c896fe29Sbellard     r->addend = addend;
2997ecd02a0SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
300c896fe29Sbellard }
301c896fe29Sbellard 
30292ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l)
303c896fe29Sbellard {
304eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
305c896fe29Sbellard     l->has_value = 1;
30692ab8e7dSRichard Henderson     l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr);
307c896fe29Sbellard }
308c896fe29Sbellard 
30942a268c2SRichard Henderson TCGLabel *gen_new_label(void)
310c896fe29Sbellard {
311b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
31251e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
313c896fe29Sbellard 
3147ecd02a0SRichard Henderson     memset(l, 0, sizeof(TCGLabel));
3157ecd02a0SRichard Henderson     l->id = s->nb_labels++;
3167ecd02a0SRichard Henderson     QSIMPLEQ_INIT(&l->relocs);
3177ecd02a0SRichard Henderson 
318bef16ab4SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
31942a268c2SRichard Henderson 
32042a268c2SRichard Henderson     return l;
321c896fe29Sbellard }
322c896fe29Sbellard 
3237ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s)
3247ecd02a0SRichard Henderson {
3257ecd02a0SRichard Henderson     TCGLabel *l;
3267ecd02a0SRichard Henderson 
3277ecd02a0SRichard Henderson     QSIMPLEQ_FOREACH(l, &s->labels, next) {
3287ecd02a0SRichard Henderson         TCGRelocation *r;
3297ecd02a0SRichard Henderson         uintptr_t value = l->u.value;
3307ecd02a0SRichard Henderson 
3317ecd02a0SRichard Henderson         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
3327ecd02a0SRichard Henderson             if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
3337ecd02a0SRichard Henderson                 return false;
3347ecd02a0SRichard Henderson             }
3357ecd02a0SRichard Henderson         }
3367ecd02a0SRichard Henderson     }
3377ecd02a0SRichard Henderson     return true;
3387ecd02a0SRichard Henderson }
3397ecd02a0SRichard Henderson 
3409f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3419f754620SRichard Henderson {
342f14bed3fSRichard Henderson     /*
343f14bed3fSRichard Henderson      * We will check for overflow at the end of the opcode loop in
344f14bed3fSRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
345f14bed3fSRichard Henderson      */
346f14bed3fSRichard Henderson     s->tb_jmp_reset_offset[which] = tcg_current_code_size(s);
3479f754620SRichard Henderson }
3489f754620SRichard Henderson 
349db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */
350db6b7d0cSRichard Henderson static void QEMU_NORETURN tcg_raise_tb_overflow(TCGContext *s)
351db6b7d0cSRichard Henderson {
352db6b7d0cSRichard Henderson     siglongjmp(s->jmp_trans, -2);
353db6b7d0cSRichard Henderson }
354db6b7d0cSRichard Henderson 
3554c22e840SRichard Henderson #define C_PFX1(P, A)                    P##A
3564c22e840SRichard Henderson #define C_PFX2(P, A, B)                 P##A##_##B
3574c22e840SRichard Henderson #define C_PFX3(P, A, B, C)              P##A##_##B##_##C
3584c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D)           P##A##_##B##_##C##_##D
3594c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E)        P##A##_##B##_##C##_##D##_##E
3604c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F)     P##A##_##B##_##C##_##D##_##E##_##F
3614c22e840SRichard Henderson 
3624c22e840SRichard Henderson /* Define an enumeration for the various combinations. */
3634c22e840SRichard Henderson 
3644c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1),
3654c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2),
3664c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3),
3674c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4),
3684c22e840SRichard Henderson 
3694c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1),
3704c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2),
3714c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3),
3724c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4),
3734c22e840SRichard Henderson 
3744c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2),
3754c22e840SRichard Henderson 
3764c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1),
3774c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2),
3784c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3),
3794c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4),
3804c22e840SRichard Henderson 
3814c22e840SRichard Henderson typedef enum {
3824c22e840SRichard Henderson #include "tcg-target-con-set.h"
3834c22e840SRichard Henderson } TCGConstraintSetIndex;
3844c22e840SRichard Henderson 
3854c22e840SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode);
3864c22e840SRichard Henderson 
3874c22e840SRichard Henderson #undef C_O0_I1
3884c22e840SRichard Henderson #undef C_O0_I2
3894c22e840SRichard Henderson #undef C_O0_I3
3904c22e840SRichard Henderson #undef C_O0_I4
3914c22e840SRichard Henderson #undef C_O1_I1
3924c22e840SRichard Henderson #undef C_O1_I2
3934c22e840SRichard Henderson #undef C_O1_I3
3944c22e840SRichard Henderson #undef C_O1_I4
3954c22e840SRichard Henderson #undef C_N1_I2
3964c22e840SRichard Henderson #undef C_O2_I1
3974c22e840SRichard Henderson #undef C_O2_I2
3984c22e840SRichard Henderson #undef C_O2_I3
3994c22e840SRichard Henderson #undef C_O2_I4
4004c22e840SRichard Henderson 
4014c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */
4024c22e840SRichard Henderson 
4034c22e840SRichard Henderson #define C_O0_I1(I1)                     { .args_ct_str = { #I1 } },
4044c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 { .args_ct_str = { #I1, #I2 } },
4054c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             { .args_ct_str = { #I1, #I2, #I3 } },
4064c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         { .args_ct_str = { #I1, #I2, #I3, #I4 } },
4074c22e840SRichard Henderson 
4084c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 { .args_ct_str = { #O1, #I1 } },
4094c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             { .args_ct_str = { #O1, #I1, #I2 } },
4104c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         { .args_ct_str = { #O1, #I1, #I2, #I3 } },
4114c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } },
4124c22e840SRichard Henderson 
4134c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             { .args_ct_str = { "&" #O1, #I1, #I2 } },
4144c22e840SRichard Henderson 
4154c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             { .args_ct_str = { #O1, #O2, #I1 } },
4164c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         { .args_ct_str = { #O1, #O2, #I1, #I2 } },
4174c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } },
4184c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } },
4194c22e840SRichard Henderson 
4204c22e840SRichard Henderson static const TCGTargetOpDef constraint_sets[] = {
4214c22e840SRichard Henderson #include "tcg-target-con-set.h"
4224c22e840SRichard Henderson };
4234c22e840SRichard Henderson 
4244c22e840SRichard Henderson 
4254c22e840SRichard Henderson #undef C_O0_I1
4264c22e840SRichard Henderson #undef C_O0_I2
4274c22e840SRichard Henderson #undef C_O0_I3
4284c22e840SRichard Henderson #undef C_O0_I4
4294c22e840SRichard Henderson #undef C_O1_I1
4304c22e840SRichard Henderson #undef C_O1_I2
4314c22e840SRichard Henderson #undef C_O1_I3
4324c22e840SRichard Henderson #undef C_O1_I4
4334c22e840SRichard Henderson #undef C_N1_I2
4344c22e840SRichard Henderson #undef C_O2_I1
4354c22e840SRichard Henderson #undef C_O2_I2
4364c22e840SRichard Henderson #undef C_O2_I3
4374c22e840SRichard Henderson #undef C_O2_I4
4384c22e840SRichard Henderson 
4394c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */
4404c22e840SRichard Henderson 
4414c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1)
4424c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2)
4434c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3)
4444c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4)
4454c22e840SRichard Henderson 
4464c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1)
4474c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2)
4484c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3)
4494c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4)
4504c22e840SRichard Henderson 
4514c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2)
4524c22e840SRichard Henderson 
4534c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1)
4544c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2)
4554c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3)
4564c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4)
4574c22e840SRichard Henderson 
458139c1837SPaolo Bonzini #include "tcg-target.c.inc"
459c896fe29Sbellard 
460be2cdc5eSEmilio G. Cota /* compare a pointer @ptr and a tb_tc @s */
461be2cdc5eSEmilio G. Cota static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s)
462be2cdc5eSEmilio G. Cota {
463be2cdc5eSEmilio G. Cota     if (ptr >= s->ptr + s->size) {
464be2cdc5eSEmilio G. Cota         return 1;
465be2cdc5eSEmilio G. Cota     } else if (ptr < s->ptr) {
466be2cdc5eSEmilio G. Cota         return -1;
467be2cdc5eSEmilio G. Cota     }
468be2cdc5eSEmilio G. Cota     return 0;
469be2cdc5eSEmilio G. Cota }
470be2cdc5eSEmilio G. Cota 
471be2cdc5eSEmilio G. Cota static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp)
472be2cdc5eSEmilio G. Cota {
473be2cdc5eSEmilio G. Cota     const struct tb_tc *a = ap;
474be2cdc5eSEmilio G. Cota     const struct tb_tc *b = bp;
475be2cdc5eSEmilio G. Cota 
476be2cdc5eSEmilio G. Cota     /*
477be2cdc5eSEmilio G. Cota      * When both sizes are set, we know this isn't a lookup.
478be2cdc5eSEmilio G. Cota      * This is the most likely case: every TB must be inserted; lookups
479be2cdc5eSEmilio G. Cota      * are a lot less frequent.
480be2cdc5eSEmilio G. Cota      */
481be2cdc5eSEmilio G. Cota     if (likely(a->size && b->size)) {
482be2cdc5eSEmilio G. Cota         if (a->ptr > b->ptr) {
483be2cdc5eSEmilio G. Cota             return 1;
484be2cdc5eSEmilio G. Cota         } else if (a->ptr < b->ptr) {
485be2cdc5eSEmilio G. Cota             return -1;
486be2cdc5eSEmilio G. Cota         }
487be2cdc5eSEmilio G. Cota         /* a->ptr == b->ptr should happen only on deletions */
488be2cdc5eSEmilio G. Cota         g_assert(a->size == b->size);
489be2cdc5eSEmilio G. Cota         return 0;
490be2cdc5eSEmilio G. Cota     }
491be2cdc5eSEmilio G. Cota     /*
492be2cdc5eSEmilio G. Cota      * All lookups have either .size field set to 0.
493be2cdc5eSEmilio G. Cota      * From the glib sources we see that @ap is always the lookup key. However
494be2cdc5eSEmilio G. Cota      * the docs provide no guarantee, so we just mark this case as likely.
495be2cdc5eSEmilio G. Cota      */
496be2cdc5eSEmilio G. Cota     if (likely(a->size == 0)) {
497be2cdc5eSEmilio G. Cota         return ptr_cmp_tb_tc(a->ptr, b);
498be2cdc5eSEmilio G. Cota     }
499be2cdc5eSEmilio G. Cota     return ptr_cmp_tb_tc(b->ptr, a);
500be2cdc5eSEmilio G. Cota }
501be2cdc5eSEmilio G. Cota 
502be2cdc5eSEmilio G. Cota static void tcg_region_trees_init(void)
503be2cdc5eSEmilio G. Cota {
504be2cdc5eSEmilio G. Cota     size_t i;
505be2cdc5eSEmilio G. Cota 
506be2cdc5eSEmilio G. Cota     tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize);
507be2cdc5eSEmilio G. Cota     region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size);
508be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
509be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
510be2cdc5eSEmilio G. Cota 
511be2cdc5eSEmilio G. Cota         qemu_mutex_init(&rt->lock);
512be2cdc5eSEmilio G. Cota         rt->tree = g_tree_new(tb_tc_cmp);
513be2cdc5eSEmilio G. Cota     }
514be2cdc5eSEmilio G. Cota }
515be2cdc5eSEmilio G. Cota 
5160610067eSRichard Henderson static struct tcg_region_tree *tc_ptr_to_region_tree(const void *p)
517be2cdc5eSEmilio G. Cota {
518be2cdc5eSEmilio G. Cota     size_t region_idx;
519be2cdc5eSEmilio G. Cota 
5200610067eSRichard Henderson     /*
5210610067eSRichard Henderson      * Like tcg_splitwx_to_rw, with no assert.  The pc may come from
5220610067eSRichard Henderson      * a signal handler over which the caller has no control.
5230610067eSRichard Henderson      */
5240610067eSRichard Henderson     if (!in_code_gen_buffer(p)) {
5250610067eSRichard Henderson         p -= tcg_splitwx_diff;
5260610067eSRichard Henderson         if (!in_code_gen_buffer(p)) {
5270610067eSRichard Henderson             return NULL;
5280610067eSRichard Henderson         }
5290610067eSRichard Henderson     }
5300610067eSRichard Henderson 
531be2cdc5eSEmilio G. Cota     if (p < region.start_aligned) {
532be2cdc5eSEmilio G. Cota         region_idx = 0;
533be2cdc5eSEmilio G. Cota     } else {
534be2cdc5eSEmilio G. Cota         ptrdiff_t offset = p - region.start_aligned;
535be2cdc5eSEmilio G. Cota 
536be2cdc5eSEmilio G. Cota         if (offset > region.stride * (region.n - 1)) {
537be2cdc5eSEmilio G. Cota             region_idx = region.n - 1;
538be2cdc5eSEmilio G. Cota         } else {
539be2cdc5eSEmilio G. Cota             region_idx = offset / region.stride;
540be2cdc5eSEmilio G. Cota         }
541be2cdc5eSEmilio G. Cota     }
542be2cdc5eSEmilio G. Cota     return region_trees + region_idx * tree_size;
543be2cdc5eSEmilio G. Cota }
544be2cdc5eSEmilio G. Cota 
545be2cdc5eSEmilio G. Cota void tcg_tb_insert(TranslationBlock *tb)
546be2cdc5eSEmilio G. Cota {
547be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
548be2cdc5eSEmilio G. Cota 
5490610067eSRichard Henderson     g_assert(rt != NULL);
550be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
551be2cdc5eSEmilio G. Cota     g_tree_insert(rt->tree, &tb->tc, tb);
552be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
553be2cdc5eSEmilio G. Cota }
554be2cdc5eSEmilio G. Cota 
555be2cdc5eSEmilio G. Cota void tcg_tb_remove(TranslationBlock *tb)
556be2cdc5eSEmilio G. Cota {
557be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
558be2cdc5eSEmilio G. Cota 
5590610067eSRichard Henderson     g_assert(rt != NULL);
560be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
561be2cdc5eSEmilio G. Cota     g_tree_remove(rt->tree, &tb->tc);
562be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
563be2cdc5eSEmilio G. Cota }
564be2cdc5eSEmilio G. Cota 
565be2cdc5eSEmilio G. Cota /*
566be2cdc5eSEmilio G. Cota  * Find the TB 'tb' such that
567be2cdc5eSEmilio G. Cota  * tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size
568be2cdc5eSEmilio G. Cota  * Return NULL if not found.
569be2cdc5eSEmilio G. Cota  */
570be2cdc5eSEmilio G. Cota TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr)
571be2cdc5eSEmilio G. Cota {
572be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr);
573be2cdc5eSEmilio G. Cota     TranslationBlock *tb;
574be2cdc5eSEmilio G. Cota     struct tb_tc s = { .ptr = (void *)tc_ptr };
575be2cdc5eSEmilio G. Cota 
5760610067eSRichard Henderson     if (rt == NULL) {
5770610067eSRichard Henderson         return NULL;
5780610067eSRichard Henderson     }
5790610067eSRichard Henderson 
580be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
581be2cdc5eSEmilio G. Cota     tb = g_tree_lookup(rt->tree, &s);
582be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
583be2cdc5eSEmilio G. Cota     return tb;
584be2cdc5eSEmilio G. Cota }
585be2cdc5eSEmilio G. Cota 
586be2cdc5eSEmilio G. Cota static void tcg_region_tree_lock_all(void)
587be2cdc5eSEmilio G. Cota {
588be2cdc5eSEmilio G. Cota     size_t i;
589be2cdc5eSEmilio G. Cota 
590be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
591be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
592be2cdc5eSEmilio G. Cota 
593be2cdc5eSEmilio G. Cota         qemu_mutex_lock(&rt->lock);
594be2cdc5eSEmilio G. Cota     }
595be2cdc5eSEmilio G. Cota }
596be2cdc5eSEmilio G. Cota 
597be2cdc5eSEmilio G. Cota static void tcg_region_tree_unlock_all(void)
598be2cdc5eSEmilio G. Cota {
599be2cdc5eSEmilio G. Cota     size_t i;
600be2cdc5eSEmilio G. Cota 
601be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
602be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
603be2cdc5eSEmilio G. Cota 
604be2cdc5eSEmilio G. Cota         qemu_mutex_unlock(&rt->lock);
605be2cdc5eSEmilio G. Cota     }
606be2cdc5eSEmilio G. Cota }
607be2cdc5eSEmilio G. Cota 
608be2cdc5eSEmilio G. Cota void tcg_tb_foreach(GTraverseFunc func, gpointer user_data)
609be2cdc5eSEmilio G. Cota {
610be2cdc5eSEmilio G. Cota     size_t i;
611be2cdc5eSEmilio G. Cota 
612be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
613be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
614be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
615be2cdc5eSEmilio G. Cota 
616be2cdc5eSEmilio G. Cota         g_tree_foreach(rt->tree, func, user_data);
617be2cdc5eSEmilio G. Cota     }
618be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
619be2cdc5eSEmilio G. Cota }
620be2cdc5eSEmilio G. Cota 
621be2cdc5eSEmilio G. Cota size_t tcg_nb_tbs(void)
622be2cdc5eSEmilio G. Cota {
623be2cdc5eSEmilio G. Cota     size_t nb_tbs = 0;
624be2cdc5eSEmilio G. Cota     size_t i;
625be2cdc5eSEmilio G. Cota 
626be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
627be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
628be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
629be2cdc5eSEmilio G. Cota 
630be2cdc5eSEmilio G. Cota         nb_tbs += g_tree_nnodes(rt->tree);
631be2cdc5eSEmilio G. Cota     }
632be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
633be2cdc5eSEmilio G. Cota     return nb_tbs;
634be2cdc5eSEmilio G. Cota }
635be2cdc5eSEmilio G. Cota 
636938e897aSEmilio G. Cota static gboolean tcg_region_tree_traverse(gpointer k, gpointer v, gpointer data)
637938e897aSEmilio G. Cota {
638938e897aSEmilio G. Cota     TranslationBlock *tb = v;
639938e897aSEmilio G. Cota 
640938e897aSEmilio G. Cota     tb_destroy(tb);
641938e897aSEmilio G. Cota     return FALSE;
642938e897aSEmilio G. Cota }
643938e897aSEmilio G. Cota 
644be2cdc5eSEmilio G. Cota static void tcg_region_tree_reset_all(void)
645be2cdc5eSEmilio G. Cota {
646be2cdc5eSEmilio G. Cota     size_t i;
647be2cdc5eSEmilio G. Cota 
648be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
649be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
650be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
651be2cdc5eSEmilio G. Cota 
652938e897aSEmilio G. Cota         g_tree_foreach(rt->tree, tcg_region_tree_traverse, NULL);
653be2cdc5eSEmilio G. Cota         /* Increment the refcount first so that destroy acts as a reset */
654be2cdc5eSEmilio G. Cota         g_tree_ref(rt->tree);
655be2cdc5eSEmilio G. Cota         g_tree_destroy(rt->tree);
656be2cdc5eSEmilio G. Cota     }
657be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
658be2cdc5eSEmilio G. Cota }
659be2cdc5eSEmilio G. Cota 
660e8feb96fSEmilio G. Cota static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend)
661e8feb96fSEmilio G. Cota {
662e8feb96fSEmilio G. Cota     void *start, *end;
663e8feb96fSEmilio G. Cota 
664e8feb96fSEmilio G. Cota     start = region.start_aligned + curr_region * region.stride;
665e8feb96fSEmilio G. Cota     end = start + region.size;
666e8feb96fSEmilio G. Cota 
667e8feb96fSEmilio G. Cota     if (curr_region == 0) {
668e8feb96fSEmilio G. Cota         start = region.start;
669e8feb96fSEmilio G. Cota     }
670e8feb96fSEmilio G. Cota     if (curr_region == region.n - 1) {
671e8feb96fSEmilio G. Cota         end = region.end;
672e8feb96fSEmilio G. Cota     }
673e8feb96fSEmilio G. Cota 
674e8feb96fSEmilio G. Cota     *pstart = start;
675e8feb96fSEmilio G. Cota     *pend = end;
676e8feb96fSEmilio G. Cota }
677e8feb96fSEmilio G. Cota 
678e8feb96fSEmilio G. Cota static void tcg_region_assign(TCGContext *s, size_t curr_region)
679e8feb96fSEmilio G. Cota {
680e8feb96fSEmilio G. Cota     void *start, *end;
681e8feb96fSEmilio G. Cota 
682e8feb96fSEmilio G. Cota     tcg_region_bounds(curr_region, &start, &end);
683e8feb96fSEmilio G. Cota 
684e8feb96fSEmilio G. Cota     s->code_gen_buffer = start;
685e8feb96fSEmilio G. Cota     s->code_gen_ptr = start;
686e8feb96fSEmilio G. Cota     s->code_gen_buffer_size = end - start;
687e8feb96fSEmilio G. Cota     s->code_gen_highwater = end - TCG_HIGHWATER;
688e8feb96fSEmilio G. Cota }
689e8feb96fSEmilio G. Cota 
690e8feb96fSEmilio G. Cota static bool tcg_region_alloc__locked(TCGContext *s)
691e8feb96fSEmilio G. Cota {
692e8feb96fSEmilio G. Cota     if (region.current == region.n) {
693e8feb96fSEmilio G. Cota         return true;
694e8feb96fSEmilio G. Cota     }
695e8feb96fSEmilio G. Cota     tcg_region_assign(s, region.current);
696e8feb96fSEmilio G. Cota     region.current++;
697e8feb96fSEmilio G. Cota     return false;
698e8feb96fSEmilio G. Cota }
699e8feb96fSEmilio G. Cota 
700e8feb96fSEmilio G. Cota /*
701e8feb96fSEmilio G. Cota  * Request a new region once the one in use has filled up.
702e8feb96fSEmilio G. Cota  * Returns true on error.
703e8feb96fSEmilio G. Cota  */
704e8feb96fSEmilio G. Cota static bool tcg_region_alloc(TCGContext *s)
705e8feb96fSEmilio G. Cota {
706e8feb96fSEmilio G. Cota     bool err;
707e8feb96fSEmilio G. Cota     /* read the region size now; alloc__locked will overwrite it on success */
708e8feb96fSEmilio G. Cota     size_t size_full = s->code_gen_buffer_size;
709e8feb96fSEmilio G. Cota 
710e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
711e8feb96fSEmilio G. Cota     err = tcg_region_alloc__locked(s);
712e8feb96fSEmilio G. Cota     if (!err) {
713e8feb96fSEmilio G. Cota         region.agg_size_full += size_full - TCG_HIGHWATER;
714e8feb96fSEmilio G. Cota     }
715e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
716e8feb96fSEmilio G. Cota     return err;
717e8feb96fSEmilio G. Cota }
718e8feb96fSEmilio G. Cota 
719e8feb96fSEmilio G. Cota /*
720e8feb96fSEmilio G. Cota  * Perform a context's first region allocation.
721e8feb96fSEmilio G. Cota  * This function does _not_ increment region.agg_size_full.
722e8feb96fSEmilio G. Cota  */
723e8feb96fSEmilio G. Cota static inline bool tcg_region_initial_alloc__locked(TCGContext *s)
724e8feb96fSEmilio G. Cota {
725e8feb96fSEmilio G. Cota     return tcg_region_alloc__locked(s);
726e8feb96fSEmilio G. Cota }
727e8feb96fSEmilio G. Cota 
728e8feb96fSEmilio G. Cota /* Call from a safe-work context */
729e8feb96fSEmilio G. Cota void tcg_region_reset_all(void)
730e8feb96fSEmilio G. Cota {
731d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
732e8feb96fSEmilio G. Cota     unsigned int i;
733e8feb96fSEmilio G. Cota 
734e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
735e8feb96fSEmilio G. Cota     region.current = 0;
736e8feb96fSEmilio G. Cota     region.agg_size_full = 0;
737e8feb96fSEmilio G. Cota 
7383468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
739d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
7403468b59eSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(s);
741e8feb96fSEmilio G. Cota 
742e8feb96fSEmilio G. Cota         g_assert(!err);
743e8feb96fSEmilio G. Cota     }
744e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
745be2cdc5eSEmilio G. Cota 
746be2cdc5eSEmilio G. Cota     tcg_region_tree_reset_all();
747e8feb96fSEmilio G. Cota }
748e8feb96fSEmilio G. Cota 
7493468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
7503468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
7513468b59eSEmilio G. Cota {
7523468b59eSEmilio G. Cota     return 1;
7533468b59eSEmilio G. Cota }
7543468b59eSEmilio G. Cota #else
7553468b59eSEmilio G. Cota /*
7563468b59eSEmilio G. Cota  * It is likely that some vCPUs will translate more code than others, so we
7573468b59eSEmilio G. Cota  * first try to set more regions than max_cpus, with those regions being of
7583468b59eSEmilio G. Cota  * reasonable size. If that's not possible we make do by evenly dividing
7593468b59eSEmilio G. Cota  * the code_gen_buffer among the vCPUs.
7603468b59eSEmilio G. Cota  */
7613468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
7623468b59eSEmilio G. Cota {
7633468b59eSEmilio G. Cota     size_t i;
7643468b59eSEmilio G. Cota 
7653468b59eSEmilio G. Cota     /* Use a single region if all we have is one vCPU thread */
7665cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY)
7675cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
7685cc8767dSLike Xu     unsigned int max_cpus = ms->smp.max_cpus;
7695cc8767dSLike Xu #endif
7703468b59eSEmilio G. Cota     if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) {
7713468b59eSEmilio G. Cota         return 1;
7723468b59eSEmilio G. Cota     }
7733468b59eSEmilio G. Cota 
7743468b59eSEmilio G. Cota     /* Try to have more regions than max_cpus, with each region being >= 2 MB */
7753468b59eSEmilio G. Cota     for (i = 8; i > 0; i--) {
7763468b59eSEmilio G. Cota         size_t regions_per_thread = i;
7773468b59eSEmilio G. Cota         size_t region_size;
7783468b59eSEmilio G. Cota 
7793468b59eSEmilio G. Cota         region_size = tcg_init_ctx.code_gen_buffer_size;
7803468b59eSEmilio G. Cota         region_size /= max_cpus * regions_per_thread;
7813468b59eSEmilio G. Cota 
7823468b59eSEmilio G. Cota         if (region_size >= 2 * 1024u * 1024) {
7833468b59eSEmilio G. Cota             return max_cpus * regions_per_thread;
7843468b59eSEmilio G. Cota         }
7853468b59eSEmilio G. Cota     }
7863468b59eSEmilio G. Cota     /* If we can't, then just allocate one region per vCPU thread */
7873468b59eSEmilio G. Cota     return max_cpus;
7883468b59eSEmilio G. Cota }
7893468b59eSEmilio G. Cota #endif
7903468b59eSEmilio G. Cota 
791e8feb96fSEmilio G. Cota /*
792e8feb96fSEmilio G. Cota  * Initializes region partitioning.
793e8feb96fSEmilio G. Cota  *
794e8feb96fSEmilio G. Cota  * Called at init time from the parent thread (i.e. the one calling
795e8feb96fSEmilio G. Cota  * tcg_context_init), after the target's TCG globals have been set.
7963468b59eSEmilio G. Cota  *
7973468b59eSEmilio G. Cota  * Region partitioning works by splitting code_gen_buffer into separate regions,
7983468b59eSEmilio G. Cota  * and then assigning regions to TCG threads so that the threads can translate
7993468b59eSEmilio G. Cota  * code in parallel without synchronization.
8003468b59eSEmilio G. Cota  *
8013468b59eSEmilio G. Cota  * In softmmu the number of TCG threads is bounded by max_cpus, so we use at
8023468b59eSEmilio G. Cota  * least max_cpus regions in MTTCG. In !MTTCG we use a single region.
8033468b59eSEmilio G. Cota  * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...])
8043468b59eSEmilio G. Cota  * must have been parsed before calling this function, since it calls
8053468b59eSEmilio G. Cota  * qemu_tcg_mttcg_enabled().
8063468b59eSEmilio G. Cota  *
8073468b59eSEmilio G. Cota  * In user-mode we use a single region.  Having multiple regions in user-mode
8083468b59eSEmilio G. Cota  * is not supported, because the number of vCPU threads (recall that each thread
8093468b59eSEmilio G. Cota  * spawned by the guest corresponds to a vCPU thread) is only bounded by the
8103468b59eSEmilio G. Cota  * OS, and usually this number is huge (tens of thousands is not uncommon).
8113468b59eSEmilio G. Cota  * Thus, given this large bound on the number of vCPU threads and the fact
8123468b59eSEmilio G. Cota  * that code_gen_buffer is allocated at compile-time, we cannot guarantee
8133468b59eSEmilio G. Cota  * that the availability of at least one region per vCPU thread.
8143468b59eSEmilio G. Cota  *
8153468b59eSEmilio G. Cota  * However, this user-mode limitation is unlikely to be a significant problem
8163468b59eSEmilio G. Cota  * in practice. Multi-threaded guests share most if not all of their translated
8173468b59eSEmilio G. Cota  * code, which makes parallel code generation less appealing than in softmmu.
818e8feb96fSEmilio G. Cota  */
819e8feb96fSEmilio G. Cota void tcg_region_init(void)
820e8feb96fSEmilio G. Cota {
821e8feb96fSEmilio G. Cota     void *buf = tcg_init_ctx.code_gen_buffer;
822e8feb96fSEmilio G. Cota     void *aligned;
823e8feb96fSEmilio G. Cota     size_t size = tcg_init_ctx.code_gen_buffer_size;
824e8feb96fSEmilio G. Cota     size_t page_size = qemu_real_host_page_size;
825e8feb96fSEmilio G. Cota     size_t region_size;
826e8feb96fSEmilio G. Cota     size_t n_regions;
827e8feb96fSEmilio G. Cota     size_t i;
828e8feb96fSEmilio G. Cota 
8293468b59eSEmilio G. Cota     n_regions = tcg_n_regions();
830e8feb96fSEmilio G. Cota 
831e8feb96fSEmilio G. Cota     /* The first region will be 'aligned - buf' bytes larger than the others */
832e8feb96fSEmilio G. Cota     aligned = QEMU_ALIGN_PTR_UP(buf, page_size);
833e8feb96fSEmilio G. Cota     g_assert(aligned < tcg_init_ctx.code_gen_buffer + size);
834e8feb96fSEmilio G. Cota     /*
835e8feb96fSEmilio G. Cota      * Make region_size a multiple of page_size, using aligned as the start.
836e8feb96fSEmilio G. Cota      * As a result of this we might end up with a few extra pages at the end of
837e8feb96fSEmilio G. Cota      * the buffer; we will assign those to the last region.
838e8feb96fSEmilio G. Cota      */
839e8feb96fSEmilio G. Cota     region_size = (size - (aligned - buf)) / n_regions;
840e8feb96fSEmilio G. Cota     region_size = QEMU_ALIGN_DOWN(region_size, page_size);
841e8feb96fSEmilio G. Cota 
842e8feb96fSEmilio G. Cota     /* A region must have at least 2 pages; one code, one guard */
843e8feb96fSEmilio G. Cota     g_assert(region_size >= 2 * page_size);
844e8feb96fSEmilio G. Cota 
845e8feb96fSEmilio G. Cota     /* init the region struct */
846e8feb96fSEmilio G. Cota     qemu_mutex_init(&region.lock);
847e8feb96fSEmilio G. Cota     region.n = n_regions;
848e8feb96fSEmilio G. Cota     region.size = region_size - page_size;
849e8feb96fSEmilio G. Cota     region.stride = region_size;
850e8feb96fSEmilio G. Cota     region.start = buf;
851e8feb96fSEmilio G. Cota     region.start_aligned = aligned;
852e8feb96fSEmilio G. Cota     /* page-align the end, since its last page will be a guard page */
853e8feb96fSEmilio G. Cota     region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size);
854e8feb96fSEmilio G. Cota     /* account for that last guard page */
855e8feb96fSEmilio G. Cota     region.end -= page_size;
856e8feb96fSEmilio G. Cota 
85715c4e8feSRichard Henderson     /*
85815c4e8feSRichard Henderson      * Set guard pages in the rw buffer, as that's the one into which
85915c4e8feSRichard Henderson      * buffer overruns could occur.  Do not set guard pages in the rx
86015c4e8feSRichard Henderson      * buffer -- let that one use hugepages throughout.
86115c4e8feSRichard Henderson      */
862e8feb96fSEmilio G. Cota     for (i = 0; i < region.n; i++) {
863e8feb96fSEmilio G. Cota         void *start, *end;
864e8feb96fSEmilio G. Cota 
865e8feb96fSEmilio G. Cota         tcg_region_bounds(i, &start, &end);
866c118881eSRichard Henderson 
867c118881eSRichard Henderson         /*
868c118881eSRichard Henderson          * macOS 11.2 has a bug (Apple Feedback FB8994773) in which mprotect
869c118881eSRichard Henderson          * rejects a permission change from RWX -> NONE.  Guard pages are
870c118881eSRichard Henderson          * nice for bug detection but are not essential; ignore any failure.
871c118881eSRichard Henderson          */
872c118881eSRichard Henderson         (void)qemu_mprotect_none(end, page_size);
873e8feb96fSEmilio G. Cota     }
874e8feb96fSEmilio G. Cota 
875be2cdc5eSEmilio G. Cota     tcg_region_trees_init();
876be2cdc5eSEmilio G. Cota 
8773468b59eSEmilio G. Cota     /* In user-mode we support only one ctx, so do the initial allocation now */
8783468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
879e8feb96fSEmilio G. Cota     {
880e8feb96fSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(tcg_ctx);
881e8feb96fSEmilio G. Cota 
882e8feb96fSEmilio G. Cota         g_assert(!err);
883e8feb96fSEmilio G. Cota     }
8843468b59eSEmilio G. Cota #endif
885e8feb96fSEmilio G. Cota }
886e8feb96fSEmilio G. Cota 
887db0c51a3SRichard Henderson #ifdef CONFIG_DEBUG_TCG
888db0c51a3SRichard Henderson const void *tcg_splitwx_to_rx(void *rw)
889db0c51a3SRichard Henderson {
890db0c51a3SRichard Henderson     /* Pass NULL pointers unchanged. */
891db0c51a3SRichard Henderson     if (rw) {
892db0c51a3SRichard Henderson         g_assert(in_code_gen_buffer(rw));
893db0c51a3SRichard Henderson         rw += tcg_splitwx_diff;
894db0c51a3SRichard Henderson     }
895db0c51a3SRichard Henderson     return rw;
896db0c51a3SRichard Henderson }
897db0c51a3SRichard Henderson 
898db0c51a3SRichard Henderson void *tcg_splitwx_to_rw(const void *rx)
899db0c51a3SRichard Henderson {
900db0c51a3SRichard Henderson     /* Pass NULL pointers unchanged. */
901db0c51a3SRichard Henderson     if (rx) {
902db0c51a3SRichard Henderson         rx -= tcg_splitwx_diff;
903db0c51a3SRichard Henderson         /* Assert that we end with a pointer in the rw region. */
904db0c51a3SRichard Henderson         g_assert(in_code_gen_buffer(rx));
905db0c51a3SRichard Henderson     }
906db0c51a3SRichard Henderson     return (void *)rx;
907db0c51a3SRichard Henderson }
908db0c51a3SRichard Henderson #endif /* CONFIG_DEBUG_TCG */
909db0c51a3SRichard Henderson 
91038b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s)
91138b47b19SEmilio G. Cota {
91238b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
91338b47b19SEmilio G. Cota     s->plugin_tb = g_new0(struct qemu_plugin_tb, 1);
91438b47b19SEmilio G. Cota     s->plugin_tb->insns =
91538b47b19SEmilio G. Cota         g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn);
91638b47b19SEmilio G. Cota #endif
91738b47b19SEmilio G. Cota }
91838b47b19SEmilio G. Cota 
919e8feb96fSEmilio G. Cota /*
9203468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
9213468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
9223468b59eSEmilio G. Cota  * before initiating translation.
9233468b59eSEmilio G. Cota  *
9243468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
9253468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
9263468b59eSEmilio G. Cota  *
9273468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
9283468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
9293468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
9303468b59eSEmilio G. Cota  *
9313468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
9323468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
9333468b59eSEmilio G. Cota  */
9343468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
9353468b59eSEmilio G. Cota void tcg_register_thread(void)
9363468b59eSEmilio G. Cota {
9373468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
9383468b59eSEmilio G. Cota }
9393468b59eSEmilio G. Cota #else
9403468b59eSEmilio G. Cota void tcg_register_thread(void)
9413468b59eSEmilio G. Cota {
9425cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
9433468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
9443468b59eSEmilio G. Cota     unsigned int i, n;
9453468b59eSEmilio G. Cota     bool err;
9463468b59eSEmilio G. Cota 
9473468b59eSEmilio G. Cota     *s = tcg_init_ctx;
9483468b59eSEmilio G. Cota 
9493468b59eSEmilio G. Cota     /* Relink mem_base.  */
9503468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
9513468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
9523468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
9533468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
9543468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
9553468b59eSEmilio G. Cota         }
9563468b59eSEmilio G. Cota     }
9573468b59eSEmilio G. Cota 
9583468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
959d73415a3SStefan Hajnoczi     n = qatomic_fetch_inc(&n_tcg_ctxs);
9605cc8767dSLike Xu     g_assert(n < ms->smp.max_cpus);
961d73415a3SStefan Hajnoczi     qatomic_set(&tcg_ctxs[n], s);
9623468b59eSEmilio G. Cota 
96338b47b19SEmilio G. Cota     if (n > 0) {
96438b47b19SEmilio G. Cota         alloc_tcg_plugin_context(s);
96538b47b19SEmilio G. Cota     }
96638b47b19SEmilio G. Cota 
9673468b59eSEmilio G. Cota     tcg_ctx = s;
9683468b59eSEmilio G. Cota     qemu_mutex_lock(&region.lock);
9693468b59eSEmilio G. Cota     err = tcg_region_initial_alloc__locked(tcg_ctx);
9703468b59eSEmilio G. Cota     g_assert(!err);
9713468b59eSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
9723468b59eSEmilio G. Cota }
9733468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
9743468b59eSEmilio G. Cota 
9753468b59eSEmilio G. Cota /*
976e8feb96fSEmilio G. Cota  * Returns the size (in bytes) of all translated code (i.e. from all regions)
977e8feb96fSEmilio G. Cota  * currently in the cache.
978e8feb96fSEmilio G. Cota  * See also: tcg_code_capacity()
979e8feb96fSEmilio G. Cota  * Do not confuse with tcg_current_code_size(); that one applies to a single
980e8feb96fSEmilio G. Cota  * TCG context.
981e8feb96fSEmilio G. Cota  */
982e8feb96fSEmilio G. Cota size_t tcg_code_size(void)
983e8feb96fSEmilio G. Cota {
984d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
985e8feb96fSEmilio G. Cota     unsigned int i;
986e8feb96fSEmilio G. Cota     size_t total;
987e8feb96fSEmilio G. Cota 
988e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
989e8feb96fSEmilio G. Cota     total = region.agg_size_full;
9903468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
991d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
992e8feb96fSEmilio G. Cota         size_t size;
993e8feb96fSEmilio G. Cota 
994d73415a3SStefan Hajnoczi         size = qatomic_read(&s->code_gen_ptr) - s->code_gen_buffer;
995e8feb96fSEmilio G. Cota         g_assert(size <= s->code_gen_buffer_size);
996e8feb96fSEmilio G. Cota         total += size;
997e8feb96fSEmilio G. Cota     }
998e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
999e8feb96fSEmilio G. Cota     return total;
1000e8feb96fSEmilio G. Cota }
1001e8feb96fSEmilio G. Cota 
1002e8feb96fSEmilio G. Cota /*
1003e8feb96fSEmilio G. Cota  * Returns the code capacity (in bytes) of the entire cache, i.e. including all
1004e8feb96fSEmilio G. Cota  * regions.
1005e8feb96fSEmilio G. Cota  * See also: tcg_code_size()
1006e8feb96fSEmilio G. Cota  */
1007e8feb96fSEmilio G. Cota size_t tcg_code_capacity(void)
1008e8feb96fSEmilio G. Cota {
1009e8feb96fSEmilio G. Cota     size_t guard_size, capacity;
1010e8feb96fSEmilio G. Cota 
1011e8feb96fSEmilio G. Cota     /* no need for synchronization; these variables are set at init time */
1012e8feb96fSEmilio G. Cota     guard_size = region.stride - region.size;
1013e8feb96fSEmilio G. Cota     capacity = region.end + guard_size - region.start;
1014e8feb96fSEmilio G. Cota     capacity -= region.n * (guard_size + TCG_HIGHWATER);
1015e8feb96fSEmilio G. Cota     return capacity;
1016e8feb96fSEmilio G. Cota }
1017e8feb96fSEmilio G. Cota 
1018128ed227SEmilio G. Cota size_t tcg_tb_phys_invalidate_count(void)
1019128ed227SEmilio G. Cota {
1020d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
1021128ed227SEmilio G. Cota     unsigned int i;
1022128ed227SEmilio G. Cota     size_t total = 0;
1023128ed227SEmilio G. Cota 
1024128ed227SEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
1025d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
1026128ed227SEmilio G. Cota 
1027d73415a3SStefan Hajnoczi         total += qatomic_read(&s->tb_phys_invalidate_count);
1028128ed227SEmilio G. Cota     }
1029128ed227SEmilio G. Cota     return total;
1030128ed227SEmilio G. Cota }
1031128ed227SEmilio G. Cota 
1032c896fe29Sbellard /* pool based memory allocation */
1033c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
1034c896fe29Sbellard {
1035c896fe29Sbellard     TCGPool *p;
1036c896fe29Sbellard     int pool_size;
1037c896fe29Sbellard 
1038c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
1039c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
10407267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
1041c896fe29Sbellard         p->size = size;
10424055299eSKirill Batuzov         p->next = s->pool_first_large;
10434055299eSKirill Batuzov         s->pool_first_large = p;
10444055299eSKirill Batuzov         return p->data;
1045c896fe29Sbellard     } else {
1046c896fe29Sbellard         p = s->pool_current;
1047c896fe29Sbellard         if (!p) {
1048c896fe29Sbellard             p = s->pool_first;
1049c896fe29Sbellard             if (!p)
1050c896fe29Sbellard                 goto new_pool;
1051c896fe29Sbellard         } else {
1052c896fe29Sbellard             if (!p->next) {
1053c896fe29Sbellard             new_pool:
1054c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
10557267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
1056c896fe29Sbellard                 p->size = pool_size;
1057c896fe29Sbellard                 p->next = NULL;
1058c896fe29Sbellard                 if (s->pool_current)
1059c896fe29Sbellard                     s->pool_current->next = p;
1060c896fe29Sbellard                 else
1061c896fe29Sbellard                     s->pool_first = p;
1062c896fe29Sbellard             } else {
1063c896fe29Sbellard                 p = p->next;
1064c896fe29Sbellard             }
1065c896fe29Sbellard         }
1066c896fe29Sbellard     }
1067c896fe29Sbellard     s->pool_current = p;
1068c896fe29Sbellard     s->pool_cur = p->data + size;
1069c896fe29Sbellard     s->pool_end = p->data + p->size;
1070c896fe29Sbellard     return p->data;
1071c896fe29Sbellard }
1072c896fe29Sbellard 
1073c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
1074c896fe29Sbellard {
10754055299eSKirill Batuzov     TCGPool *p, *t;
10764055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
10774055299eSKirill Batuzov         t = p->next;
10784055299eSKirill Batuzov         g_free(p);
10794055299eSKirill Batuzov     }
10804055299eSKirill Batuzov     s->pool_first_large = NULL;
1081c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
1082c896fe29Sbellard     s->pool_current = NULL;
1083c896fe29Sbellard }
1084c896fe29Sbellard 
1085100b5e01SRichard Henderson typedef struct TCGHelperInfo {
1086100b5e01SRichard Henderson     void *func;
1087100b5e01SRichard Henderson     const char *name;
1088afb49896SRichard Henderson     unsigned flags;
1089afb49896SRichard Henderson     unsigned sizemask;
1090100b5e01SRichard Henderson } TCGHelperInfo;
1091100b5e01SRichard Henderson 
10922ef6175aSRichard Henderson #include "exec/helper-proto.h"
10932ef6175aSRichard Henderson 
1094100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = {
10952ef6175aSRichard Henderson #include "exec/helper-tcg.h"
1096100b5e01SRichard Henderson };
1097619205fdSEmilio G. Cota static GHashTable *helper_table;
1098100b5e01SRichard Henderson 
109991478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
1100f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
11011c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
11021c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
110391478cefSRichard Henderson 
1104c896fe29Sbellard void tcg_context_init(TCGContext *s)
1105c896fe29Sbellard {
1106100b5e01SRichard Henderson     int op, total_args, n, i;
1107c896fe29Sbellard     TCGOpDef *def;
1108c896fe29Sbellard     TCGArgConstraint *args_ct;
11091c2adb95SRichard Henderson     TCGTemp *ts;
1110c896fe29Sbellard 
1111c896fe29Sbellard     memset(s, 0, sizeof(*s));
1112c896fe29Sbellard     s->nb_globals = 0;
1113c896fe29Sbellard 
1114c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
1115c896fe29Sbellard        space */
1116c896fe29Sbellard     total_args = 0;
1117c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
1118c896fe29Sbellard         def = &tcg_op_defs[op];
1119c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
1120c896fe29Sbellard         total_args += n;
1121c896fe29Sbellard     }
1122c896fe29Sbellard 
1123bc2b17e6SRichard Henderson     args_ct = g_new0(TCGArgConstraint, total_args);
1124c896fe29Sbellard 
1125c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
1126c896fe29Sbellard         def = &tcg_op_defs[op];
1127c896fe29Sbellard         def->args_ct = args_ct;
1128c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
1129c896fe29Sbellard         args_ct += n;
1130c896fe29Sbellard     }
1131c896fe29Sbellard 
11325cd8f621SRichard Henderson     /* Register helpers.  */
113384fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
1134619205fdSEmilio G. Cota     helper_table = g_hash_table_new(NULL, NULL);
113584fd9dd3SRichard Henderson 
1136100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
113784fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
113872866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
1139100b5e01SRichard Henderson     }
11405cd8f621SRichard Henderson 
1141c896fe29Sbellard     tcg_target_init(s);
1142f69d277eSRichard Henderson     process_op_defs(s);
114391478cefSRichard Henderson 
114491478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
114591478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
114691478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
114791478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
114891478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
114991478cefSRichard Henderson             break;
115091478cefSRichard Henderson         }
115191478cefSRichard Henderson     }
115291478cefSRichard Henderson     for (i = 0; i < n; ++i) {
115391478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
115491478cefSRichard Henderson     }
115591478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
115691478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
115791478cefSRichard Henderson     }
1158b1311c4aSEmilio G. Cota 
115938b47b19SEmilio G. Cota     alloc_tcg_plugin_context(s);
116038b47b19SEmilio G. Cota 
1161b1311c4aSEmilio G. Cota     tcg_ctx = s;
11623468b59eSEmilio G. Cota     /*
11633468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
11643468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
11653468b59eSEmilio G. Cota      * reasoning behind this.
11663468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
11673468b59eSEmilio G. Cota      */
11683468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
1169df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
1170df2cce29SEmilio G. Cota     n_tcg_ctxs = 1;
11713468b59eSEmilio G. Cota #else
11725cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
11735cc8767dSLike Xu     unsigned int max_cpus = ms->smp.max_cpus;
11743468b59eSEmilio G. Cota     tcg_ctxs = g_new(TCGContext *, max_cpus);
11753468b59eSEmilio G. Cota #endif
11761c2adb95SRichard Henderson 
11771c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
11781c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
11791c2adb95SRichard Henderson     cpu_env = temp_tcgv_ptr(ts);
11809002ec79SRichard Henderson }
1181b03cce8eSbellard 
11826e3b2bfdSEmilio G. Cota /*
11836e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
11846e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
11856e3b2bfdSEmilio G. Cota  */
11866e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
11876e3b2bfdSEmilio G. Cota {
11886e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
11896e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
11906e3b2bfdSEmilio G. Cota     void *next;
11916e3b2bfdSEmilio G. Cota 
1192e8feb96fSEmilio G. Cota  retry:
11936e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
11946e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
11956e3b2bfdSEmilio G. Cota 
11966e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
1197e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
11986e3b2bfdSEmilio G. Cota             return NULL;
11996e3b2bfdSEmilio G. Cota         }
1200e8feb96fSEmilio G. Cota         goto retry;
1201e8feb96fSEmilio G. Cota     }
1202d73415a3SStefan Hajnoczi     qatomic_set(&s->code_gen_ptr, next);
120357a26946SRichard Henderson     s->data_gen_ptr = NULL;
12046e3b2bfdSEmilio G. Cota     return tb;
12056e3b2bfdSEmilio G. Cota }
12066e3b2bfdSEmilio G. Cota 
12079002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
12089002ec79SRichard Henderson {
1209*b0a0794aSRichard Henderson     size_t prologue_size;
12108163b749SRichard Henderson 
12118163b749SRichard Henderson     /* Put the prologue at the beginning of code_gen_buffer.  */
1212*b0a0794aSRichard Henderson     tcg_region_assign(s, 0);
1213*b0a0794aSRichard Henderson     s->code_ptr = s->code_gen_ptr;
1214*b0a0794aSRichard Henderson     s->code_buf = s->code_gen_ptr;
12155b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
1216b91ccb31SRichard Henderson 
1217b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1218*b0a0794aSRichard Henderson     tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr);
1219b91ccb31SRichard Henderson #endif
12208163b749SRichard Henderson 
12215b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
12225b38ee31SRichard Henderson     s->pool_labels = NULL;
12235b38ee31SRichard Henderson #endif
12245b38ee31SRichard Henderson 
1225653b87ebSRoman Bolshakov     qemu_thread_jit_write();
12268163b749SRichard Henderson     /* Generate the prologue.  */
1227b03cce8eSbellard     tcg_target_qemu_prologue(s);
12285b38ee31SRichard Henderson 
12295b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
12305b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
12315b38ee31SRichard Henderson     {
12321768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
12331768987bSRichard Henderson         tcg_debug_assert(result == 0);
12345b38ee31SRichard Henderson     }
12355b38ee31SRichard Henderson #endif
12365b38ee31SRichard Henderson 
1237*b0a0794aSRichard Henderson     prologue_size = tcg_current_code_size(s);
1238*b0a0794aSRichard Henderson 
1239df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1240*b0a0794aSRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
1241*b0a0794aSRichard Henderson                         (uintptr_t)s->code_buf, prologue_size);
1242df5d2b16SRichard Henderson #endif
12438163b749SRichard Henderson 
1244*b0a0794aSRichard Henderson     /* Deduct the prologue from the first region.  */
1245*b0a0794aSRichard Henderson     region.start = s->code_ptr;
12468163b749SRichard Henderson 
1247*b0a0794aSRichard Henderson     /* Recompute boundaries of the first region. */
1248*b0a0794aSRichard Henderson     tcg_region_assign(s, 0);
1249*b0a0794aSRichard Henderson 
1250*b0a0794aSRichard Henderson     tcg_register_jit(tcg_splitwx_to_rx(region.start),
1251*b0a0794aSRichard Henderson                      region.end - region.start);
1252d6b64b2bSRichard Henderson 
1253d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
1254d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
1255fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
12568163b749SRichard Henderson         qemu_log("PROLOGUE: [size=%zu]\n", prologue_size);
12575b38ee31SRichard Henderson         if (s->data_gen_ptr) {
1258*b0a0794aSRichard Henderson             size_t code_size = s->data_gen_ptr - s->code_gen_ptr;
12595b38ee31SRichard Henderson             size_t data_size = prologue_size - code_size;
12605b38ee31SRichard Henderson             size_t i;
12615b38ee31SRichard Henderson 
1262*b0a0794aSRichard Henderson             log_disas(s->code_gen_ptr, code_size);
12635b38ee31SRichard Henderson 
12645b38ee31SRichard Henderson             for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
12655b38ee31SRichard Henderson                 if (sizeof(tcg_target_ulong) == 8) {
12665b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
12675b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
12685b38ee31SRichard Henderson                              *(uint64_t *)(s->data_gen_ptr + i));
12695b38ee31SRichard Henderson                 } else {
12705b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .long  0x%08x\n",
12715b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
12725b38ee31SRichard Henderson                              *(uint32_t *)(s->data_gen_ptr + i));
12735b38ee31SRichard Henderson                 }
12745b38ee31SRichard Henderson             }
12755b38ee31SRichard Henderson         } else {
1276*b0a0794aSRichard Henderson             log_disas(s->code_gen_ptr, prologue_size);
12775b38ee31SRichard Henderson         }
1278d6b64b2bSRichard Henderson         qemu_log("\n");
1279d6b64b2bSRichard Henderson         qemu_log_flush();
1280fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
1281d6b64b2bSRichard Henderson     }
1282d6b64b2bSRichard Henderson #endif
1283cedbcb01SEmilio G. Cota 
1284cedbcb01SEmilio G. Cota     /* Assert that goto_ptr is implemented completely.  */
1285cedbcb01SEmilio G. Cota     if (TCG_TARGET_HAS_goto_ptr) {
12868b5c2b62SRichard Henderson         tcg_debug_assert(tcg_code_gen_epilogue != NULL);
1287cedbcb01SEmilio G. Cota     }
1288c896fe29Sbellard }
1289c896fe29Sbellard 
1290c896fe29Sbellard void tcg_func_start(TCGContext *s)
1291c896fe29Sbellard {
1292c896fe29Sbellard     tcg_pool_reset(s);
1293c896fe29Sbellard     s->nb_temps = s->nb_globals;
12940ec9eabcSRichard Henderson 
12950ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
12960ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
12970ec9eabcSRichard Henderson 
1298c0522136SRichard Henderson     /* No constant temps have been previously allocated. */
1299c0522136SRichard Henderson     for (int i = 0; i < TCG_TYPE_COUNT; ++i) {
1300c0522136SRichard Henderson         if (s->const_table[i]) {
1301c0522136SRichard Henderson             g_hash_table_remove_all(s->const_table[i]);
1302c0522136SRichard Henderson         }
1303c0522136SRichard Henderson     }
1304c0522136SRichard Henderson 
1305abebf925SRichard Henderson     s->nb_ops = 0;
1306c896fe29Sbellard     s->nb_labels = 0;
1307c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1308c896fe29Sbellard 
13090a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
13100a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
13110a209d4bSRichard Henderson #endif
13120a209d4bSRichard Henderson 
131315fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
131415fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
1315bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
1316c896fe29Sbellard }
1317c896fe29Sbellard 
1318ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s)
13197ca4b752SRichard Henderson {
13207ca4b752SRichard Henderson     int n = s->nb_temps++;
1321ae30e866SRichard Henderson 
1322ae30e866SRichard Henderson     if (n >= TCG_MAX_TEMPS) {
1323db6b7d0cSRichard Henderson         tcg_raise_tb_overflow(s);
1324ae30e866SRichard Henderson     }
13257ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
13267ca4b752SRichard Henderson }
13277ca4b752SRichard Henderson 
1328ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s)
13297ca4b752SRichard Henderson {
1330fa477d25SRichard Henderson     TCGTemp *ts;
1331fa477d25SRichard Henderson 
13327ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
1333ae30e866SRichard Henderson     tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS);
13347ca4b752SRichard Henderson     s->nb_globals++;
1335fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1336ee17db83SRichard Henderson     ts->kind = TEMP_GLOBAL;
1337fa477d25SRichard Henderson 
1338fa477d25SRichard Henderson     return ts;
1339c896fe29Sbellard }
1340c896fe29Sbellard 
1341085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1342b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1343c896fe29Sbellard {
1344c896fe29Sbellard     TCGTemp *ts;
1345c896fe29Sbellard 
1346b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
1347c896fe29Sbellard         tcg_abort();
1348b3a62939SRichard Henderson     }
13497ca4b752SRichard Henderson 
13507ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1351c896fe29Sbellard     ts->base_type = type;
1352c896fe29Sbellard     ts->type = type;
1353ee17db83SRichard Henderson     ts->kind = TEMP_FIXED;
1354c896fe29Sbellard     ts->reg = reg;
1355c896fe29Sbellard     ts->name = name;
1356c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
13577ca4b752SRichard Henderson 
1358085272b3SRichard Henderson     return ts;
1359a7812ae4Spbrook }
1360a7812ae4Spbrook 
1361b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1362a7812ae4Spbrook {
1363b3a62939SRichard Henderson     s->frame_start = start;
1364b3a62939SRichard Henderson     s->frame_end = start + size;
1365085272b3SRichard Henderson     s->frame_temp
1366085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1367b3a62939SRichard Henderson }
1368a7812ae4Spbrook 
1369085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
1370e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
1371c896fe29Sbellard {
1372b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1373dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
13747ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1375b3915dbbSRichard Henderson     int indirect_reg = 0, bigendian = 0;
13767ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
13777ca4b752SRichard Henderson     bigendian = 1;
13787ca4b752SRichard Henderson #endif
1379c896fe29Sbellard 
1380c0522136SRichard Henderson     switch (base_ts->kind) {
1381c0522136SRichard Henderson     case TEMP_FIXED:
1382c0522136SRichard Henderson         break;
1383c0522136SRichard Henderson     case TEMP_GLOBAL:
13845a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
13855a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1386b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
13875a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
13885a18407fSRichard Henderson                             ? 2 : 1);
13895a18407fSRichard Henderson         indirect_reg = 1;
1390c0522136SRichard Henderson         break;
1391c0522136SRichard Henderson     default:
1392c0522136SRichard Henderson         g_assert_not_reached();
1393b3915dbbSRichard Henderson     }
1394b3915dbbSRichard Henderson 
13957ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
13967ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1397c896fe29Sbellard         char buf[64];
13987ca4b752SRichard Henderson 
13997ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1400c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1401b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1402c896fe29Sbellard         ts->mem_allocated = 1;
1403b3a62939SRichard Henderson         ts->mem_base = base_ts;
14047ca4b752SRichard Henderson         ts->mem_offset = offset + bigendian * 4;
1405c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1406c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1407c896fe29Sbellard         ts->name = strdup(buf);
1408c896fe29Sbellard 
14097ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
14107ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
14117ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1412b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
14137ca4b752SRichard Henderson         ts2->mem_allocated = 1;
14147ca4b752SRichard Henderson         ts2->mem_base = base_ts;
14157ca4b752SRichard Henderson         ts2->mem_offset = offset + (1 - bigendian) * 4;
1416c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1417c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1418120c1084SRichard Henderson         ts2->name = strdup(buf);
14197ca4b752SRichard Henderson     } else {
1420c896fe29Sbellard         ts->base_type = type;
1421c896fe29Sbellard         ts->type = type;
1422b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1423c896fe29Sbellard         ts->mem_allocated = 1;
1424b3a62939SRichard Henderson         ts->mem_base = base_ts;
1425c896fe29Sbellard         ts->mem_offset = offset;
1426c896fe29Sbellard         ts->name = name;
1427c896fe29Sbellard     }
1428085272b3SRichard Henderson     return ts;
1429c896fe29Sbellard }
1430c896fe29Sbellard 
14315bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local)
1432c896fe29Sbellard {
1433b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1434ee17db83SRichard Henderson     TCGTempKind kind = temp_local ? TEMP_LOCAL : TEMP_NORMAL;
1435c896fe29Sbellard     TCGTemp *ts;
1436641d5fbeSbellard     int idx, k;
1437c896fe29Sbellard 
14380ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
14390ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
14400ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
14410ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
14420ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
14430ec9eabcSRichard Henderson 
1444e8996ee0Sbellard         ts = &s->temps[idx];
1445e8996ee0Sbellard         ts->temp_allocated = 1;
14467ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
1447ee17db83SRichard Henderson         tcg_debug_assert(ts->kind == kind);
1448e8996ee0Sbellard     } else {
14497ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
14507ca4b752SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
14517ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
14527ca4b752SRichard Henderson 
1453c896fe29Sbellard             ts->base_type = type;
1454c896fe29Sbellard             ts->type = TCG_TYPE_I32;
1455e8996ee0Sbellard             ts->temp_allocated = 1;
1456ee17db83SRichard Henderson             ts->kind = kind;
14577ca4b752SRichard Henderson 
14587ca4b752SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
14597ca4b752SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
14607ca4b752SRichard Henderson             ts2->type = TCG_TYPE_I32;
14617ca4b752SRichard Henderson             ts2->temp_allocated = 1;
1462ee17db83SRichard Henderson             ts2->kind = kind;
14637ca4b752SRichard Henderson         } else {
1464c896fe29Sbellard             ts->base_type = type;
1465c896fe29Sbellard             ts->type = type;
1466e8996ee0Sbellard             ts->temp_allocated = 1;
1467ee17db83SRichard Henderson             ts->kind = kind;
1468c896fe29Sbellard         }
1469e8996ee0Sbellard     }
147027bfd83cSPeter Maydell 
147127bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
147227bfd83cSPeter Maydell     s->temps_in_use++;
147327bfd83cSPeter Maydell #endif
1474085272b3SRichard Henderson     return ts;
1475c896fe29Sbellard }
1476c896fe29Sbellard 
1477d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1478d2fd745fSRichard Henderson {
1479d2fd745fSRichard Henderson     TCGTemp *t;
1480d2fd745fSRichard Henderson 
1481d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1482d2fd745fSRichard Henderson     switch (type) {
1483d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1484d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1485d2fd745fSRichard Henderson         break;
1486d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1487d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1488d2fd745fSRichard Henderson         break;
1489d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1490d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1491d2fd745fSRichard Henderson         break;
1492d2fd745fSRichard Henderson     default:
1493d2fd745fSRichard Henderson         g_assert_not_reached();
1494d2fd745fSRichard Henderson     }
1495d2fd745fSRichard Henderson #endif
1496d2fd745fSRichard Henderson 
1497d2fd745fSRichard Henderson     t = tcg_temp_new_internal(type, 0);
1498d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1499d2fd745fSRichard Henderson }
1500d2fd745fSRichard Henderson 
1501d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1502d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1503d2fd745fSRichard Henderson {
1504d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1505d2fd745fSRichard Henderson 
1506d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1507d2fd745fSRichard Henderson 
1508d2fd745fSRichard Henderson     t = tcg_temp_new_internal(t->base_type, 0);
1509d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1510d2fd745fSRichard Henderson }
1511d2fd745fSRichard Henderson 
15125bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1513c896fe29Sbellard {
1514b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1515085272b3SRichard Henderson     int k, idx;
1516c896fe29Sbellard 
1517c0522136SRichard Henderson     /* In order to simplify users of tcg_constant_*, silently ignore free. */
1518c0522136SRichard Henderson     if (ts->kind == TEMP_CONST) {
1519c0522136SRichard Henderson         return;
1520c0522136SRichard Henderson     }
1521c0522136SRichard Henderson 
152227bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
152327bfd83cSPeter Maydell     s->temps_in_use--;
152427bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
152527bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
152627bfd83cSPeter Maydell     }
152727bfd83cSPeter Maydell #endif
152827bfd83cSPeter Maydell 
1529ee17db83SRichard Henderson     tcg_debug_assert(ts->kind < TEMP_GLOBAL);
1530eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
1531e8996ee0Sbellard     ts->temp_allocated = 0;
15320ec9eabcSRichard Henderson 
1533085272b3SRichard Henderson     idx = temp_idx(ts);
1534ee17db83SRichard Henderson     k = ts->base_type + (ts->kind == TEMP_NORMAL ? 0 : TCG_TYPE_COUNT);
15350ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
1536e8996ee0Sbellard }
1537e8996ee0Sbellard 
1538c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val)
1539c0522136SRichard Henderson {
1540c0522136SRichard Henderson     TCGContext *s = tcg_ctx;
1541c0522136SRichard Henderson     GHashTable *h = s->const_table[type];
1542c0522136SRichard Henderson     TCGTemp *ts;
1543c0522136SRichard Henderson 
1544c0522136SRichard Henderson     if (h == NULL) {
1545c0522136SRichard Henderson         h = g_hash_table_new(g_int64_hash, g_int64_equal);
1546c0522136SRichard Henderson         s->const_table[type] = h;
1547c0522136SRichard Henderson     }
1548c0522136SRichard Henderson 
1549c0522136SRichard Henderson     ts = g_hash_table_lookup(h, &val);
1550c0522136SRichard Henderson     if (ts == NULL) {
1551c0522136SRichard Henderson         ts = tcg_temp_alloc(s);
1552c0522136SRichard Henderson 
1553c0522136SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
1554c0522136SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
1555c0522136SRichard Henderson 
1556c0522136SRichard Henderson             ts->base_type = TCG_TYPE_I64;
1557c0522136SRichard Henderson             ts->type = TCG_TYPE_I32;
1558c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1559c0522136SRichard Henderson             ts->temp_allocated = 1;
1560c0522136SRichard Henderson             /*
1561c0522136SRichard Henderson              * Retain the full value of the 64-bit constant in the low
1562c0522136SRichard Henderson              * part, so that the hash table works.  Actual uses will
1563c0522136SRichard Henderson              * truncate the value to the low part.
1564c0522136SRichard Henderson              */
1565c0522136SRichard Henderson             ts->val = val;
1566c0522136SRichard Henderson 
1567c0522136SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
1568c0522136SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
1569c0522136SRichard Henderson             ts2->type = TCG_TYPE_I32;
1570c0522136SRichard Henderson             ts2->kind = TEMP_CONST;
1571c0522136SRichard Henderson             ts2->temp_allocated = 1;
1572c0522136SRichard Henderson             ts2->val = val >> 32;
1573c0522136SRichard Henderson         } else {
1574c0522136SRichard Henderson             ts->base_type = type;
1575c0522136SRichard Henderson             ts->type = type;
1576c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1577c0522136SRichard Henderson             ts->temp_allocated = 1;
1578c0522136SRichard Henderson             ts->val = val;
1579c0522136SRichard Henderson         }
1580c0522136SRichard Henderson         g_hash_table_insert(h, &ts->val, ts);
1581c0522136SRichard Henderson     }
1582c0522136SRichard Henderson 
1583c0522136SRichard Henderson     return ts;
1584c0522136SRichard Henderson }
1585c0522136SRichard Henderson 
1586c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val)
1587c0522136SRichard Henderson {
1588c0522136SRichard Henderson     val = dup_const(vece, val);
1589c0522136SRichard Henderson     return temp_tcgv_vec(tcg_constant_internal(type, val));
1590c0522136SRichard Henderson }
1591c0522136SRichard Henderson 
159288d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val)
159388d4005bSRichard Henderson {
159488d4005bSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
159588d4005bSRichard Henderson 
159688d4005bSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
159788d4005bSRichard Henderson     return tcg_constant_vec(t->base_type, vece, val);
159888d4005bSRichard Henderson }
159988d4005bSRichard Henderson 
1600a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
1601a7812ae4Spbrook {
1602a7812ae4Spbrook     TCGv_i32 t0;
1603a7812ae4Spbrook     t0 = tcg_temp_new_i32();
1604e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
1605e8996ee0Sbellard     return t0;
1606c896fe29Sbellard }
1607c896fe29Sbellard 
1608a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
1609c896fe29Sbellard {
1610a7812ae4Spbrook     TCGv_i64 t0;
1611a7812ae4Spbrook     t0 = tcg_temp_new_i64();
1612e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
1613e8996ee0Sbellard     return t0;
1614c896fe29Sbellard }
1615c896fe29Sbellard 
1616a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
1617bdffd4a9Saurel32 {
1618a7812ae4Spbrook     TCGv_i32 t0;
1619a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
1620bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
1621bdffd4a9Saurel32     return t0;
1622bdffd4a9Saurel32 }
1623bdffd4a9Saurel32 
1624a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
1625bdffd4a9Saurel32 {
1626a7812ae4Spbrook     TCGv_i64 t0;
1627a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
1628bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
1629bdffd4a9Saurel32     return t0;
1630bdffd4a9Saurel32 }
1631bdffd4a9Saurel32 
163227bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
163327bfd83cSPeter Maydell void tcg_clear_temp_count(void)
163427bfd83cSPeter Maydell {
1635b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
163627bfd83cSPeter Maydell     s->temps_in_use = 0;
163727bfd83cSPeter Maydell }
163827bfd83cSPeter Maydell 
163927bfd83cSPeter Maydell int tcg_check_temp_count(void)
164027bfd83cSPeter Maydell {
1641b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
164227bfd83cSPeter Maydell     if (s->temps_in_use) {
164327bfd83cSPeter Maydell         /* Clear the count so that we don't give another
164427bfd83cSPeter Maydell          * warning immediately next time around.
164527bfd83cSPeter Maydell          */
164627bfd83cSPeter Maydell         s->temps_in_use = 0;
164727bfd83cSPeter Maydell         return 1;
164827bfd83cSPeter Maydell     }
164927bfd83cSPeter Maydell     return 0;
165027bfd83cSPeter Maydell }
165127bfd83cSPeter Maydell #endif
165227bfd83cSPeter Maydell 
1653be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1654be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1655be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1656be0f34b5SRichard Henderson {
1657d2fd745fSRichard Henderson     const bool have_vec
1658d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1659d2fd745fSRichard Henderson 
1660be0f34b5SRichard Henderson     switch (op) {
1661be0f34b5SRichard Henderson     case INDEX_op_discard:
1662be0f34b5SRichard Henderson     case INDEX_op_set_label:
1663be0f34b5SRichard Henderson     case INDEX_op_call:
1664be0f34b5SRichard Henderson     case INDEX_op_br:
1665be0f34b5SRichard Henderson     case INDEX_op_mb:
1666be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1667be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1668be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1669be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i32:
1670be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i32:
1671be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i64:
1672be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i64:
1673be0f34b5SRichard Henderson         return true;
1674be0f34b5SRichard Henderson 
167507ce0b05SRichard Henderson     case INDEX_op_qemu_st8_i32:
167607ce0b05SRichard Henderson         return TCG_TARGET_HAS_qemu_st8_i32;
167707ce0b05SRichard Henderson 
1678be0f34b5SRichard Henderson     case INDEX_op_goto_ptr:
1679be0f34b5SRichard Henderson         return TCG_TARGET_HAS_goto_ptr;
1680be0f34b5SRichard Henderson 
1681be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1682be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1683be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1684be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1685be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1686be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1687be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1688be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1689be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1690be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1691be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1692be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1693be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1694be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1695be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1696be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1697be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1698be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1699be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1700be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1701be0f34b5SRichard Henderson         return true;
1702be0f34b5SRichard Henderson 
1703be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1704be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1705be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1706be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1707be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1708be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1709be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1710be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1711be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1712be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1713be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1714be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1715be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1716be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1717be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1718be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1719be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1720be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1721be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1722be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1723fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
1724fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
1725be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1726be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1727be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1728be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1729be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1730be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1731be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1732be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1733be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1734be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1735be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1736be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1737be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1738be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1739be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1740be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1741be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1742be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1743be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1744be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1745be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1746be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1747be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1748be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1749be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1750be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1751be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1752be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1753be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1754be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1755be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1756be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1757be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1758be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1759be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1760be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1761be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1762be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1763be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1764be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1765be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1766be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1767be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1768be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1769be0f34b5SRichard Henderson 
1770be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1771be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1772be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1773be0f34b5SRichard Henderson 
1774be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1775be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1776be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1777be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1778be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1779be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1780be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1781be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1782be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1783be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1784be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1785be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1786be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1787be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1788be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1789be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1790be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1791be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1792be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1793be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1794be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1795be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1796be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1797be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1798be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1799be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1800be0f34b5SRichard Henderson 
1801be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1802be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1803be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1804be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1805be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1806be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1807be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1808be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1809be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1810be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
1811be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
1812be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
1813be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
1814be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
1815be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
1816be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
1817be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
1818be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
1819be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
1820be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
1821fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
1822fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
1823be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
1824be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrl_i64_i32;
1825be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
1826be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrh_i64_i32;
1827be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
1828be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
1829be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
1830be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
1831be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
1832be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
1833be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
1834be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
1835be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
1836be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
1837be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
1838be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
1839be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
1840be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
1841be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
1842be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
1843be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
1844be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
1845be0f34b5SRichard Henderson     case INDEX_op_not_i64:
1846be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
1847be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
1848be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
1849be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
1850be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
1851be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
1852be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
1853be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
1854be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
1855be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
1856be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
1857be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
1858be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
1859be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
1860be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
1861be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
1862be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
1863be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
1864be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
1865be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
1866be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
1867be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
1868be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
1869be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
1870be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
1871be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
1872be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
1873be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
1874be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
1875be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
1876be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
1877be0f34b5SRichard Henderson 
1878d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
1879d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
188037ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
1881d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
1882d2fd745fSRichard Henderson     case INDEX_op_st_vec:
1883d2fd745fSRichard Henderson     case INDEX_op_add_vec:
1884d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
1885d2fd745fSRichard Henderson     case INDEX_op_and_vec:
1886d2fd745fSRichard Henderson     case INDEX_op_or_vec:
1887d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
1888212be173SRichard Henderson     case INDEX_op_cmp_vec:
1889d2fd745fSRichard Henderson         return have_vec;
1890d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
1891d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
1892d2fd745fSRichard Henderson     case INDEX_op_not_vec:
1893d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
1894d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
1895d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
1896bcefc902SRichard Henderson     case INDEX_op_abs_vec:
1897bcefc902SRichard Henderson         return have_vec && TCG_TARGET_HAS_abs_vec;
1898d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
1899d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
1900d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
1901d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
19023774030aSRichard Henderson     case INDEX_op_mul_vec:
19033774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
1904d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
1905d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
1906d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
1907d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
1908d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
1909d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
1910d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
1911d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
1912d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
1913d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
1914d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
1915d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
1916b0f7e744SRichard Henderson     case INDEX_op_rotli_vec:
1917b0f7e744SRichard Henderson         return have_vec && TCG_TARGET_HAS_roti_vec;
191823850a74SRichard Henderson     case INDEX_op_rotls_vec:
191923850a74SRichard Henderson         return have_vec && TCG_TARGET_HAS_rots_vec;
19205d0ceda9SRichard Henderson     case INDEX_op_rotlv_vec:
19215d0ceda9SRichard Henderson     case INDEX_op_rotrv_vec:
19225d0ceda9SRichard Henderson         return have_vec && TCG_TARGET_HAS_rotv_vec;
19238afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
19248afaf050SRichard Henderson     case INDEX_op_usadd_vec:
19258afaf050SRichard Henderson     case INDEX_op_sssub_vec:
19268afaf050SRichard Henderson     case INDEX_op_ussub_vec:
19278afaf050SRichard Henderson         return have_vec && TCG_TARGET_HAS_sat_vec;
1928dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
1929dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
1930dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
1931dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
1932dd0a0fcdSRichard Henderson         return have_vec && TCG_TARGET_HAS_minmax_vec;
193338dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
193438dc1294SRichard Henderson         return have_vec && TCG_TARGET_HAS_bitsel_vec;
1935f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
1936f75da298SRichard Henderson         return have_vec && TCG_TARGET_HAS_cmpsel_vec;
1937d2fd745fSRichard Henderson 
1938db432672SRichard Henderson     default:
1939db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
1940db432672SRichard Henderson         return true;
1941be0f34b5SRichard Henderson     }
1942be0f34b5SRichard Henderson }
1943be0f34b5SRichard Henderson 
194439cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment
194539cf05d3Sbellard    and endian swap. Maybe it would be better to do the alignment
194639cf05d3Sbellard    and endian swap in tcg_reg_alloc_call(). */
1947ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
1948c896fe29Sbellard {
194975e8b9b7SRichard Henderson     int i, real_args, nb_rets, pi;
1950bbb8a1b4SRichard Henderson     unsigned sizemask, flags;
1951afb49896SRichard Henderson     TCGHelperInfo *info;
195275e8b9b7SRichard Henderson     TCGOp *op;
1953afb49896SRichard Henderson 
1954619205fdSEmilio G. Cota     info = g_hash_table_lookup(helper_table, (gpointer)func);
1955bbb8a1b4SRichard Henderson     flags = info->flags;
1956bbb8a1b4SRichard Henderson     sizemask = info->sizemask;
19572bece2c8SRichard Henderson 
195838b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
195938b47b19SEmilio G. Cota     /* detect non-plugin helpers */
196038b47b19SEmilio G. Cota     if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) {
196138b47b19SEmilio G. Cota         tcg_ctx->plugin_insn->calls_helpers = true;
196238b47b19SEmilio G. Cota     }
196338b47b19SEmilio G. Cota #endif
196438b47b19SEmilio G. Cota 
196534b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
196634b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
196734b1a49cSRichard Henderson     /* We have 64-bit values in one register, but need to pass as two
196834b1a49cSRichard Henderson        separate parameters.  Split them.  */
196934b1a49cSRichard Henderson     int orig_sizemask = sizemask;
197034b1a49cSRichard Henderson     int orig_nargs = nargs;
197134b1a49cSRichard Henderson     TCGv_i64 retl, reth;
1972ae8b75dcSRichard Henderson     TCGTemp *split_args[MAX_OPC_PARAM];
197334b1a49cSRichard Henderson 
1974f764718dSRichard Henderson     retl = NULL;
1975f764718dSRichard Henderson     reth = NULL;
197634b1a49cSRichard Henderson     if (sizemask != 0) {
197734b1a49cSRichard Henderson         for (i = real_args = 0; i < nargs; ++i) {
197834b1a49cSRichard Henderson             int is_64bit = sizemask & (1 << (i+1)*2);
197934b1a49cSRichard Henderson             if (is_64bit) {
1980085272b3SRichard Henderson                 TCGv_i64 orig = temp_tcgv_i64(args[i]);
198134b1a49cSRichard Henderson                 TCGv_i32 h = tcg_temp_new_i32();
198234b1a49cSRichard Henderson                 TCGv_i32 l = tcg_temp_new_i32();
198334b1a49cSRichard Henderson                 tcg_gen_extr_i64_i32(l, h, orig);
1984ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(h);
1985ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(l);
198634b1a49cSRichard Henderson             } else {
198734b1a49cSRichard Henderson                 split_args[real_args++] = args[i];
198834b1a49cSRichard Henderson             }
198934b1a49cSRichard Henderson         }
199034b1a49cSRichard Henderson         nargs = real_args;
199134b1a49cSRichard Henderson         args = split_args;
199234b1a49cSRichard Henderson         sizemask = 0;
199334b1a49cSRichard Henderson     }
199434b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
19952bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
19962bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
19972bece2c8SRichard Henderson         int is_signed = sizemask & (2 << (i+1)*2);
19982bece2c8SRichard Henderson         if (!is_64bit) {
19992bece2c8SRichard Henderson             TCGv_i64 temp = tcg_temp_new_i64();
2000085272b3SRichard Henderson             TCGv_i64 orig = temp_tcgv_i64(args[i]);
20012bece2c8SRichard Henderson             if (is_signed) {
20022bece2c8SRichard Henderson                 tcg_gen_ext32s_i64(temp, orig);
20032bece2c8SRichard Henderson             } else {
20042bece2c8SRichard Henderson                 tcg_gen_ext32u_i64(temp, orig);
20052bece2c8SRichard Henderson             }
2006ae8b75dcSRichard Henderson             args[i] = tcgv_i64_temp(temp);
20072bece2c8SRichard Henderson         }
20082bece2c8SRichard Henderson     }
20092bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
20102bece2c8SRichard Henderson 
201115fa08f8SRichard Henderson     op = tcg_emit_op(INDEX_op_call);
201275e8b9b7SRichard Henderson 
201375e8b9b7SRichard Henderson     pi = 0;
2014ae8b75dcSRichard Henderson     if (ret != NULL) {
201534b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
201634b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
201734b1a49cSRichard Henderson         if (orig_sizemask & 1) {
201834b1a49cSRichard Henderson             /* The 32-bit ABI is going to return the 64-bit value in
201934b1a49cSRichard Henderson                the %o0/%o1 register pair.  Prepare for this by using
202034b1a49cSRichard Henderson                two return temporaries, and reassemble below.  */
202134b1a49cSRichard Henderson             retl = tcg_temp_new_i64();
202234b1a49cSRichard Henderson             reth = tcg_temp_new_i64();
2023ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(reth);
2024ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(retl);
202534b1a49cSRichard Henderson             nb_rets = 2;
202634b1a49cSRichard Henderson         } else {
2027ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
202834b1a49cSRichard Henderson             nb_rets = 1;
202934b1a49cSRichard Henderson         }
203034b1a49cSRichard Henderson #else
203134b1a49cSRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) {
203202eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
2033ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
2034ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
2035a7812ae4Spbrook #else
2036ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
2037ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
2038a7812ae4Spbrook #endif
2039a7812ae4Spbrook             nb_rets = 2;
204034b1a49cSRichard Henderson         } else {
2041ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
2042a7812ae4Spbrook             nb_rets = 1;
2043a7812ae4Spbrook         }
204434b1a49cSRichard Henderson #endif
2045a7812ae4Spbrook     } else {
2046a7812ae4Spbrook         nb_rets = 0;
2047a7812ae4Spbrook     }
2048cd9090aaSRichard Henderson     TCGOP_CALLO(op) = nb_rets;
204975e8b9b7SRichard Henderson 
2050a7812ae4Spbrook     real_args = 0;
2051a7812ae4Spbrook     for (i = 0; i < nargs; i++) {
20522bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
2053bbb8a1b4SRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
205439cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS
205539cf05d3Sbellard             /* some targets want aligned 64 bit args */
2056ebd486d5Smalc             if (real_args & 1) {
205775e8b9b7SRichard Henderson                 op->args[pi++] = TCG_CALL_DUMMY_ARG;
2058ebd486d5Smalc                 real_args++;
205939cf05d3Sbellard             }
206039cf05d3Sbellard #endif
20613f90f252SRichard Henderson            /* If stack grows up, then we will be placing successive
20623f90f252SRichard Henderson               arguments at lower addresses, which means we need to
20633f90f252SRichard Henderson               reverse the order compared to how we would normally
20643f90f252SRichard Henderson               treat either big or little-endian.  For those arguments
20653f90f252SRichard Henderson               that will wind up in registers, this still works for
20663f90f252SRichard Henderson               HPPA (the only current STACK_GROWSUP target) since the
20673f90f252SRichard Henderson               argument registers are *also* allocated in decreasing
20683f90f252SRichard Henderson               order.  If another such target is added, this logic may
20693f90f252SRichard Henderson               have to get more complicated to differentiate between
20703f90f252SRichard Henderson               stack arguments and register arguments.  */
207102eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
2072ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
2073ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
2074c896fe29Sbellard #else
2075ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
2076ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
2077c896fe29Sbellard #endif
2078a7812ae4Spbrook             real_args += 2;
20792bece2c8SRichard Henderson             continue;
20802bece2c8SRichard Henderson         }
20812bece2c8SRichard Henderson 
2082ae8b75dcSRichard Henderson         op->args[pi++] = temp_arg(args[i]);
2083a7812ae4Spbrook         real_args++;
2084c896fe29Sbellard     }
208575e8b9b7SRichard Henderson     op->args[pi++] = (uintptr_t)func;
208675e8b9b7SRichard Henderson     op->args[pi++] = flags;
2087cd9090aaSRichard Henderson     TCGOP_CALLI(op) = real_args;
2088a7812ae4Spbrook 
208975e8b9b7SRichard Henderson     /* Make sure the fields didn't overflow.  */
2090cd9090aaSRichard Henderson     tcg_debug_assert(TCGOP_CALLI(op) == real_args);
209175e8b9b7SRichard Henderson     tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
20922bece2c8SRichard Henderson 
209334b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
209434b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
209534b1a49cSRichard Henderson     /* Free all of the parts we allocated above.  */
209634b1a49cSRichard Henderson     for (i = real_args = 0; i < orig_nargs; ++i) {
209734b1a49cSRichard Henderson         int is_64bit = orig_sizemask & (1 << (i+1)*2);
209834b1a49cSRichard Henderson         if (is_64bit) {
2099085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
2100085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
210134b1a49cSRichard Henderson         } else {
210234b1a49cSRichard Henderson             real_args++;
210334b1a49cSRichard Henderson         }
210434b1a49cSRichard Henderson     }
210534b1a49cSRichard Henderson     if (orig_sizemask & 1) {
210634b1a49cSRichard Henderson         /* The 32-bit ABI returned two 32-bit pieces.  Re-assemble them.
210734b1a49cSRichard Henderson            Note that describing these as TCGv_i64 eliminates an unnecessary
210834b1a49cSRichard Henderson            zero-extension that tcg_gen_concat_i32_i64 would create.  */
2109085272b3SRichard Henderson         tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth);
211034b1a49cSRichard Henderson         tcg_temp_free_i64(retl);
211134b1a49cSRichard Henderson         tcg_temp_free_i64(reth);
211234b1a49cSRichard Henderson     }
211334b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
21142bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
21152bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
21162bece2c8SRichard Henderson         if (!is_64bit) {
2117085272b3SRichard Henderson             tcg_temp_free_internal(args[i]);
21182bece2c8SRichard Henderson         }
21192bece2c8SRichard Henderson     }
21202bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
2121a7812ae4Spbrook }
2122c896fe29Sbellard 
21238fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
2124c896fe29Sbellard {
2125ac3b8891SRichard Henderson     int i, n;
2126ac3b8891SRichard Henderson 
2127ee17db83SRichard Henderson     for (i = 0, n = s->nb_temps; i < n; i++) {
2128ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2129ee17db83SRichard Henderson         TCGTempVal val = TEMP_VAL_MEM;
2130ee17db83SRichard Henderson 
2131ee17db83SRichard Henderson         switch (ts->kind) {
2132c0522136SRichard Henderson         case TEMP_CONST:
2133c0522136SRichard Henderson             val = TEMP_VAL_CONST;
2134c0522136SRichard Henderson             break;
2135ee17db83SRichard Henderson         case TEMP_FIXED:
2136ee17db83SRichard Henderson             val = TEMP_VAL_REG;
2137ee17db83SRichard Henderson             break;
2138ee17db83SRichard Henderson         case TEMP_GLOBAL:
2139ee17db83SRichard Henderson             break;
2140ee17db83SRichard Henderson         case TEMP_NORMAL:
2141ee17db83SRichard Henderson             val = TEMP_VAL_DEAD;
2142ee17db83SRichard Henderson             /* fall through */
2143ee17db83SRichard Henderson         case TEMP_LOCAL:
2144e8996ee0Sbellard             ts->mem_allocated = 0;
2145ee17db83SRichard Henderson             break;
2146ee17db83SRichard Henderson         default:
2147ee17db83SRichard Henderson             g_assert_not_reached();
2148ee17db83SRichard Henderson         }
2149ee17db83SRichard Henderson         ts->val_type = val;
2150e8996ee0Sbellard     }
2151f8b2f202SRichard Henderson 
2152f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
2153c896fe29Sbellard }
2154c896fe29Sbellard 
2155f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
2156f8b2f202SRichard Henderson                                  TCGTemp *ts)
2157c896fe29Sbellard {
21581807f4c4SRichard Henderson     int idx = temp_idx(ts);
2159ac56dd48Spbrook 
2160ee17db83SRichard Henderson     switch (ts->kind) {
2161ee17db83SRichard Henderson     case TEMP_FIXED:
2162ee17db83SRichard Henderson     case TEMP_GLOBAL:
2163ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
2164ee17db83SRichard Henderson         break;
2165ee17db83SRichard Henderson     case TEMP_LOCAL:
2166641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
2167ee17db83SRichard Henderson         break;
2168ee17db83SRichard Henderson     case TEMP_NORMAL:
2169ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
2170ee17db83SRichard Henderson         break;
2171c0522136SRichard Henderson     case TEMP_CONST:
2172c0522136SRichard Henderson         switch (ts->type) {
2173c0522136SRichard Henderson         case TCG_TYPE_I32:
2174c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val);
2175c0522136SRichard Henderson             break;
2176c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32
2177c0522136SRichard Henderson         case TCG_TYPE_I64:
2178c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%" PRIx64, ts->val);
2179c0522136SRichard Henderson             break;
2180c0522136SRichard Henderson #endif
2181c0522136SRichard Henderson         case TCG_TYPE_V64:
2182c0522136SRichard Henderson         case TCG_TYPE_V128:
2183c0522136SRichard Henderson         case TCG_TYPE_V256:
2184c0522136SRichard Henderson             snprintf(buf, buf_size, "v%d$0x%" PRIx64,
2185c0522136SRichard Henderson                      64 << (ts->type - TCG_TYPE_V64), ts->val);
2186c0522136SRichard Henderson             break;
2187c0522136SRichard Henderson         default:
2188c0522136SRichard Henderson             g_assert_not_reached();
2189c0522136SRichard Henderson         }
2190c0522136SRichard Henderson         break;
2191c896fe29Sbellard     }
2192c896fe29Sbellard     return buf;
2193c896fe29Sbellard }
2194c896fe29Sbellard 
219543439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
219643439139SRichard Henderson                              int buf_size, TCGArg arg)
2197f8b2f202SRichard Henderson {
219843439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
2199f8b2f202SRichard Henderson }
2200f8b2f202SRichard Henderson 
22016e085f72SRichard Henderson /* Find helper name.  */
22026e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val)
2203e8996ee0Sbellard {
22046e085f72SRichard Henderson     const char *ret = NULL;
2205619205fdSEmilio G. Cota     if (helper_table) {
2206619205fdSEmilio G. Cota         TCGHelperInfo *info = g_hash_table_lookup(helper_table, (gpointer)val);
220772866e82SRichard Henderson         if (info) {
220872866e82SRichard Henderson             ret = info->name;
220972866e82SRichard Henderson         }
2210e8996ee0Sbellard     }
22116e085f72SRichard Henderson     return ret;
22124dc81f28Sbellard }
22134dc81f28Sbellard 
2214f48f3edeSblueswir1 static const char * const cond_name[] =
2215f48f3edeSblueswir1 {
22160aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
22170aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
2218f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
2219f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
2220f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
2221f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
2222f48f3edeSblueswir1     [TCG_COND_LE] = "le",
2223f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
2224f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
2225f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
2226f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
2227f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
2228f48f3edeSblueswir1 };
2229f48f3edeSblueswir1 
2230f713d6adSRichard Henderson static const char * const ldst_name[] =
2231f713d6adSRichard Henderson {
2232f713d6adSRichard Henderson     [MO_UB]   = "ub",
2233f713d6adSRichard Henderson     [MO_SB]   = "sb",
2234f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
2235f713d6adSRichard Henderson     [MO_LESW] = "lesw",
2236f713d6adSRichard Henderson     [MO_LEUL] = "leul",
2237f713d6adSRichard Henderson     [MO_LESL] = "lesl",
2238f713d6adSRichard Henderson     [MO_LEQ]  = "leq",
2239f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
2240f713d6adSRichard Henderson     [MO_BESW] = "besw",
2241f713d6adSRichard Henderson     [MO_BEUL] = "beul",
2242f713d6adSRichard Henderson     [MO_BESL] = "besl",
2243f713d6adSRichard Henderson     [MO_BEQ]  = "beq",
2244f713d6adSRichard Henderson };
2245f713d6adSRichard Henderson 
22461f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
224752bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY
22481f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
22491f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
22501f00b27fSSergey Sorokin #else
22511f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
22521f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
22531f00b27fSSergey Sorokin #endif
22541f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
22551f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
22561f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
22571f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
22581f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
22591f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
22601f00b27fSSergey Sorokin };
22611f00b27fSSergey Sorokin 
2262b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
2263b016486eSRichard Henderson {
2264b016486eSRichard Henderson     return (d & (d - 1)) == 0;
2265b016486eSRichard Henderson }
2266b016486eSRichard Henderson 
2267b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
2268b016486eSRichard Henderson {
2269b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
2270b016486eSRichard Henderson         return ctz32(d);
2271b016486eSRichard Henderson     } else {
2272b016486eSRichard Henderson         return ctz64(d);
2273b016486eSRichard Henderson     }
2274b016486eSRichard Henderson }
2275b016486eSRichard Henderson 
22761894f69aSRichard Henderson static void tcg_dump_ops(TCGContext *s, bool have_prefs)
2277c896fe29Sbellard {
2278c896fe29Sbellard     char buf[128];
2279c45cb8bbSRichard Henderson     TCGOp *op;
2280c896fe29Sbellard 
228115fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
2282c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
2283c45cb8bbSRichard Henderson         const TCGOpDef *def;
2284c45cb8bbSRichard Henderson         TCGOpcode c;
2285bdfb460eSRichard Henderson         int col = 0;
2286c45cb8bbSRichard Henderson 
2287c45cb8bbSRichard Henderson         c = op->opc;
2288c896fe29Sbellard         def = &tcg_op_defs[c];
2289c45cb8bbSRichard Henderson 
2290765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
2291b016486eSRichard Henderson             nb_oargs = 0;
229215fa08f8SRichard Henderson             col += qemu_log("\n ----");
22939aef40edSRichard Henderson 
22949aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
22959aef40edSRichard Henderson                 target_ulong a;
22967e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
2297efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
22987e4597d7Sbellard #else
2299efee3746SRichard Henderson                 a = op->args[i];
23007e4597d7Sbellard #endif
2301bdfb460eSRichard Henderson                 col += qemu_log(" " TARGET_FMT_lx, a);
2302eeacee4dSBlue Swirl             }
23037e4597d7Sbellard         } else if (c == INDEX_op_call) {
2304c896fe29Sbellard             /* variable number of arguments */
2305cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2306cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2307c896fe29Sbellard             nb_cargs = def->nb_cargs;
2308b03cce8eSbellard 
2309cf066674SRichard Henderson             /* function name, flags, out args */
2310bdfb460eSRichard Henderson             col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name,
2311efee3746SRichard Henderson                             tcg_find_helper(s, op->args[nb_oargs + nb_iargs]),
2312efee3746SRichard Henderson                             op->args[nb_oargs + nb_iargs + 1], nb_oargs);
2313b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
231443439139SRichard Henderson                 col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf),
2315efee3746SRichard Henderson                                                        op->args[i]));
2316b03cce8eSbellard             }
2317cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
2318efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
2319cf066674SRichard Henderson                 const char *t = "<dummy>";
2320cf066674SRichard Henderson                 if (arg != TCG_CALL_DUMMY_ARG) {
232143439139SRichard Henderson                     t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
2322b03cce8eSbellard                 }
2323bdfb460eSRichard Henderson                 col += qemu_log(",%s", t);
2324e8996ee0Sbellard             }
2325b03cce8eSbellard         } else {
2326bdfb460eSRichard Henderson             col += qemu_log(" %s ", def->name);
2327c45cb8bbSRichard Henderson 
2328c896fe29Sbellard             nb_oargs = def->nb_oargs;
2329c896fe29Sbellard             nb_iargs = def->nb_iargs;
2330c896fe29Sbellard             nb_cargs = def->nb_cargs;
2331c896fe29Sbellard 
2332d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
2333d2fd745fSRichard Henderson                 col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op),
2334d2fd745fSRichard Henderson                                 8 << TCGOP_VECE(op));
2335d2fd745fSRichard Henderson             }
2336d2fd745fSRichard Henderson 
2337c896fe29Sbellard             k = 0;
2338c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
2339eeacee4dSBlue Swirl                 if (k != 0) {
2340bdfb460eSRichard Henderson                     col += qemu_log(",");
2341eeacee4dSBlue Swirl                 }
234243439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2343efee3746SRichard Henderson                                                       op->args[k++]));
2344c896fe29Sbellard             }
2345c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
2346eeacee4dSBlue Swirl                 if (k != 0) {
2347bdfb460eSRichard Henderson                     col += qemu_log(",");
2348eeacee4dSBlue Swirl                 }
234943439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2350efee3746SRichard Henderson                                                       op->args[k++]));
2351c896fe29Sbellard             }
2352be210acbSRichard Henderson             switch (c) {
2353be210acbSRichard Henderson             case INDEX_op_brcond_i32:
2354ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
2355ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
2356be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
2357be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
2358ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
2359be210acbSRichard Henderson             case INDEX_op_setcond_i64:
2360ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
2361212be173SRichard Henderson             case INDEX_op_cmp_vec:
2362f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
2363efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
2364efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
2365efee3746SRichard Henderson                     col += qemu_log(",%s", cond_name[op->args[k++]]);
2366eeacee4dSBlue Swirl                 } else {
2367efee3746SRichard Henderson                     col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]);
2368eeacee4dSBlue Swirl                 }
2369f48f3edeSblueswir1                 i = 1;
2370be210acbSRichard Henderson                 break;
2371f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
2372f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
237307ce0b05SRichard Henderson             case INDEX_op_qemu_st8_i32:
2374f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
2375f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
237659227d5dSRichard Henderson                 {
2377efee3746SRichard Henderson                     TCGMemOpIdx oi = op->args[k++];
237814776ab5STony Nguyen                     MemOp op = get_memop(oi);
237959227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
238059227d5dSRichard Henderson 
238159c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
2382bdfb460eSRichard Henderson                         col += qemu_log(",$0x%x,%u", op, ix);
238359c4b7e8SRichard Henderson                     } else {
23841f00b27fSSergey Sorokin                         const char *s_al, *s_op;
23851f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
238659c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
2387bdfb460eSRichard Henderson                         col += qemu_log(",%s%s,%u", s_al, s_op, ix);
2388f713d6adSRichard Henderson                     }
2389f713d6adSRichard Henderson                     i = 1;
239059227d5dSRichard Henderson                 }
2391f713d6adSRichard Henderson                 break;
2392be210acbSRichard Henderson             default:
2393f48f3edeSblueswir1                 i = 0;
2394be210acbSRichard Henderson                 break;
2395be210acbSRichard Henderson             }
239651e3972cSRichard Henderson             switch (c) {
239751e3972cSRichard Henderson             case INDEX_op_set_label:
239851e3972cSRichard Henderson             case INDEX_op_br:
239951e3972cSRichard Henderson             case INDEX_op_brcond_i32:
240051e3972cSRichard Henderson             case INDEX_op_brcond_i64:
240151e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2402efee3746SRichard Henderson                 col += qemu_log("%s$L%d", k ? "," : "",
2403efee3746SRichard Henderson                                 arg_label(op->args[k])->id);
240451e3972cSRichard Henderson                 i++, k++;
240551e3972cSRichard Henderson                 break;
240651e3972cSRichard Henderson             default:
240751e3972cSRichard Henderson                 break;
2408eeacee4dSBlue Swirl             }
240951e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
2410efee3746SRichard Henderson                 col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]);
2411bdfb460eSRichard Henderson             }
2412bdfb460eSRichard Henderson         }
2413bdfb460eSRichard Henderson 
24141894f69aSRichard Henderson         if (have_prefs || op->life) {
24157606488cSRobert Foley 
24167606488cSRobert Foley             QemuLogFile *logfile;
24177606488cSRobert Foley 
24187606488cSRobert Foley             rcu_read_lock();
2419d73415a3SStefan Hajnoczi             logfile = qatomic_rcu_read(&qemu_logfile);
24207606488cSRobert Foley             if (logfile) {
24211894f69aSRichard Henderson                 for (; col < 40; ++col) {
24227606488cSRobert Foley                     putc(' ', logfile->fd);
2423bdfb460eSRichard Henderson                 }
24241894f69aSRichard Henderson             }
24257606488cSRobert Foley             rcu_read_unlock();
24267606488cSRobert Foley         }
24271894f69aSRichard Henderson 
24281894f69aSRichard Henderson         if (op->life) {
24291894f69aSRichard Henderson             unsigned life = op->life;
2430bdfb460eSRichard Henderson 
2431bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
2432bdfb460eSRichard Henderson                 qemu_log("  sync:");
2433bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
2434bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
2435bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2436bdfb460eSRichard Henderson                     }
2437bdfb460eSRichard Henderson                 }
2438bdfb460eSRichard Henderson             }
2439bdfb460eSRichard Henderson             life /= DEAD_ARG;
2440bdfb460eSRichard Henderson             if (life) {
2441bdfb460eSRichard Henderson                 qemu_log("  dead:");
2442bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
2443bdfb460eSRichard Henderson                     if (life & 1) {
2444bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2445bdfb460eSRichard Henderson                     }
2446bdfb460eSRichard Henderson                 }
2447c896fe29Sbellard             }
2448b03cce8eSbellard         }
24491894f69aSRichard Henderson 
24501894f69aSRichard Henderson         if (have_prefs) {
24511894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
24521894f69aSRichard Henderson                 TCGRegSet set = op->output_pref[i];
24531894f69aSRichard Henderson 
24541894f69aSRichard Henderson                 if (i == 0) {
24551894f69aSRichard Henderson                     qemu_log("  pref=");
24561894f69aSRichard Henderson                 } else {
24571894f69aSRichard Henderson                     qemu_log(",");
24581894f69aSRichard Henderson                 }
24591894f69aSRichard Henderson                 if (set == 0) {
24601894f69aSRichard Henderson                     qemu_log("none");
24611894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
24621894f69aSRichard Henderson                     qemu_log("all");
24631894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
24641894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
24651894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
24661894f69aSRichard Henderson                     qemu_log("%s", tcg_target_reg_names[reg]);
24671894f69aSRichard Henderson #endif
24681894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
24691894f69aSRichard Henderson                     qemu_log("%#x", (uint32_t)set);
24701894f69aSRichard Henderson                 } else {
24711894f69aSRichard Henderson                     qemu_log("%#" PRIx64, (uint64_t)set);
24721894f69aSRichard Henderson                 }
24731894f69aSRichard Henderson             }
24741894f69aSRichard Henderson         }
24751894f69aSRichard Henderson 
2476eeacee4dSBlue Swirl         qemu_log("\n");
2477c896fe29Sbellard     }
2478c896fe29Sbellard }
2479c896fe29Sbellard 
2480c896fe29Sbellard /* we give more priority to constraints with less registers */
2481c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2482c896fe29Sbellard {
248374a11790SRichard Henderson     const TCGArgConstraint *arg_ct = &def->args_ct[k];
248474a11790SRichard Henderson     int n;
2485c896fe29Sbellard 
2486bc2b17e6SRichard Henderson     if (arg_ct->oalias) {
2487c896fe29Sbellard         /* an alias is equivalent to a single register */
2488c896fe29Sbellard         n = 1;
2489c896fe29Sbellard     } else {
249074a11790SRichard Henderson         n = ctpop64(arg_ct->regs);
2491c896fe29Sbellard     }
2492c896fe29Sbellard     return TCG_TARGET_NB_REGS - n + 1;
2493c896fe29Sbellard }
2494c896fe29Sbellard 
2495c896fe29Sbellard /* sort from highest priority to lowest */
2496c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2497c896fe29Sbellard {
249866792f90SRichard Henderson     int i, j;
249966792f90SRichard Henderson     TCGArgConstraint *a = def->args_ct;
2500c896fe29Sbellard 
250166792f90SRichard Henderson     for (i = 0; i < n; i++) {
250266792f90SRichard Henderson         a[start + i].sort_index = start + i;
250366792f90SRichard Henderson     }
250466792f90SRichard Henderson     if (n <= 1) {
2505c896fe29Sbellard         return;
250666792f90SRichard Henderson     }
2507c896fe29Sbellard     for (i = 0; i < n - 1; i++) {
2508c896fe29Sbellard         for (j = i + 1; j < n; j++) {
250966792f90SRichard Henderson             int p1 = get_constraint_priority(def, a[start + i].sort_index);
251066792f90SRichard Henderson             int p2 = get_constraint_priority(def, a[start + j].sort_index);
2511c896fe29Sbellard             if (p1 < p2) {
251266792f90SRichard Henderson                 int tmp = a[start + i].sort_index;
251366792f90SRichard Henderson                 a[start + i].sort_index = a[start + j].sort_index;
251466792f90SRichard Henderson                 a[start + j].sort_index = tmp;
2515c896fe29Sbellard             }
2516c896fe29Sbellard         }
2517c896fe29Sbellard     }
2518c896fe29Sbellard }
2519c896fe29Sbellard 
2520f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2521c896fe29Sbellard {
2522a9751609SRichard Henderson     TCGOpcode op;
2523c896fe29Sbellard 
2524f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
2525f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
2526f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
2527069ea736SRichard Henderson         int i, nb_args;
2528f69d277eSRichard Henderson 
2529f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
2530f69d277eSRichard Henderson             continue;
2531f69d277eSRichard Henderson         }
2532f69d277eSRichard Henderson 
2533c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
2534f69d277eSRichard Henderson         if (nb_args == 0) {
2535f69d277eSRichard Henderson             continue;
2536f69d277eSRichard Henderson         }
2537f69d277eSRichard Henderson 
25384c22e840SRichard Henderson         /*
25394c22e840SRichard Henderson          * Macro magic should make it impossible, but double-check that
25404c22e840SRichard Henderson          * the array index is in range.  Since the signness of an enum
25414c22e840SRichard Henderson          * is implementation defined, force the result to unsigned.
25424c22e840SRichard Henderson          */
25434c22e840SRichard Henderson         unsigned con_set = tcg_target_op_def(op);
25444c22e840SRichard Henderson         tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets));
25454c22e840SRichard Henderson         tdefs = &constraint_sets[con_set];
2546f69d277eSRichard Henderson 
2547c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2548f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
2549f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2550eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2551f69d277eSRichard Henderson 
255217280ff4SRichard Henderson             while (*ct_str != '\0') {
255317280ff4SRichard Henderson                 switch(*ct_str) {
255417280ff4SRichard Henderson                 case '0' ... '9':
255517280ff4SRichard Henderson                     {
255617280ff4SRichard Henderson                         int oarg = *ct_str - '0';
255717280ff4SRichard Henderson                         tcg_debug_assert(ct_str == tdefs->args_ct_str[i]);
2558eabb7b91SAurelien Jarno                         tcg_debug_assert(oarg < def->nb_oargs);
255974a11790SRichard Henderson                         tcg_debug_assert(def->args_ct[oarg].regs != 0);
2560c896fe29Sbellard                         def->args_ct[i] = def->args_ct[oarg];
2561bc2b17e6SRichard Henderson                         /* The output sets oalias.  */
2562bc2b17e6SRichard Henderson                         def->args_ct[oarg].oalias = true;
25635ff9d6a4Sbellard                         def->args_ct[oarg].alias_index = i;
2564bc2b17e6SRichard Henderson                         /* The input sets ialias. */
2565bc2b17e6SRichard Henderson                         def->args_ct[i].ialias = true;
25665ff9d6a4Sbellard                         def->args_ct[i].alias_index = oarg;
256717280ff4SRichard Henderson                     }
256817280ff4SRichard Henderson                     ct_str++;
2569c896fe29Sbellard                     break;
257082790a87SRichard Henderson                 case '&':
2571bc2b17e6SRichard Henderson                     def->args_ct[i].newreg = true;
257282790a87SRichard Henderson                     ct_str++;
257382790a87SRichard Henderson                     break;
2574c896fe29Sbellard                 case 'i':
2575c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2576c896fe29Sbellard                     ct_str++;
2577c896fe29Sbellard                     break;
2578358b4923SRichard Henderson 
2579358b4923SRichard Henderson                 /* Include all of the target-specific constraints. */
2580358b4923SRichard Henderson 
2581358b4923SRichard Henderson #undef CONST
2582358b4923SRichard Henderson #define CONST(CASE, MASK) \
2583358b4923SRichard Henderson     case CASE: def->args_ct[i].ct |= MASK; ct_str++; break;
2584358b4923SRichard Henderson #define REGS(CASE, MASK) \
2585358b4923SRichard Henderson     case CASE: def->args_ct[i].regs |= MASK; ct_str++; break;
2586358b4923SRichard Henderson 
2587358b4923SRichard Henderson #include "tcg-target-con-str.h"
2588358b4923SRichard Henderson 
2589358b4923SRichard Henderson #undef REGS
2590358b4923SRichard Henderson #undef CONST
2591c896fe29Sbellard                 default:
2592358b4923SRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2593358b4923SRichard Henderson                     g_assert_not_reached();
2594358b4923SRichard Henderson                 }
2595c896fe29Sbellard             }
2596c896fe29Sbellard         }
2597c896fe29Sbellard 
2598c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2599eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2600c68aaa18SStefan Weil 
2601c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
2602c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
2603c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
2604c896fe29Sbellard     }
2605c896fe29Sbellard }
2606c896fe29Sbellard 
26070c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
26080c627cdcSRichard Henderson {
2609d88a117eSRichard Henderson     TCGLabel *label;
2610d88a117eSRichard Henderson 
2611d88a117eSRichard Henderson     switch (op->opc) {
2612d88a117eSRichard Henderson     case INDEX_op_br:
2613d88a117eSRichard Henderson         label = arg_label(op->args[0]);
2614d88a117eSRichard Henderson         label->refs--;
2615d88a117eSRichard Henderson         break;
2616d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
2617d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
2618d88a117eSRichard Henderson         label = arg_label(op->args[3]);
2619d88a117eSRichard Henderson         label->refs--;
2620d88a117eSRichard Henderson         break;
2621d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
2622d88a117eSRichard Henderson         label = arg_label(op->args[5]);
2623d88a117eSRichard Henderson         label->refs--;
2624d88a117eSRichard Henderson         break;
2625d88a117eSRichard Henderson     default:
2626d88a117eSRichard Henderson         break;
2627d88a117eSRichard Henderson     }
2628d88a117eSRichard Henderson 
262915fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
263015fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
2631abebf925SRichard Henderson     s->nb_ops--;
26320c627cdcSRichard Henderson 
26330c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
2634d73415a3SStefan Hajnoczi     qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
26350c627cdcSRichard Henderson #endif
26360c627cdcSRichard Henderson }
26370c627cdcSRichard Henderson 
263815fa08f8SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc)
263915fa08f8SRichard Henderson {
264015fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
264115fa08f8SRichard Henderson     TCGOp *op;
264215fa08f8SRichard Henderson 
264315fa08f8SRichard Henderson     if (likely(QTAILQ_EMPTY(&s->free_ops))) {
264415fa08f8SRichard Henderson         op = tcg_malloc(sizeof(TCGOp));
264515fa08f8SRichard Henderson     } else {
264615fa08f8SRichard Henderson         op = QTAILQ_FIRST(&s->free_ops);
264715fa08f8SRichard Henderson         QTAILQ_REMOVE(&s->free_ops, op, link);
264815fa08f8SRichard Henderson     }
264915fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
265015fa08f8SRichard Henderson     op->opc = opc;
2651abebf925SRichard Henderson     s->nb_ops++;
265215fa08f8SRichard Henderson 
265315fa08f8SRichard Henderson     return op;
265415fa08f8SRichard Henderson }
265515fa08f8SRichard Henderson 
265615fa08f8SRichard Henderson TCGOp *tcg_emit_op(TCGOpcode opc)
265715fa08f8SRichard Henderson {
265815fa08f8SRichard Henderson     TCGOp *op = tcg_op_alloc(opc);
265915fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
266015fa08f8SRichard Henderson     return op;
266115fa08f8SRichard Henderson }
266215fa08f8SRichard Henderson 
2663ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
26645a18407fSRichard Henderson {
266515fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
266615fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
26675a18407fSRichard Henderson     return new_op;
26685a18407fSRichard Henderson }
26695a18407fSRichard Henderson 
2670ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
26715a18407fSRichard Henderson {
267215fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
267315fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
26745a18407fSRichard Henderson     return new_op;
26755a18407fSRichard Henderson }
26765a18407fSRichard Henderson 
2677b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
2678b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s)
2679b4fc67c7SRichard Henderson {
2680b4fc67c7SRichard Henderson     TCGOp *op, *op_next;
2681b4fc67c7SRichard Henderson     bool dead = false;
2682b4fc67c7SRichard Henderson 
2683b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
2684b4fc67c7SRichard Henderson         bool remove = dead;
2685b4fc67c7SRichard Henderson         TCGLabel *label;
2686b4fc67c7SRichard Henderson         int call_flags;
2687b4fc67c7SRichard Henderson 
2688b4fc67c7SRichard Henderson         switch (op->opc) {
2689b4fc67c7SRichard Henderson         case INDEX_op_set_label:
2690b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
2691b4fc67c7SRichard Henderson             if (label->refs == 0) {
2692b4fc67c7SRichard Henderson                 /*
2693b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
2694b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
2695b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
2696b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
2697b4fc67c7SRichard Henderson                  * little to be gained by iterating.
2698b4fc67c7SRichard Henderson                  */
2699b4fc67c7SRichard Henderson                 remove = true;
2700b4fc67c7SRichard Henderson             } else {
2701b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
2702b4fc67c7SRichard Henderson                 dead = false;
2703b4fc67c7SRichard Henderson                 remove = false;
2704b4fc67c7SRichard Henderson 
2705b4fc67c7SRichard Henderson                 /*
2706b4fc67c7SRichard Henderson                  * Optimization can fold conditional branches to unconditional.
2707b4fc67c7SRichard Henderson                  * If we find a label with one reference which is preceded by
2708b4fc67c7SRichard Henderson                  * an unconditional branch to it, remove both.  This needed to
2709b4fc67c7SRichard Henderson                  * wait until the dead code in between them was removed.
2710b4fc67c7SRichard Henderson                  */
2711b4fc67c7SRichard Henderson                 if (label->refs == 1) {
2712eae3eb3eSPaolo Bonzini                     TCGOp *op_prev = QTAILQ_PREV(op, link);
2713b4fc67c7SRichard Henderson                     if (op_prev->opc == INDEX_op_br &&
2714b4fc67c7SRichard Henderson                         label == arg_label(op_prev->args[0])) {
2715b4fc67c7SRichard Henderson                         tcg_op_remove(s, op_prev);
2716b4fc67c7SRichard Henderson                         remove = true;
2717b4fc67c7SRichard Henderson                     }
2718b4fc67c7SRichard Henderson                 }
2719b4fc67c7SRichard Henderson             }
2720b4fc67c7SRichard Henderson             break;
2721b4fc67c7SRichard Henderson 
2722b4fc67c7SRichard Henderson         case INDEX_op_br:
2723b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
2724b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
2725b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
2726b4fc67c7SRichard Henderson             dead = true;
2727b4fc67c7SRichard Henderson             break;
2728b4fc67c7SRichard Henderson 
2729b4fc67c7SRichard Henderson         case INDEX_op_call:
2730b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
2731b4fc67c7SRichard Henderson             call_flags = op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1];
2732b4fc67c7SRichard Henderson             if (call_flags & TCG_CALL_NO_RETURN) {
2733b4fc67c7SRichard Henderson                 dead = true;
2734b4fc67c7SRichard Henderson             }
2735b4fc67c7SRichard Henderson             break;
2736b4fc67c7SRichard Henderson 
2737b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
2738b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
2739b4fc67c7SRichard Henderson             remove = false;
2740b4fc67c7SRichard Henderson             break;
2741b4fc67c7SRichard Henderson 
2742b4fc67c7SRichard Henderson         default:
2743b4fc67c7SRichard Henderson             break;
2744b4fc67c7SRichard Henderson         }
2745b4fc67c7SRichard Henderson 
2746b4fc67c7SRichard Henderson         if (remove) {
2747b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
2748b4fc67c7SRichard Henderson         }
2749b4fc67c7SRichard Henderson     }
2750b4fc67c7SRichard Henderson }
2751b4fc67c7SRichard Henderson 
2752c70fbf0aSRichard Henderson #define TS_DEAD  1
2753c70fbf0aSRichard Henderson #define TS_MEM   2
2754c70fbf0aSRichard Henderson 
27555a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
27565a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
27575a18407fSRichard Henderson 
275825f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
275925f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
276025f49c5fSRichard Henderson {
276125f49c5fSRichard Henderson     return ts->state_ptr;
276225f49c5fSRichard Henderson }
276325f49c5fSRichard Henderson 
276425f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
276525f49c5fSRichard Henderson  * maximal regset for its type.
276625f49c5fSRichard Henderson  */
276725f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
276825f49c5fSRichard Henderson {
276925f49c5fSRichard Henderson     *la_temp_pref(ts)
277025f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
277125f49c5fSRichard Henderson }
277225f49c5fSRichard Henderson 
27739c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
27749c43b68dSAurelien Jarno    should be in memory. */
27752616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
2776c896fe29Sbellard {
2777b83eabeaSRichard Henderson     int i;
2778b83eabeaSRichard Henderson 
2779b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2780b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
278125f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2782b83eabeaSRichard Henderson     }
2783b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2784b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
278525f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2786b83eabeaSRichard Henderson     }
2787c896fe29Sbellard }
2788c896fe29Sbellard 
27899c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
27909c43b68dSAurelien Jarno    and local temps should be in memory. */
27912616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
2792641d5fbeSbellard {
2793b83eabeaSRichard Henderson     int i;
2794641d5fbeSbellard 
2795ee17db83SRichard Henderson     for (i = 0; i < nt; ++i) {
2796ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2797ee17db83SRichard Henderson         int state;
2798ee17db83SRichard Henderson 
2799ee17db83SRichard Henderson         switch (ts->kind) {
2800ee17db83SRichard Henderson         case TEMP_FIXED:
2801ee17db83SRichard Henderson         case TEMP_GLOBAL:
2802ee17db83SRichard Henderson         case TEMP_LOCAL:
2803ee17db83SRichard Henderson             state = TS_DEAD | TS_MEM;
2804ee17db83SRichard Henderson             break;
2805ee17db83SRichard Henderson         case TEMP_NORMAL:
2806c0522136SRichard Henderson         case TEMP_CONST:
2807ee17db83SRichard Henderson             state = TS_DEAD;
2808ee17db83SRichard Henderson             break;
2809ee17db83SRichard Henderson         default:
2810ee17db83SRichard Henderson             g_assert_not_reached();
2811c70fbf0aSRichard Henderson         }
2812ee17db83SRichard Henderson         ts->state = state;
2813ee17db83SRichard Henderson         la_reset_pref(ts);
2814641d5fbeSbellard     }
2815641d5fbeSbellard }
2816641d5fbeSbellard 
2817f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
2818f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
2819f65a061cSRichard Henderson {
2820f65a061cSRichard Henderson     int i;
2821f65a061cSRichard Henderson 
2822f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
282325f49c5fSRichard Henderson         int state = s->temps[i].state;
282425f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
282525f49c5fSRichard Henderson         if (state == TS_DEAD) {
282625f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
282725f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
282825f49c5fSRichard Henderson         }
2829f65a061cSRichard Henderson     }
2830f65a061cSRichard Henderson }
2831f65a061cSRichard Henderson 
2832b4cb76e6SRichard Henderson /*
2833b4cb76e6SRichard Henderson  * liveness analysis: conditional branch: all temps are dead,
2834b4cb76e6SRichard Henderson  * globals and local temps should be synced.
2835b4cb76e6SRichard Henderson  */
2836b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
2837b4cb76e6SRichard Henderson {
2838b4cb76e6SRichard Henderson     la_global_sync(s, ng);
2839b4cb76e6SRichard Henderson 
2840b4cb76e6SRichard Henderson     for (int i = ng; i < nt; ++i) {
2841c0522136SRichard Henderson         TCGTemp *ts = &s->temps[i];
2842c0522136SRichard Henderson         int state;
2843c0522136SRichard Henderson 
2844c0522136SRichard Henderson         switch (ts->kind) {
2845c0522136SRichard Henderson         case TEMP_LOCAL:
2846c0522136SRichard Henderson             state = ts->state;
2847c0522136SRichard Henderson             ts->state = state | TS_MEM;
2848b4cb76e6SRichard Henderson             if (state != TS_DEAD) {
2849b4cb76e6SRichard Henderson                 continue;
2850b4cb76e6SRichard Henderson             }
2851c0522136SRichard Henderson             break;
2852c0522136SRichard Henderson         case TEMP_NORMAL:
2853b4cb76e6SRichard Henderson             s->temps[i].state = TS_DEAD;
2854c0522136SRichard Henderson             break;
2855c0522136SRichard Henderson         case TEMP_CONST:
2856c0522136SRichard Henderson             continue;
2857c0522136SRichard Henderson         default:
2858c0522136SRichard Henderson             g_assert_not_reached();
2859b4cb76e6SRichard Henderson         }
2860b4cb76e6SRichard Henderson         la_reset_pref(&s->temps[i]);
2861b4cb76e6SRichard Henderson     }
2862b4cb76e6SRichard Henderson }
2863b4cb76e6SRichard Henderson 
2864f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
2865f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
2866f65a061cSRichard Henderson {
2867f65a061cSRichard Henderson     int i;
2868f65a061cSRichard Henderson 
2869f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
2870f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
287125f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
287225f49c5fSRichard Henderson     }
287325f49c5fSRichard Henderson }
287425f49c5fSRichard Henderson 
287525f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
287625f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
287725f49c5fSRichard Henderson {
287825f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
287925f49c5fSRichard Henderson     int i;
288025f49c5fSRichard Henderson 
288125f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
288225f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
288325f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
288425f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
288525f49c5fSRichard Henderson             TCGRegSet set = *pset;
288625f49c5fSRichard Henderson 
288725f49c5fSRichard Henderson             set &= mask;
288825f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
288925f49c5fSRichard Henderson             if (set == 0) {
289025f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
289125f49c5fSRichard Henderson             }
289225f49c5fSRichard Henderson             *pset = set;
289325f49c5fSRichard Henderson         }
2894f65a061cSRichard Henderson     }
2895f65a061cSRichard Henderson }
2896f65a061cSRichard Henderson 
2897a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
2898c896fe29Sbellard    given input arguments is dead. Instructions updating dead
2899c896fe29Sbellard    temporaries are removed. */
2900b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s)
2901c896fe29Sbellard {
2902c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
29032616c808SRichard Henderson     int nb_temps = s->nb_temps;
290415fa08f8SRichard Henderson     TCGOp *op, *op_prev;
290525f49c5fSRichard Henderson     TCGRegSet *prefs;
290625f49c5fSRichard Henderson     int i;
290725f49c5fSRichard Henderson 
290825f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
290925f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
291025f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
291125f49c5fSRichard Henderson     }
2912c896fe29Sbellard 
2913ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
29142616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
2915c896fe29Sbellard 
2916eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
291725f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
2918c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
2919c45cb8bbSRichard Henderson         bool have_opc_new2;
2920a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
292125f49c5fSRichard Henderson         TCGTemp *ts;
2922c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2923c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2924c45cb8bbSRichard Henderson 
2925c45cb8bbSRichard Henderson         switch (opc) {
2926c896fe29Sbellard         case INDEX_op_call:
2927c6e113f5Sbellard             {
2928c6e113f5Sbellard                 int call_flags;
292925f49c5fSRichard Henderson                 int nb_call_regs;
2930c6e113f5Sbellard 
2931cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
2932cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
2933efee3746SRichard Henderson                 call_flags = op->args[nb_oargs + nb_iargs + 1];
2934c6e113f5Sbellard 
2935c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
293678505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
2937c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
293825f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
293925f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
2940c6e113f5Sbellard                             goto do_not_remove_call;
2941c6e113f5Sbellard                         }
29429c43b68dSAurelien Jarno                     }
2943c45cb8bbSRichard Henderson                     goto do_remove;
2944152c35aaSRichard Henderson                 }
2945c6e113f5Sbellard             do_not_remove_call:
2946c896fe29Sbellard 
294725f49c5fSRichard Henderson                 /* Output args are dead.  */
2948c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
294925f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
295025f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
2951a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
29526b64b624SAurelien Jarno                     }
295325f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
2954a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
29559c43b68dSAurelien Jarno                     }
295625f49c5fSRichard Henderson                     ts->state = TS_DEAD;
295725f49c5fSRichard Henderson                     la_reset_pref(ts);
295825f49c5fSRichard Henderson 
295925f49c5fSRichard Henderson                     /* Not used -- it will be tcg_target_call_oarg_regs[i].  */
296025f49c5fSRichard Henderson                     op->output_pref[i] = 0;
2961c896fe29Sbellard                 }
2962c896fe29Sbellard 
296378505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
296478505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
2965f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
2966c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
2967f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
2968b9c18f56Saurel32                 }
2969c896fe29Sbellard 
297025f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
2971866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
297225f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
297325f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
2974a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
2975c896fe29Sbellard                     }
2976c896fe29Sbellard                 }
297725f49c5fSRichard Henderson 
297825f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
297925f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
298025f49c5fSRichard Henderson 
298125f49c5fSRichard Henderson                 nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
298225f49c5fSRichard Henderson 
298325f49c5fSRichard Henderson                 /* Input arguments are live for preceding opcodes.  */
298425f49c5fSRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
298525f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
298625f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
298725f49c5fSRichard Henderson                         /* For those arguments that die, and will be allocated
298825f49c5fSRichard Henderson                          * in registers, clear the register set for that arg,
298925f49c5fSRichard Henderson                          * to be filled in below.  For args that will be on
299025f49c5fSRichard Henderson                          * the stack, reset to any available reg.
299125f49c5fSRichard Henderson                          */
299225f49c5fSRichard Henderson                         *la_temp_pref(ts)
299325f49c5fSRichard Henderson                             = (i < nb_call_regs ? 0 :
299425f49c5fSRichard Henderson                                tcg_target_available_regs[ts->type]);
299525f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
299625f49c5fSRichard Henderson                     }
299725f49c5fSRichard Henderson                 }
299825f49c5fSRichard Henderson 
299925f49c5fSRichard Henderson                 /* For each input argument, add its input register to prefs.
300025f49c5fSRichard Henderson                    If a temp is used once, this produces a single set bit.  */
300125f49c5fSRichard Henderson                 for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) {
300225f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
300325f49c5fSRichard Henderson                     if (ts) {
300425f49c5fSRichard Henderson                         tcg_regset_set_reg(*la_temp_pref(ts),
300525f49c5fSRichard Henderson                                            tcg_target_call_iarg_regs[i]);
3006c70fbf0aSRichard Henderson                     }
3007c19f47bfSAurelien Jarno                 }
3008c6e113f5Sbellard             }
3009c896fe29Sbellard             break;
3010765b842aSRichard Henderson         case INDEX_op_insn_start:
3011c896fe29Sbellard             break;
30125ff9d6a4Sbellard         case INDEX_op_discard:
30135ff9d6a4Sbellard             /* mark the temporary as dead */
301425f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
301525f49c5fSRichard Henderson             ts->state = TS_DEAD;
301625f49c5fSRichard Henderson             la_reset_pref(ts);
30175ff9d6a4Sbellard             break;
30181305c451SRichard Henderson 
30191305c451SRichard Henderson         case INDEX_op_add2_i32:
3020c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
3021f1fae40cSRichard Henderson             goto do_addsub2;
30221305c451SRichard Henderson         case INDEX_op_sub2_i32:
3023c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
3024f1fae40cSRichard Henderson             goto do_addsub2;
3025f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
3026c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
3027f1fae40cSRichard Henderson             goto do_addsub2;
3028f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
3029c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
3030f1fae40cSRichard Henderson         do_addsub2:
30311305c451SRichard Henderson             nb_iargs = 4;
30321305c451SRichard Henderson             nb_oargs = 2;
30331305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
30341305c451SRichard Henderson                the low part.  The result can be optimized to a simple
30351305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
30361305c451SRichard Henderson                cpu mode is set to 32 bit.  */
3037b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
3038b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
30391305c451SRichard Henderson                     goto do_remove;
30401305c451SRichard Henderson                 }
3041c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
3042c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
3043c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
3044efee3746SRichard Henderson                 op->args[1] = op->args[2];
3045efee3746SRichard Henderson                 op->args[2] = op->args[4];
30461305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
30471305c451SRichard Henderson                 nb_iargs = 2;
30481305c451SRichard Henderson                 nb_oargs = 1;
30491305c451SRichard Henderson             }
30501305c451SRichard Henderson             goto do_not_remove;
30511305c451SRichard Henderson 
30521414968aSRichard Henderson         case INDEX_op_mulu2_i32:
3053c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
3054c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
3055c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
305603271524SRichard Henderson             goto do_mul2;
3057f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
3058c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
3059c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
3060c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
3061f1fae40cSRichard Henderson             goto do_mul2;
3062f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
3063c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
3064c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
3065c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
306603271524SRichard Henderson             goto do_mul2;
3067f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
3068c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
3069c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
3070c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
307103271524SRichard Henderson             goto do_mul2;
3072f1fae40cSRichard Henderson         do_mul2:
30731414968aSRichard Henderson             nb_iargs = 2;
30741414968aSRichard Henderson             nb_oargs = 2;
3075b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
3076b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
307703271524SRichard Henderson                     /* Both parts of the operation are dead.  */
30781414968aSRichard Henderson                     goto do_remove;
30791414968aSRichard Henderson                 }
308003271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
3081c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
3082efee3746SRichard Henderson                 op->args[1] = op->args[2];
3083efee3746SRichard Henderson                 op->args[2] = op->args[3];
3084b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
308503271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
3086c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
3087efee3746SRichard Henderson                 op->args[0] = op->args[1];
3088efee3746SRichard Henderson                 op->args[1] = op->args[2];
3089efee3746SRichard Henderson                 op->args[2] = op->args[3];
309003271524SRichard Henderson             } else {
309103271524SRichard Henderson                 goto do_not_remove;
309203271524SRichard Henderson             }
309303271524SRichard Henderson             /* Mark the single-word operation live.  */
30941414968aSRichard Henderson             nb_oargs = 1;
30951414968aSRichard Henderson             goto do_not_remove;
30961414968aSRichard Henderson 
3097c896fe29Sbellard         default:
30981305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
3099c896fe29Sbellard             nb_iargs = def->nb_iargs;
3100c896fe29Sbellard             nb_oargs = def->nb_oargs;
3101c896fe29Sbellard 
3102c896fe29Sbellard             /* Test if the operation can be removed because all
31035ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
31045ff9d6a4Sbellard                implies side effects */
31055ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
3106c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
3107b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
3108c896fe29Sbellard                         goto do_not_remove;
3109c896fe29Sbellard                     }
31109c43b68dSAurelien Jarno                 }
3111152c35aaSRichard Henderson                 goto do_remove;
3112152c35aaSRichard Henderson             }
3113152c35aaSRichard Henderson             goto do_not_remove;
3114152c35aaSRichard Henderson 
31151305c451SRichard Henderson         do_remove:
31160c627cdcSRichard Henderson             tcg_op_remove(s, op);
3117152c35aaSRichard Henderson             break;
3118152c35aaSRichard Henderson 
3119c896fe29Sbellard         do_not_remove:
3120c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
312125f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
312225f49c5fSRichard Henderson 
312325f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
312425f49c5fSRichard Henderson                 op->output_pref[i] = *la_temp_pref(ts);
312525f49c5fSRichard Henderson 
312625f49c5fSRichard Henderson                 /* Output args are dead.  */
312725f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
3128a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
31296b64b624SAurelien Jarno                 }
313025f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
3131a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
31329c43b68dSAurelien Jarno                 }
313325f49c5fSRichard Henderson                 ts->state = TS_DEAD;
313425f49c5fSRichard Henderson                 la_reset_pref(ts);
3135c896fe29Sbellard             }
3136c896fe29Sbellard 
313725f49c5fSRichard Henderson             /* If end of basic block, update.  */
3138ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
3139ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
3140b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_COND_BRANCH) {
3141b4cb76e6SRichard Henderson                 la_bb_sync(s, nb_globals, nb_temps);
3142ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
31432616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
31443d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
3145f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
314625f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
314725f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
314825f49c5fSRichard Henderson                 }
3149c896fe29Sbellard             }
3150c896fe29Sbellard 
315125f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
3152866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
315325f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
315425f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
3155a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
3156c896fe29Sbellard                 }
3157c19f47bfSAurelien Jarno             }
315825f49c5fSRichard Henderson 
315925f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
3160c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
316125f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
316225f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
316325f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
316425f49c5fSRichard Henderson                        all regs for the type.  */
316525f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
316625f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
316725f49c5fSRichard Henderson                 }
316825f49c5fSRichard Henderson             }
316925f49c5fSRichard Henderson 
317025f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
317125f49c5fSRichard Henderson             switch (opc) {
317225f49c5fSRichard Henderson             case INDEX_op_mov_i32:
317325f49c5fSRichard Henderson             case INDEX_op_mov_i64:
317425f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
317525f49c5fSRichard Henderson                    have proper constraints.  That said, special case
317625f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
317725f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
317825f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
317925f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
318025f49c5fSRichard Henderson                 }
318125f49c5fSRichard Henderson                 break;
318225f49c5fSRichard Henderson 
318325f49c5fSRichard Henderson             default:
318425f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
318525f49c5fSRichard Henderson                     const TCGArgConstraint *ct = &def->args_ct[i];
318625f49c5fSRichard Henderson                     TCGRegSet set, *pset;
318725f49c5fSRichard Henderson 
318825f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
318925f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
319025f49c5fSRichard Henderson                     set = *pset;
319125f49c5fSRichard Henderson 
31929be0d080SRichard Henderson                     set &= ct->regs;
3193bc2b17e6SRichard Henderson                     if (ct->ialias) {
319425f49c5fSRichard Henderson                         set &= op->output_pref[ct->alias_index];
319525f49c5fSRichard Henderson                     }
319625f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
319725f49c5fSRichard Henderson                     if (set == 0) {
31989be0d080SRichard Henderson                         set = ct->regs;
319925f49c5fSRichard Henderson                     }
320025f49c5fSRichard Henderson                     *pset = set;
320125f49c5fSRichard Henderson                 }
320225f49c5fSRichard Henderson                 break;
3203c896fe29Sbellard             }
3204c896fe29Sbellard             break;
3205c896fe29Sbellard         }
3206bee158cbSRichard Henderson         op->life = arg_life;
3207c896fe29Sbellard     }
32081ff0a2c5SEvgeny Voevodin }
3209c896fe29Sbellard 
32105a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
3211b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s)
32125a18407fSRichard Henderson {
32135a18407fSRichard Henderson     int nb_globals = s->nb_globals;
321415fa08f8SRichard Henderson     int nb_temps, i;
32155a18407fSRichard Henderson     bool changes = false;
321615fa08f8SRichard Henderson     TCGOp *op, *op_next;
32175a18407fSRichard Henderson 
32185a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
32195a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
32205a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
32215a18407fSRichard Henderson         if (its->indirect_reg) {
32225a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
32235a18407fSRichard Henderson             dts->type = its->type;
32245a18407fSRichard Henderson             dts->base_type = its->base_type;
3225b83eabeaSRichard Henderson             its->state_ptr = dts;
3226b83eabeaSRichard Henderson         } else {
3227b83eabeaSRichard Henderson             its->state_ptr = NULL;
32285a18407fSRichard Henderson         }
3229b83eabeaSRichard Henderson         /* All globals begin dead.  */
3230b83eabeaSRichard Henderson         its->state = TS_DEAD;
32315a18407fSRichard Henderson     }
3232b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
3233b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
3234b83eabeaSRichard Henderson         its->state_ptr = NULL;
3235b83eabeaSRichard Henderson         its->state = TS_DEAD;
3236b83eabeaSRichard Henderson     }
32375a18407fSRichard Henderson 
323815fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
32395a18407fSRichard Henderson         TCGOpcode opc = op->opc;
32405a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
32415a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
32425a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
3243b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
32445a18407fSRichard Henderson 
32455a18407fSRichard Henderson         if (opc == INDEX_op_call) {
3246cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
3247cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
3248efee3746SRichard Henderson             call_flags = op->args[nb_oargs + nb_iargs + 1];
32495a18407fSRichard Henderson         } else {
32505a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
32515a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
32525a18407fSRichard Henderson 
32535a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
3254b4cb76e6SRichard Henderson             if (def->flags & TCG_OPF_COND_BRANCH) {
3255b4cb76e6SRichard Henderson                 /* Like reading globals: sync_globals */
3256b4cb76e6SRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
3257b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
32585a18407fSRichard Henderson                 /* Like writing globals: save_globals */
32595a18407fSRichard Henderson                 call_flags = 0;
32605a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
32615a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
32625a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
32635a18407fSRichard Henderson             } else {
32645a18407fSRichard Henderson                 /* No effect on globals.  */
32655a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
32665a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
32675a18407fSRichard Henderson             }
32685a18407fSRichard Henderson         }
32695a18407fSRichard Henderson 
32705a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
32715a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3272b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3273b83eabeaSRichard Henderson             if (arg_ts) {
3274b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3275b83eabeaSRichard Henderson                 if (dir_ts && arg_ts->state == TS_DEAD) {
3276b83eabeaSRichard Henderson                     TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
32775a18407fSRichard Henderson                                       ? INDEX_op_ld_i32
32785a18407fSRichard Henderson                                       : INDEX_op_ld_i64);
3279ac1043f6SEmilio G. Cota                     TCGOp *lop = tcg_op_insert_before(s, op, lopc);
32805a18407fSRichard Henderson 
3281b83eabeaSRichard Henderson                     lop->args[0] = temp_arg(dir_ts);
3282b83eabeaSRichard Henderson                     lop->args[1] = temp_arg(arg_ts->mem_base);
3283b83eabeaSRichard Henderson                     lop->args[2] = arg_ts->mem_offset;
32845a18407fSRichard Henderson 
32855a18407fSRichard Henderson                     /* Loaded, but synced with memory.  */
3286b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
32875a18407fSRichard Henderson                 }
32885a18407fSRichard Henderson             }
32895a18407fSRichard Henderson         }
32905a18407fSRichard Henderson 
32915a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
32925a18407fSRichard Henderson            No action is required except keeping temp_state up to date
32935a18407fSRichard Henderson            so that we reload when needed.  */
32945a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3295b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3296b83eabeaSRichard Henderson             if (arg_ts) {
3297b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3298b83eabeaSRichard Henderson                 if (dir_ts) {
3299b83eabeaSRichard Henderson                     op->args[i] = temp_arg(dir_ts);
33005a18407fSRichard Henderson                     changes = true;
33015a18407fSRichard Henderson                     if (IS_DEAD_ARG(i)) {
3302b83eabeaSRichard Henderson                         arg_ts->state = TS_DEAD;
33035a18407fSRichard Henderson                     }
33045a18407fSRichard Henderson                 }
33055a18407fSRichard Henderson             }
33065a18407fSRichard Henderson         }
33075a18407fSRichard Henderson 
33085a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
33095a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
33105a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
33115a18407fSRichard Henderson             /* Nothing to do */
33125a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
33135a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
33145a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
33155a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
3316b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3317b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3318b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
33195a18407fSRichard Henderson             }
33205a18407fSRichard Henderson         } else {
33215a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
33225a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
33235a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
3324b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3325b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3326b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
33275a18407fSRichard Henderson             }
33285a18407fSRichard Henderson         }
33295a18407fSRichard Henderson 
33305a18407fSRichard Henderson         /* Outputs become available.  */
333161f15c48SRichard Henderson         if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) {
333261f15c48SRichard Henderson             arg_ts = arg_temp(op->args[0]);
333361f15c48SRichard Henderson             dir_ts = arg_ts->state_ptr;
333461f15c48SRichard Henderson             if (dir_ts) {
333561f15c48SRichard Henderson                 op->args[0] = temp_arg(dir_ts);
333661f15c48SRichard Henderson                 changes = true;
333761f15c48SRichard Henderson 
333861f15c48SRichard Henderson                 /* The output is now live and modified.  */
333961f15c48SRichard Henderson                 arg_ts->state = 0;
334061f15c48SRichard Henderson 
334161f15c48SRichard Henderson                 if (NEED_SYNC_ARG(0)) {
334261f15c48SRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
334361f15c48SRichard Henderson                                       ? INDEX_op_st_i32
334461f15c48SRichard Henderson                                       : INDEX_op_st_i64);
334561f15c48SRichard Henderson                     TCGOp *sop = tcg_op_insert_after(s, op, sopc);
334661f15c48SRichard Henderson                     TCGTemp *out_ts = dir_ts;
334761f15c48SRichard Henderson 
334861f15c48SRichard Henderson                     if (IS_DEAD_ARG(0)) {
334961f15c48SRichard Henderson                         out_ts = arg_temp(op->args[1]);
335061f15c48SRichard Henderson                         arg_ts->state = TS_DEAD;
335161f15c48SRichard Henderson                         tcg_op_remove(s, op);
335261f15c48SRichard Henderson                     } else {
335361f15c48SRichard Henderson                         arg_ts->state = TS_MEM;
335461f15c48SRichard Henderson                     }
335561f15c48SRichard Henderson 
335661f15c48SRichard Henderson                     sop->args[0] = temp_arg(out_ts);
335761f15c48SRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
335861f15c48SRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
335961f15c48SRichard Henderson                 } else {
336061f15c48SRichard Henderson                     tcg_debug_assert(!IS_DEAD_ARG(0));
336161f15c48SRichard Henderson                 }
336261f15c48SRichard Henderson             }
336361f15c48SRichard Henderson         } else {
33645a18407fSRichard Henderson             for (i = 0; i < nb_oargs; i++) {
3365b83eabeaSRichard Henderson                 arg_ts = arg_temp(op->args[i]);
3366b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3367b83eabeaSRichard Henderson                 if (!dir_ts) {
33685a18407fSRichard Henderson                     continue;
33695a18407fSRichard Henderson                 }
3370b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
33715a18407fSRichard Henderson                 changes = true;
33725a18407fSRichard Henderson 
33735a18407fSRichard Henderson                 /* The output is now live and modified.  */
3374b83eabeaSRichard Henderson                 arg_ts->state = 0;
33755a18407fSRichard Henderson 
33765a18407fSRichard Henderson                 /* Sync outputs upon their last write.  */
33775a18407fSRichard Henderson                 if (NEED_SYNC_ARG(i)) {
3378b83eabeaSRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
33795a18407fSRichard Henderson                                       ? INDEX_op_st_i32
33805a18407fSRichard Henderson                                       : INDEX_op_st_i64);
3381ac1043f6SEmilio G. Cota                     TCGOp *sop = tcg_op_insert_after(s, op, sopc);
33825a18407fSRichard Henderson 
3383b83eabeaSRichard Henderson                     sop->args[0] = temp_arg(dir_ts);
3384b83eabeaSRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
3385b83eabeaSRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
33865a18407fSRichard Henderson 
3387b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
33885a18407fSRichard Henderson                 }
33895a18407fSRichard Henderson                 /* Drop outputs that are dead.  */
33905a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3391b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
33925a18407fSRichard Henderson                 }
33935a18407fSRichard Henderson             }
33945a18407fSRichard Henderson         }
339561f15c48SRichard Henderson     }
33965a18407fSRichard Henderson 
33975a18407fSRichard Henderson     return changes;
33985a18407fSRichard Henderson }
33995a18407fSRichard Henderson 
34008d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
3401c896fe29Sbellard static void dump_regs(TCGContext *s)
3402c896fe29Sbellard {
3403c896fe29Sbellard     TCGTemp *ts;
3404c896fe29Sbellard     int i;
3405c896fe29Sbellard     char buf[64];
3406c896fe29Sbellard 
3407c896fe29Sbellard     for(i = 0; i < s->nb_temps; i++) {
3408c896fe29Sbellard         ts = &s->temps[i];
340943439139SRichard Henderson         printf("  %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3410c896fe29Sbellard         switch(ts->val_type) {
3411c896fe29Sbellard         case TEMP_VAL_REG:
3412c896fe29Sbellard             printf("%s", tcg_target_reg_names[ts->reg]);
3413c896fe29Sbellard             break;
3414c896fe29Sbellard         case TEMP_VAL_MEM:
3415b3a62939SRichard Henderson             printf("%d(%s)", (int)ts->mem_offset,
3416b3a62939SRichard Henderson                    tcg_target_reg_names[ts->mem_base->reg]);
3417c896fe29Sbellard             break;
3418c896fe29Sbellard         case TEMP_VAL_CONST:
3419bdb38b95SRichard Henderson             printf("$0x%" PRIx64, ts->val);
3420c896fe29Sbellard             break;
3421c896fe29Sbellard         case TEMP_VAL_DEAD:
3422c896fe29Sbellard             printf("D");
3423c896fe29Sbellard             break;
3424c896fe29Sbellard         default:
3425c896fe29Sbellard             printf("???");
3426c896fe29Sbellard             break;
3427c896fe29Sbellard         }
3428c896fe29Sbellard         printf("\n");
3429c896fe29Sbellard     }
3430c896fe29Sbellard 
3431c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
3432f8b2f202SRichard Henderson         if (s->reg_to_temp[i] != NULL) {
3433c896fe29Sbellard             printf("%s: %s\n",
3434c896fe29Sbellard                    tcg_target_reg_names[i],
3435f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i]));
3436c896fe29Sbellard         }
3437c896fe29Sbellard     }
3438c896fe29Sbellard }
3439c896fe29Sbellard 
3440c896fe29Sbellard static void check_regs(TCGContext *s)
3441c896fe29Sbellard {
3442869938aeSRichard Henderson     int reg;
3443b6638662SRichard Henderson     int k;
3444c896fe29Sbellard     TCGTemp *ts;
3445c896fe29Sbellard     char buf[64];
3446c896fe29Sbellard 
3447c896fe29Sbellard     for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
3448f8b2f202SRichard Henderson         ts = s->reg_to_temp[reg];
3449f8b2f202SRichard Henderson         if (ts != NULL) {
3450f8b2f202SRichard Henderson             if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) {
3451c896fe29Sbellard                 printf("Inconsistency for register %s:\n",
3452c896fe29Sbellard                        tcg_target_reg_names[reg]);
3453b03cce8eSbellard                 goto fail;
3454c896fe29Sbellard             }
3455c896fe29Sbellard         }
3456c896fe29Sbellard     }
3457c896fe29Sbellard     for (k = 0; k < s->nb_temps; k++) {
3458c896fe29Sbellard         ts = &s->temps[k];
3459ee17db83SRichard Henderson         if (ts->val_type == TEMP_VAL_REG
3460ee17db83SRichard Henderson             && ts->kind != TEMP_FIXED
3461f8b2f202SRichard Henderson             && s->reg_to_temp[ts->reg] != ts) {
3462c896fe29Sbellard             printf("Inconsistency for temp %s:\n",
3463f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3464b03cce8eSbellard         fail:
3465c896fe29Sbellard             printf("reg state:\n");
3466c896fe29Sbellard             dump_regs(s);
3467c896fe29Sbellard             tcg_abort();
3468c896fe29Sbellard         }
3469c896fe29Sbellard     }
3470c896fe29Sbellard }
3471c896fe29Sbellard #endif
3472c896fe29Sbellard 
34732272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
3474c896fe29Sbellard {
34759b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64)
34769b9c37c3SRichard Henderson     /* Sparc64 stack is accessed with offset of 2047 */
3477b591dc59SBlue Swirl     s->current_frame_offset = (s->current_frame_offset +
3478b591dc59SBlue Swirl                                (tcg_target_long)sizeof(tcg_target_long) - 1) &
3479b591dc59SBlue Swirl         ~(sizeof(tcg_target_long) - 1);
3480f44c9960SBlue Swirl #endif
3481b591dc59SBlue Swirl     if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
3482b591dc59SBlue Swirl         s->frame_end) {
34835ff9d6a4Sbellard         tcg_abort();
3484b591dc59SBlue Swirl     }
3485c896fe29Sbellard     ts->mem_offset = s->current_frame_offset;
3486b3a62939SRichard Henderson     ts->mem_base = s->frame_temp;
3487c896fe29Sbellard     ts->mem_allocated = 1;
3488e2c6d1b4SRichard Henderson     s->current_frame_offset += sizeof(tcg_target_long);
3489c896fe29Sbellard }
3490c896fe29Sbellard 
3491b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
3492b3915dbbSRichard Henderson 
349359d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
349459d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
349559d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
3496c896fe29Sbellard {
3497c0522136SRichard Henderson     TCGTempVal new_type;
3498c0522136SRichard Henderson 
3499c0522136SRichard Henderson     switch (ts->kind) {
3500c0522136SRichard Henderson     case TEMP_FIXED:
350159d7c14eSRichard Henderson         return;
3502c0522136SRichard Henderson     case TEMP_GLOBAL:
3503c0522136SRichard Henderson     case TEMP_LOCAL:
3504c0522136SRichard Henderson         new_type = TEMP_VAL_MEM;
3505c0522136SRichard Henderson         break;
3506c0522136SRichard Henderson     case TEMP_NORMAL:
3507c0522136SRichard Henderson         new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD;
3508c0522136SRichard Henderson         break;
3509c0522136SRichard Henderson     case TEMP_CONST:
3510c0522136SRichard Henderson         new_type = TEMP_VAL_CONST;
3511c0522136SRichard Henderson         break;
3512c0522136SRichard Henderson     default:
3513c0522136SRichard Henderson         g_assert_not_reached();
351459d7c14eSRichard Henderson     }
351559d7c14eSRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
351659d7c14eSRichard Henderson         s->reg_to_temp[ts->reg] = NULL;
351759d7c14eSRichard Henderson     }
3518c0522136SRichard Henderson     ts->val_type = new_type;
351959d7c14eSRichard Henderson }
3520c896fe29Sbellard 
352159d7c14eSRichard Henderson /* Mark a temporary as dead.  */
352259d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
352359d7c14eSRichard Henderson {
352459d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
352559d7c14eSRichard Henderson }
352659d7c14eSRichard Henderson 
352759d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
352859d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
352959d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
353059d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
353198b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
353298b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
353359d7c14eSRichard Henderson {
3534c0522136SRichard Henderson     if (!temp_readonly(ts) && !ts->mem_coherent) {
35357f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
35362272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
353759d7c14eSRichard Henderson         }
353859d7c14eSRichard Henderson         switch (ts->val_type) {
353959d7c14eSRichard Henderson         case TEMP_VAL_CONST:
354059d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
354159d7c14eSRichard Henderson                require it later in a register, so attempt to store the
354259d7c14eSRichard Henderson                constant to memory directly.  */
354359d7c14eSRichard Henderson             if (free_or_dead
354459d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
354559d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
354659d7c14eSRichard Henderson                 break;
354759d7c14eSRichard Henderson             }
354859d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
354998b4e186SRichard Henderson                       allocated_regs, preferred_regs);
355059d7c14eSRichard Henderson             /* fallthrough */
355159d7c14eSRichard Henderson 
355259d7c14eSRichard Henderson         case TEMP_VAL_REG:
355359d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
355459d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
355559d7c14eSRichard Henderson             break;
355659d7c14eSRichard Henderson 
355759d7c14eSRichard Henderson         case TEMP_VAL_MEM:
355859d7c14eSRichard Henderson             break;
355959d7c14eSRichard Henderson 
356059d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
356159d7c14eSRichard Henderson         default:
356259d7c14eSRichard Henderson             tcg_abort();
3563c896fe29Sbellard         }
35647f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
35657f6ceedfSAurelien Jarno     }
356659d7c14eSRichard Henderson     if (free_or_dead) {
356759d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
356859d7c14eSRichard Henderson     }
356959d7c14eSRichard Henderson }
35707f6ceedfSAurelien Jarno 
35717f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
3572b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
35737f6ceedfSAurelien Jarno {
3574f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
3575f8b2f202SRichard Henderson     if (ts != NULL) {
357698b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
3577c896fe29Sbellard     }
3578c896fe29Sbellard }
3579c896fe29Sbellard 
3580b016486eSRichard Henderson /**
3581b016486eSRichard Henderson  * tcg_reg_alloc:
3582b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
3583b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
3584b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
3585b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
3586b016486eSRichard Henderson  *
3587b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
3588b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
3589b016486eSRichard Henderson  */
3590b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
3591b016486eSRichard Henderson                             TCGRegSet allocated_regs,
3592b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
3593c896fe29Sbellard {
3594b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
3595b016486eSRichard Henderson     TCGRegSet reg_ct[2];
359691478cefSRichard Henderson     const int *order;
3597c896fe29Sbellard 
3598b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
3599b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
3600b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
3601b016486eSRichard Henderson 
3602b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
3603b016486eSRichard Henderson        or if the preference made no difference.  */
3604b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
3605b016486eSRichard Henderson 
360691478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
3607c896fe29Sbellard 
3608b016486eSRichard Henderson     /* Try free registers, preferences first.  */
3609b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3610b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3611b016486eSRichard Henderson 
3612b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3613b016486eSRichard Henderson             /* One register in the set.  */
3614b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3615b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
3616c896fe29Sbellard                 return reg;
3617c896fe29Sbellard             }
3618b016486eSRichard Henderson         } else {
361991478cefSRichard Henderson             for (i = 0; i < n; i++) {
3620b016486eSRichard Henderson                 TCGReg reg = order[i];
3621b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
3622b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
3623b016486eSRichard Henderson                     return reg;
3624b016486eSRichard Henderson                 }
3625b016486eSRichard Henderson             }
3626b016486eSRichard Henderson         }
3627b016486eSRichard Henderson     }
3628b016486eSRichard Henderson 
3629b016486eSRichard Henderson     /* We must spill something.  */
3630b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3631b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3632b016486eSRichard Henderson 
3633b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3634b016486eSRichard Henderson             /* One register in the set.  */
3635b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3636b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
3637c896fe29Sbellard             return reg;
3638b016486eSRichard Henderson         } else {
3639b016486eSRichard Henderson             for (i = 0; i < n; i++) {
3640b016486eSRichard Henderson                 TCGReg reg = order[i];
3641b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
3642b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
3643b016486eSRichard Henderson                     return reg;
3644b016486eSRichard Henderson                 }
3645b016486eSRichard Henderson             }
3646c896fe29Sbellard         }
3647c896fe29Sbellard     }
3648c896fe29Sbellard 
3649c896fe29Sbellard     tcg_abort();
3650c896fe29Sbellard }
3651c896fe29Sbellard 
365240ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
365340ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
365440ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
3655b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
365640ae5c62SRichard Henderson {
365740ae5c62SRichard Henderson     TCGReg reg;
365840ae5c62SRichard Henderson 
365940ae5c62SRichard Henderson     switch (ts->val_type) {
366040ae5c62SRichard Henderson     case TEMP_VAL_REG:
366140ae5c62SRichard Henderson         return;
366240ae5c62SRichard Henderson     case TEMP_VAL_CONST:
3663b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3664b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
36650a6a8bc8SRichard Henderson         if (ts->type <= TCG_TYPE_I64) {
366640ae5c62SRichard Henderson             tcg_out_movi(s, ts->type, reg, ts->val);
36670a6a8bc8SRichard Henderson         } else {
36684e186175SRichard Henderson             uint64_t val = ts->val;
36694e186175SRichard Henderson             MemOp vece = MO_64;
36704e186175SRichard Henderson 
36714e186175SRichard Henderson             /*
36724e186175SRichard Henderson              * Find the minimal vector element that matches the constant.
36734e186175SRichard Henderson              * The targets will, in general, have to do this search anyway,
36744e186175SRichard Henderson              * do this generically.
36754e186175SRichard Henderson              */
36764e186175SRichard Henderson             if (val == dup_const(MO_8, val)) {
36774e186175SRichard Henderson                 vece = MO_8;
36784e186175SRichard Henderson             } else if (val == dup_const(MO_16, val)) {
36794e186175SRichard Henderson                 vece = MO_16;
36800b4286ddSRichard Henderson             } else if (val == dup_const(MO_32, val)) {
36814e186175SRichard Henderson                 vece = MO_32;
36824e186175SRichard Henderson             }
36834e186175SRichard Henderson 
36844e186175SRichard Henderson             tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val);
36850a6a8bc8SRichard Henderson         }
368640ae5c62SRichard Henderson         ts->mem_coherent = 0;
368740ae5c62SRichard Henderson         break;
368840ae5c62SRichard Henderson     case TEMP_VAL_MEM:
3689b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3690b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
369140ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
369240ae5c62SRichard Henderson         ts->mem_coherent = 1;
369340ae5c62SRichard Henderson         break;
369440ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
369540ae5c62SRichard Henderson     default:
369640ae5c62SRichard Henderson         tcg_abort();
369740ae5c62SRichard Henderson     }
369840ae5c62SRichard Henderson     ts->reg = reg;
369940ae5c62SRichard Henderson     ts->val_type = TEMP_VAL_REG;
370040ae5c62SRichard Henderson     s->reg_to_temp[reg] = ts;
370140ae5c62SRichard Henderson }
370240ae5c62SRichard Henderson 
370359d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
3704e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
370559d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
37061ad80729SAurelien Jarno {
37072c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
3708eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
3709e01fa97dSRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts));
37101ad80729SAurelien Jarno }
37111ad80729SAurelien Jarno 
37129814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
3713641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
3714641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
3715641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
3716641d5fbeSbellard {
3717ac3b8891SRichard Henderson     int i, n;
3718641d5fbeSbellard 
3719ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
3720b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
3721641d5fbeSbellard     }
3722e5097dc8Sbellard }
3723e5097dc8Sbellard 
37243d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
37253d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
37263d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
37273d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
37283d5c5f87SAurelien Jarno {
3729ac3b8891SRichard Henderson     int i, n;
37303d5c5f87SAurelien Jarno 
3731ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
373212b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
373312b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
3734ee17db83SRichard Henderson                          || ts->kind == TEMP_FIXED
373512b9b11aSRichard Henderson                          || ts->mem_coherent);
37363d5c5f87SAurelien Jarno     }
37373d5c5f87SAurelien Jarno }
37383d5c5f87SAurelien Jarno 
3739e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
3740e8996ee0Sbellard    all globals are stored at their canonical location. */
3741e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
3742e5097dc8Sbellard {
3743e5097dc8Sbellard     int i;
3744e5097dc8Sbellard 
3745c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
3746b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
3747c0522136SRichard Henderson 
3748c0522136SRichard Henderson         switch (ts->kind) {
3749c0522136SRichard Henderson         case TEMP_LOCAL:
3750b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
3751c0522136SRichard Henderson             break;
3752c0522136SRichard Henderson         case TEMP_NORMAL:
37532c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
3754eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
3755eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3756c0522136SRichard Henderson             break;
3757c0522136SRichard Henderson         case TEMP_CONST:
3758c0522136SRichard Henderson             /* Similarly, we should have freed any allocated register. */
3759c0522136SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_CONST);
3760c0522136SRichard Henderson             break;
3761c0522136SRichard Henderson         default:
3762c0522136SRichard Henderson             g_assert_not_reached();
3763c896fe29Sbellard         }
3764641d5fbeSbellard     }
3765e8996ee0Sbellard 
3766e8996ee0Sbellard     save_globals(s, allocated_regs);
3767c896fe29Sbellard }
3768c896fe29Sbellard 
3769bab1671fSRichard Henderson /*
3770b4cb76e6SRichard Henderson  * At a conditional branch, we assume all temporaries are dead and
3771b4cb76e6SRichard Henderson  * all globals and local temps are synced to their location.
3772b4cb76e6SRichard Henderson  */
3773b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
3774b4cb76e6SRichard Henderson {
3775b4cb76e6SRichard Henderson     sync_globals(s, allocated_regs);
3776b4cb76e6SRichard Henderson 
3777b4cb76e6SRichard Henderson     for (int i = s->nb_globals; i < s->nb_temps; i++) {
3778b4cb76e6SRichard Henderson         TCGTemp *ts = &s->temps[i];
3779b4cb76e6SRichard Henderson         /*
3780b4cb76e6SRichard Henderson          * The liveness analysis already ensures that temps are dead.
3781b4cb76e6SRichard Henderson          * Keep tcg_debug_asserts for safety.
3782b4cb76e6SRichard Henderson          */
3783c0522136SRichard Henderson         switch (ts->kind) {
3784c0522136SRichard Henderson         case TEMP_LOCAL:
3785b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
3786c0522136SRichard Henderson             break;
3787c0522136SRichard Henderson         case TEMP_NORMAL:
3788b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3789c0522136SRichard Henderson             break;
3790c0522136SRichard Henderson         case TEMP_CONST:
3791c0522136SRichard Henderson             break;
3792c0522136SRichard Henderson         default:
3793c0522136SRichard Henderson             g_assert_not_reached();
3794b4cb76e6SRichard Henderson         }
3795b4cb76e6SRichard Henderson     }
3796b4cb76e6SRichard Henderson }
3797b4cb76e6SRichard Henderson 
3798b4cb76e6SRichard Henderson /*
3799c58f4c97SRichard Henderson  * Specialized code generation for INDEX_op_mov_* with a constant.
3800bab1671fSRichard Henderson  */
38010fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
3802ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
3803ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
3804e8996ee0Sbellard {
3805d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3806e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
380759d7c14eSRichard Henderson 
380859d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
3809f8b2f202SRichard Henderson     if (ots->val_type == TEMP_VAL_REG) {
3810f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = NULL;
3811f8b2f202SRichard Henderson     }
3812e8996ee0Sbellard     ots->val_type = TEMP_VAL_CONST;
3813e8996ee0Sbellard     ots->val = val;
381459d7c14eSRichard Henderson     ots->mem_coherent = 0;
3815ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
3816ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
381759d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
3818f8bf00f1SRichard Henderson         temp_dead(s, ots);
38194c4e1ab2SAurelien Jarno     }
3820e8996ee0Sbellard }
3821e8996ee0Sbellard 
3822bab1671fSRichard Henderson /*
3823bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
3824bab1671fSRichard Henderson  */
3825dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
3826c896fe29Sbellard {
3827dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
382869e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
3829c896fe29Sbellard     TCGTemp *ts, *ots;
3830450445d5SRichard Henderson     TCGType otype, itype;
3831c896fe29Sbellard 
3832d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
383369e3706dSRichard Henderson     preferred_regs = op->output_pref[0];
383443439139SRichard Henderson     ots = arg_temp(op->args[0]);
383543439139SRichard Henderson     ts = arg_temp(op->args[1]);
3836450445d5SRichard Henderson 
3837d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3838e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
3839d63e3b6eSRichard Henderson 
3840450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
3841450445d5SRichard Henderson     otype = ots->type;
3842450445d5SRichard Henderson     itype = ts->type;
3843c896fe29Sbellard 
38440fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
38450fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
38460fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
38470fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
38480fe4fca4SPaolo Bonzini             temp_dead(s, ts);
38490fe4fca4SPaolo Bonzini         }
385069e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
38510fe4fca4SPaolo Bonzini         return;
38520fe4fca4SPaolo Bonzini     }
38530fe4fca4SPaolo Bonzini 
38540fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
38550fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
38560fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
38570fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
38580fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
385969e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
386069e3706dSRichard Henderson                   allocated_regs, preferred_regs);
3861c29c1d7eSAurelien Jarno     }
3862c29c1d7eSAurelien Jarno 
38630fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
3864d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
3865c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
3866c29c1d7eSAurelien Jarno            liveness analysis disabled). */
3867eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
3868c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
38692272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
3870c29c1d7eSAurelien Jarno         }
3871b3a62939SRichard Henderson         tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset);
3872c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
3873f8bf00f1SRichard Henderson             temp_dead(s, ts);
3874c29c1d7eSAurelien Jarno         }
3875f8bf00f1SRichard Henderson         temp_dead(s, ots);
3876e8996ee0Sbellard     } else {
3877ee17db83SRichard Henderson         if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) {
3878c29c1d7eSAurelien Jarno             /* the mov can be suppressed */
3879c29c1d7eSAurelien Jarno             if (ots->val_type == TEMP_VAL_REG) {
3880f8b2f202SRichard Henderson                 s->reg_to_temp[ots->reg] = NULL;
3881c896fe29Sbellard             }
3882c29c1d7eSAurelien Jarno             ots->reg = ts->reg;
3883f8bf00f1SRichard Henderson             temp_dead(s, ts);
3884c29c1d7eSAurelien Jarno         } else {
3885c29c1d7eSAurelien Jarno             if (ots->val_type != TEMP_VAL_REG) {
3886c29c1d7eSAurelien Jarno                 /* When allocating a new register, make sure to not spill the
3887c29c1d7eSAurelien Jarno                    input one. */
3888c29c1d7eSAurelien Jarno                 tcg_regset_set_reg(allocated_regs, ts->reg);
3889450445d5SRichard Henderson                 ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
389069e3706dSRichard Henderson                                          allocated_regs, preferred_regs,
3891b016486eSRichard Henderson                                          ots->indirect_base);
3892c29c1d7eSAurelien Jarno             }
389378113e83SRichard Henderson             if (!tcg_out_mov(s, otype, ots->reg, ts->reg)) {
3894240c08d0SRichard Henderson                 /*
3895240c08d0SRichard Henderson                  * Cross register class move not supported.
3896240c08d0SRichard Henderson                  * Store the source register into the destination slot
3897240c08d0SRichard Henderson                  * and leave the destination temp as TEMP_VAL_MEM.
3898240c08d0SRichard Henderson                  */
3899e01fa97dSRichard Henderson                 assert(!temp_readonly(ots));
3900240c08d0SRichard Henderson                 if (!ts->mem_allocated) {
3901240c08d0SRichard Henderson                     temp_allocate_frame(s, ots);
3902240c08d0SRichard Henderson                 }
3903240c08d0SRichard Henderson                 tcg_out_st(s, ts->type, ts->reg,
3904240c08d0SRichard Henderson                            ots->mem_base->reg, ots->mem_offset);
3905240c08d0SRichard Henderson                 ots->mem_coherent = 1;
3906240c08d0SRichard Henderson                 temp_free_or_dead(s, ots, -1);
3907240c08d0SRichard Henderson                 return;
390878113e83SRichard Henderson             }
3909c29c1d7eSAurelien Jarno         }
3910c896fe29Sbellard         ots->val_type = TEMP_VAL_REG;
3911c896fe29Sbellard         ots->mem_coherent = 0;
3912f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3913ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(0)) {
391498b4e186SRichard Henderson             temp_sync(s, ots, allocated_regs, 0, 0);
3915c29c1d7eSAurelien Jarno         }
3916ec7a869dSAurelien Jarno     }
3917c896fe29Sbellard }
3918c896fe29Sbellard 
3919bab1671fSRichard Henderson /*
3920bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
3921bab1671fSRichard Henderson  */
3922bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
3923bab1671fSRichard Henderson {
3924bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
3925bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
3926bab1671fSRichard Henderson     TCGTemp *its, *ots;
3927bab1671fSRichard Henderson     TCGType itype, vtype;
3928d6ecb4a9SRichard Henderson     intptr_t endian_fixup;
3929bab1671fSRichard Henderson     unsigned vece;
3930bab1671fSRichard Henderson     bool ok;
3931bab1671fSRichard Henderson 
3932bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
3933bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
3934bab1671fSRichard Henderson 
3935bab1671fSRichard Henderson     /* ENV should not be modified.  */
3936e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
3937bab1671fSRichard Henderson 
3938bab1671fSRichard Henderson     itype = its->type;
3939bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
3940bab1671fSRichard Henderson     vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
3941bab1671fSRichard Henderson 
3942bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
3943bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
3944bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
3945bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
3946bab1671fSRichard Henderson             temp_dead(s, its);
3947bab1671fSRichard Henderson         }
3948bab1671fSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, op->output_pref[0]);
3949bab1671fSRichard Henderson         return;
3950bab1671fSRichard Henderson     }
3951bab1671fSRichard Henderson 
39529be0d080SRichard Henderson     dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
39539be0d080SRichard Henderson     dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs;
3954bab1671fSRichard Henderson 
3955bab1671fSRichard Henderson     /* Allocate the output register now.  */
3956bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
3957bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
3958bab1671fSRichard Henderson 
3959bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
3960bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
3961bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
3962bab1671fSRichard Henderson         }
3963bab1671fSRichard Henderson         ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
3964bab1671fSRichard Henderson                                  op->output_pref[0], ots->indirect_base);
3965bab1671fSRichard Henderson         ots->val_type = TEMP_VAL_REG;
3966bab1671fSRichard Henderson         ots->mem_coherent = 0;
3967bab1671fSRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3968bab1671fSRichard Henderson     }
3969bab1671fSRichard Henderson 
3970bab1671fSRichard Henderson     switch (its->val_type) {
3971bab1671fSRichard Henderson     case TEMP_VAL_REG:
3972bab1671fSRichard Henderson         /*
3973bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
3974bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
3975bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
3976bab1671fSRichard Henderson          */
3977bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
3978bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
3979bab1671fSRichard Henderson                 goto done;
3980bab1671fSRichard Henderson             }
3981bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
3982bab1671fSRichard Henderson         }
3983bab1671fSRichard Henderson         if (!its->mem_coherent) {
3984bab1671fSRichard Henderson             /*
3985bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
3986bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
3987bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
3988bab1671fSRichard Henderson              */
3989bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
3990bab1671fSRichard Henderson                 break;
3991bab1671fSRichard Henderson             }
3992bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
3993bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
3994bab1671fSRichard Henderson         }
3995bab1671fSRichard Henderson         /* fall through */
3996bab1671fSRichard Henderson 
3997bab1671fSRichard Henderson     case TEMP_VAL_MEM:
3998d6ecb4a9SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
3999d6ecb4a9SRichard Henderson         endian_fixup = itype == TCG_TYPE_I32 ? 4 : 8;
4000d6ecb4a9SRichard Henderson         endian_fixup -= 1 << vece;
4001d6ecb4a9SRichard Henderson #else
4002d6ecb4a9SRichard Henderson         endian_fixup = 0;
4003d6ecb4a9SRichard Henderson #endif
4004d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
4005d6ecb4a9SRichard Henderson                              its->mem_offset + endian_fixup)) {
4006d6ecb4a9SRichard Henderson             goto done;
4007d6ecb4a9SRichard Henderson         }
4008bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
4009bab1671fSRichard Henderson         break;
4010bab1671fSRichard Henderson 
4011bab1671fSRichard Henderson     default:
4012bab1671fSRichard Henderson         g_assert_not_reached();
4013bab1671fSRichard Henderson     }
4014bab1671fSRichard Henderson 
4015bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
4016bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
4017bab1671fSRichard Henderson     tcg_debug_assert(ok);
4018bab1671fSRichard Henderson 
4019bab1671fSRichard Henderson  done:
4020bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
4021bab1671fSRichard Henderson         temp_dead(s, its);
4022bab1671fSRichard Henderson     }
4023bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
4024bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
4025bab1671fSRichard Henderson     }
4026bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
4027bab1671fSRichard Henderson         temp_dead(s, ots);
4028bab1671fSRichard Henderson     }
4029bab1671fSRichard Henderson }
4030bab1671fSRichard Henderson 
4031dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
4032c896fe29Sbellard {
4033dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
4034dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
403582790a87SRichard Henderson     TCGRegSet i_allocated_regs;
403682790a87SRichard Henderson     TCGRegSet o_allocated_regs;
4037b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
4038b6638662SRichard Henderson     TCGReg reg;
4039c896fe29Sbellard     TCGArg arg;
4040c896fe29Sbellard     const TCGArgConstraint *arg_ct;
4041c896fe29Sbellard     TCGTemp *ts;
4042c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
4043c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
4044c896fe29Sbellard 
4045c896fe29Sbellard     nb_oargs = def->nb_oargs;
4046c896fe29Sbellard     nb_iargs = def->nb_iargs;
4047c896fe29Sbellard 
4048c896fe29Sbellard     /* copy constants */
4049c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
4050dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
4051c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
4052c896fe29Sbellard 
4053d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
4054d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
405582790a87SRichard Henderson 
4056c896fe29Sbellard     /* satisfy input constraints */
4057c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
4058d62816f2SRichard Henderson         TCGRegSet i_preferred_regs, o_preferred_regs;
4059d62816f2SRichard Henderson 
406066792f90SRichard Henderson         i = def->args_ct[nb_oargs + k].sort_index;
4061dd186292SRichard Henderson         arg = op->args[i];
4062c896fe29Sbellard         arg_ct = &def->args_ct[i];
406343439139SRichard Henderson         ts = arg_temp(arg);
406440ae5c62SRichard Henderson 
406540ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
4066a4fbbd77SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct->ct)) {
4067c896fe29Sbellard             /* constant is OK for instruction */
4068c896fe29Sbellard             const_args[i] = 1;
4069c896fe29Sbellard             new_args[i] = ts->val;
4070d62816f2SRichard Henderson             continue;
4071c896fe29Sbellard         }
407240ae5c62SRichard Henderson 
4073d62816f2SRichard Henderson         i_preferred_regs = o_preferred_regs = 0;
4074bc2b17e6SRichard Henderson         if (arg_ct->ialias) {
4075d62816f2SRichard Henderson             o_preferred_regs = op->output_pref[arg_ct->alias_index];
4076c0522136SRichard Henderson 
4077c0522136SRichard Henderson             /*
4078c0522136SRichard Henderson              * If the input is readonly, then it cannot also be an
4079c0522136SRichard Henderson              * output and aliased to itself.  If the input is not
4080c0522136SRichard Henderson              * dead after the instruction, we must allocate a new
4081c0522136SRichard Henderson              * register and move it.
4082c0522136SRichard Henderson              */
4083c0522136SRichard Henderson             if (temp_readonly(ts) || !IS_DEAD_ARG(i)) {
4084c896fe29Sbellard                 goto allocate_in_reg;
4085c896fe29Sbellard             }
4086d62816f2SRichard Henderson 
4087c0522136SRichard Henderson             /*
4088c0522136SRichard Henderson              * Check if the current register has already been allocated
4089c0522136SRichard Henderson              * for another input aliased to an output.
4090c0522136SRichard Henderson              */
4091d62816f2SRichard Henderson             if (ts->val_type == TEMP_VAL_REG) {
4092d62816f2SRichard Henderson                 reg = ts->reg;
4093c0522136SRichard Henderson                 for (int k2 = 0; k2 < k; k2++) {
4094c0522136SRichard Henderson                     int i2 = def->args_ct[nb_oargs + k2].sort_index;
4095bc2b17e6SRichard Henderson                     if (def->args_ct[i2].ialias && reg == new_args[i2]) {
40967e1df267SAurelien Jarno                         goto allocate_in_reg;
40977e1df267SAurelien Jarno                     }
40987e1df267SAurelien Jarno                 }
40995ff9d6a4Sbellard             }
4100d62816f2SRichard Henderson             i_preferred_regs = o_preferred_regs;
4101866cb6cbSAurelien Jarno         }
4102d62816f2SRichard Henderson 
41039be0d080SRichard Henderson         temp_load(s, ts, arg_ct->regs, i_allocated_regs, i_preferred_regs);
4104c896fe29Sbellard         reg = ts->reg;
4105d62816f2SRichard Henderson 
4106c0522136SRichard Henderson         if (!tcg_regset_test_reg(arg_ct->regs, reg)) {
4107c896fe29Sbellard  allocate_in_reg:
4108c0522136SRichard Henderson             /*
4109c0522136SRichard Henderson              * Allocate a new register matching the constraint
4110c0522136SRichard Henderson              * and move the temporary register into it.
4111c0522136SRichard Henderson              */
4112d62816f2SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
4113d62816f2SRichard Henderson                       i_allocated_regs, 0);
41149be0d080SRichard Henderson             reg = tcg_reg_alloc(s, arg_ct->regs, i_allocated_regs,
4115d62816f2SRichard Henderson                                 o_preferred_regs, ts->indirect_base);
411678113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4117240c08d0SRichard Henderson                 /*
4118240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
4119240c08d0SRichard Henderson                  * temp back to its slot and load from there.
4120240c08d0SRichard Henderson                  */
4121240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
4122240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
4123240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
412478113e83SRichard Henderson             }
4125c896fe29Sbellard         }
4126c896fe29Sbellard         new_args[i] = reg;
4127c896fe29Sbellard         const_args[i] = 0;
412882790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
4129c896fe29Sbellard     }
4130c896fe29Sbellard 
4131c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
4132866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
4133866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
413443439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4135c896fe29Sbellard         }
4136c896fe29Sbellard     }
4137c896fe29Sbellard 
4138b4cb76e6SRichard Henderson     if (def->flags & TCG_OPF_COND_BRANCH) {
4139b4cb76e6SRichard Henderson         tcg_reg_alloc_cbranch(s, i_allocated_regs);
4140b4cb76e6SRichard Henderson     } else if (def->flags & TCG_OPF_BB_END) {
414182790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
4142a52ad07eSAurelien Jarno     } else {
4143c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
4144b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
4145c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4146c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
414782790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
4148c896fe29Sbellard                 }
4149c896fe29Sbellard             }
41503d5c5f87SAurelien Jarno         }
41513d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
41523d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
41533d5c5f87SAurelien Jarno                an exception. */
415482790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
4155c896fe29Sbellard         }
4156c896fe29Sbellard 
4157c896fe29Sbellard         /* satisfy the output constraints */
4158c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
415966792f90SRichard Henderson             i = def->args_ct[k].sort_index;
4160dd186292SRichard Henderson             arg = op->args[i];
4161c896fe29Sbellard             arg_ct = &def->args_ct[i];
416243439139SRichard Henderson             ts = arg_temp(arg);
4163d63e3b6eSRichard Henderson 
4164d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
4165e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
4166d63e3b6eSRichard Henderson 
4167bc2b17e6SRichard Henderson             if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
41685ff9d6a4Sbellard                 reg = new_args[arg_ct->alias_index];
4169bc2b17e6SRichard Henderson             } else if (arg_ct->newreg) {
41709be0d080SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->regs,
417182790a87SRichard Henderson                                     i_allocated_regs | o_allocated_regs,
417269e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
4173c896fe29Sbellard             } else {
41749be0d080SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
417569e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
4176c896fe29Sbellard             }
417782790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
4178639368ddSAurelien Jarno             if (ts->val_type == TEMP_VAL_REG) {
4179f8b2f202SRichard Henderson                 s->reg_to_temp[ts->reg] = NULL;
4180639368ddSAurelien Jarno             }
4181c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
4182c896fe29Sbellard             ts->reg = reg;
4183d63e3b6eSRichard Henderson             /*
4184d63e3b6eSRichard Henderson              * Temp value is modified, so the value kept in memory is
4185d63e3b6eSRichard Henderson              * potentially not the same.
4186d63e3b6eSRichard Henderson              */
4187c896fe29Sbellard             ts->mem_coherent = 0;
4188f8b2f202SRichard Henderson             s->reg_to_temp[reg] = ts;
4189c896fe29Sbellard             new_args[i] = reg;
4190c896fe29Sbellard         }
4191e8996ee0Sbellard     }
4192c896fe29Sbellard 
4193c896fe29Sbellard     /* emit instruction */
4194d2fd745fSRichard Henderson     if (def->flags & TCG_OPF_VECTOR) {
4195d2fd745fSRichard Henderson         tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
4196d2fd745fSRichard Henderson                        new_args, const_args);
4197d2fd745fSRichard Henderson     } else {
4198dd186292SRichard Henderson         tcg_out_op(s, op->opc, new_args, const_args);
4199d2fd745fSRichard Henderson     }
4200c896fe29Sbellard 
4201c896fe29Sbellard     /* move the outputs in the correct register if needed */
4202c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
420343439139SRichard Henderson         ts = arg_temp(op->args[i]);
4204d63e3b6eSRichard Henderson 
4205d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
4206e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
4207d63e3b6eSRichard Henderson 
4208ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
420998b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
421059d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4211f8bf00f1SRichard Henderson             temp_dead(s, ts);
4212ec7a869dSAurelien Jarno         }
4213c896fe29Sbellard     }
4214c896fe29Sbellard }
4215c896fe29Sbellard 
4216efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op)
4217efe86b21SRichard Henderson {
4218efe86b21SRichard Henderson     const TCGLifeData arg_life = op->life;
4219efe86b21SRichard Henderson     TCGTemp *ots, *itsl, *itsh;
4220efe86b21SRichard Henderson     TCGType vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
4221efe86b21SRichard Henderson 
4222efe86b21SRichard Henderson     /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */
4223efe86b21SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 32);
4224efe86b21SRichard Henderson     tcg_debug_assert(TCGOP_VECE(op) == MO_64);
4225efe86b21SRichard Henderson 
4226efe86b21SRichard Henderson     ots = arg_temp(op->args[0]);
4227efe86b21SRichard Henderson     itsl = arg_temp(op->args[1]);
4228efe86b21SRichard Henderson     itsh = arg_temp(op->args[2]);
4229efe86b21SRichard Henderson 
4230efe86b21SRichard Henderson     /* ENV should not be modified.  */
4231efe86b21SRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4232efe86b21SRichard Henderson 
4233efe86b21SRichard Henderson     /* Allocate the output register now.  */
4234efe86b21SRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
4235efe86b21SRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
4236efe86b21SRichard Henderson         TCGRegSet dup_out_regs =
4237efe86b21SRichard Henderson             tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
4238efe86b21SRichard Henderson 
4239efe86b21SRichard Henderson         /* Make sure to not spill the input registers. */
4240efe86b21SRichard Henderson         if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) {
4241efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsl->reg);
4242efe86b21SRichard Henderson         }
4243efe86b21SRichard Henderson         if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) {
4244efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsh->reg);
4245efe86b21SRichard Henderson         }
4246efe86b21SRichard Henderson 
4247efe86b21SRichard Henderson         ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
4248efe86b21SRichard Henderson                                  op->output_pref[0], ots->indirect_base);
4249efe86b21SRichard Henderson         ots->val_type = TEMP_VAL_REG;
4250efe86b21SRichard Henderson         ots->mem_coherent = 0;
4251efe86b21SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
4252efe86b21SRichard Henderson     }
4253efe86b21SRichard Henderson 
4254efe86b21SRichard Henderson     /* Promote dup2 of immediates to dupi_vec. */
4255efe86b21SRichard Henderson     if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) {
4256efe86b21SRichard Henderson         uint64_t val = deposit64(itsl->val, 32, 32, itsh->val);
4257efe86b21SRichard Henderson         MemOp vece = MO_64;
4258efe86b21SRichard Henderson 
4259efe86b21SRichard Henderson         if (val == dup_const(MO_8, val)) {
4260efe86b21SRichard Henderson             vece = MO_8;
4261efe86b21SRichard Henderson         } else if (val == dup_const(MO_16, val)) {
4262efe86b21SRichard Henderson             vece = MO_16;
4263efe86b21SRichard Henderson         } else if (val == dup_const(MO_32, val)) {
4264efe86b21SRichard Henderson             vece = MO_32;
4265efe86b21SRichard Henderson         }
4266efe86b21SRichard Henderson 
4267efe86b21SRichard Henderson         tcg_out_dupi_vec(s, vtype, vece, ots->reg, val);
4268efe86b21SRichard Henderson         goto done;
4269efe86b21SRichard Henderson     }
4270efe86b21SRichard Henderson 
4271efe86b21SRichard Henderson     /* If the two inputs form one 64-bit value, try dupm_vec. */
4272efe86b21SRichard Henderson     if (itsl + 1 == itsh && itsl->base_type == TCG_TYPE_I64) {
4273efe86b21SRichard Henderson         if (!itsl->mem_coherent) {
4274efe86b21SRichard Henderson             temp_sync(s, itsl, s->reserved_regs, 0, 0);
4275efe86b21SRichard Henderson         }
4276efe86b21SRichard Henderson         if (!itsh->mem_coherent) {
4277efe86b21SRichard Henderson             temp_sync(s, itsh, s->reserved_regs, 0, 0);
4278efe86b21SRichard Henderson         }
4279efe86b21SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
4280efe86b21SRichard Henderson         TCGTemp *its = itsh;
4281efe86b21SRichard Henderson #else
4282efe86b21SRichard Henderson         TCGTemp *its = itsl;
4283efe86b21SRichard Henderson #endif
4284efe86b21SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg,
4285efe86b21SRichard Henderson                              its->mem_base->reg, its->mem_offset)) {
4286efe86b21SRichard Henderson             goto done;
4287efe86b21SRichard Henderson         }
4288efe86b21SRichard Henderson     }
4289efe86b21SRichard Henderson 
4290efe86b21SRichard Henderson     /* Fall back to generic expansion. */
4291efe86b21SRichard Henderson     return false;
4292efe86b21SRichard Henderson 
4293efe86b21SRichard Henderson  done:
4294efe86b21SRichard Henderson     if (IS_DEAD_ARG(1)) {
4295efe86b21SRichard Henderson         temp_dead(s, itsl);
4296efe86b21SRichard Henderson     }
4297efe86b21SRichard Henderson     if (IS_DEAD_ARG(2)) {
4298efe86b21SRichard Henderson         temp_dead(s, itsh);
4299efe86b21SRichard Henderson     }
4300efe86b21SRichard Henderson     if (NEED_SYNC_ARG(0)) {
4301efe86b21SRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0));
4302efe86b21SRichard Henderson     } else if (IS_DEAD_ARG(0)) {
4303efe86b21SRichard Henderson         temp_dead(s, ots);
4304efe86b21SRichard Henderson     }
4305efe86b21SRichard Henderson     return true;
4306efe86b21SRichard Henderson }
4307efe86b21SRichard Henderson 
4308b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP
4309b03cce8eSbellard #define STACK_DIR(x) (-(x))
4310b03cce8eSbellard #else
4311b03cce8eSbellard #define STACK_DIR(x) (x)
4312b03cce8eSbellard #endif
4313b03cce8eSbellard 
4314dd186292SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
4315c896fe29Sbellard {
4316cd9090aaSRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
4317cd9090aaSRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
4318dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
4319b6638662SRichard Henderson     int flags, nb_regs, i;
4320b6638662SRichard Henderson     TCGReg reg;
4321cf066674SRichard Henderson     TCGArg arg;
4322c896fe29Sbellard     TCGTemp *ts;
4323d3452f1fSRichard Henderson     intptr_t stack_offset;
4324d3452f1fSRichard Henderson     size_t call_stack_size;
4325cf066674SRichard Henderson     tcg_insn_unit *func_addr;
4326cf066674SRichard Henderson     int allocate_args;
4327c896fe29Sbellard     TCGRegSet allocated_regs;
4328c896fe29Sbellard 
4329dd186292SRichard Henderson     func_addr = (tcg_insn_unit *)(intptr_t)op->args[nb_oargs + nb_iargs];
4330dd186292SRichard Henderson     flags = op->args[nb_oargs + nb_iargs + 1];
4331c896fe29Sbellard 
43326e17d0c5SStefan Weil     nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
4333c45cb8bbSRichard Henderson     if (nb_regs > nb_iargs) {
4334c45cb8bbSRichard Henderson         nb_regs = nb_iargs;
4335cf066674SRichard Henderson     }
4336c896fe29Sbellard 
4337c896fe29Sbellard     /* assign stack slots first */
4338c45cb8bbSRichard Henderson     call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long);
4339c896fe29Sbellard     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
4340c896fe29Sbellard         ~(TCG_TARGET_STACK_ALIGN - 1);
4341b03cce8eSbellard     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
4342b03cce8eSbellard     if (allocate_args) {
4343345649c0SBlue Swirl         /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
4344345649c0SBlue Swirl            preallocate call stack */
4345345649c0SBlue Swirl         tcg_abort();
4346b03cce8eSbellard     }
434739cf05d3Sbellard 
434839cf05d3Sbellard     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
4349c45cb8bbSRichard Henderson     for (i = nb_regs; i < nb_iargs; i++) {
4350dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
435139cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP
435239cf05d3Sbellard         stack_offset -= sizeof(tcg_target_long);
435339cf05d3Sbellard #endif
435439cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
435543439139SRichard Henderson             ts = arg_temp(arg);
435640ae5c62SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
4357b722452aSRichard Henderson                       s->reserved_regs, 0);
4358e4d5434cSblueswir1             tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
435939cf05d3Sbellard         }
436039cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP
436139cf05d3Sbellard         stack_offset += sizeof(tcg_target_long);
436239cf05d3Sbellard #endif
4363c896fe29Sbellard     }
4364c896fe29Sbellard 
4365c896fe29Sbellard     /* assign input registers */
4366d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
4367c896fe29Sbellard     for (i = 0; i < nb_regs; i++) {
4368dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
436939cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
437043439139SRichard Henderson             ts = arg_temp(arg);
4371c896fe29Sbellard             reg = tcg_target_call_iarg_regs[i];
437240ae5c62SRichard Henderson 
4373c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
4374c896fe29Sbellard                 if (ts->reg != reg) {
43754250da10SRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
437678113e83SRichard Henderson                     if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4377240c08d0SRichard Henderson                         /*
4378240c08d0SRichard Henderson                          * Cross register class move not supported.  Sync the
4379240c08d0SRichard Henderson                          * temp back to its slot and load from there.
4380240c08d0SRichard Henderson                          */
4381240c08d0SRichard Henderson                         temp_sync(s, ts, allocated_regs, 0, 0);
4382240c08d0SRichard Henderson                         tcg_out_ld(s, ts->type, reg,
4383240c08d0SRichard Henderson                                    ts->mem_base->reg, ts->mem_offset);
438478113e83SRichard Henderson                     }
4385c896fe29Sbellard                 }
4386c896fe29Sbellard             } else {
4387ccb1bb66SRichard Henderson                 TCGRegSet arg_set = 0;
438840ae5c62SRichard Henderson 
43894250da10SRichard Henderson                 tcg_reg_free(s, reg, allocated_regs);
439040ae5c62SRichard Henderson                 tcg_regset_set_reg(arg_set, reg);
4391b722452aSRichard Henderson                 temp_load(s, ts, arg_set, allocated_regs, 0);
4392c896fe29Sbellard             }
439340ae5c62SRichard Henderson 
4394c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
4395c896fe29Sbellard         }
439639cf05d3Sbellard     }
4397c896fe29Sbellard 
4398c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
4399866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4400866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
440143439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4402c896fe29Sbellard         }
4403c896fe29Sbellard     }
4404c896fe29Sbellard 
4405c896fe29Sbellard     /* clobber call registers */
4406c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4407c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
4408b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
4409c896fe29Sbellard         }
4410c896fe29Sbellard     }
4411c896fe29Sbellard 
441278505279SAurelien Jarno     /* Save globals if they might be written by the helper, sync them if
441378505279SAurelien Jarno        they might be read. */
441478505279SAurelien Jarno     if (flags & TCG_CALL_NO_READ_GLOBALS) {
441578505279SAurelien Jarno         /* Nothing to do */
441678505279SAurelien Jarno     } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) {
441778505279SAurelien Jarno         sync_globals(s, allocated_regs);
441878505279SAurelien Jarno     } else {
4419e8996ee0Sbellard         save_globals(s, allocated_regs);
4420b9c18f56Saurel32     }
4421c896fe29Sbellard 
4422cf066674SRichard Henderson     tcg_out_call(s, func_addr);
4423c896fe29Sbellard 
4424c896fe29Sbellard     /* assign output registers and emit moves if needed */
4425c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
4426dd186292SRichard Henderson         arg = op->args[i];
442743439139SRichard Henderson         ts = arg_temp(arg);
4428d63e3b6eSRichard Henderson 
4429d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
4430e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
4431d63e3b6eSRichard Henderson 
4432c896fe29Sbellard         reg = tcg_target_call_oarg_regs[i];
4433eabb7b91SAurelien Jarno         tcg_debug_assert(s->reg_to_temp[reg] == NULL);
4434639368ddSAurelien Jarno         if (ts->val_type == TEMP_VAL_REG) {
4435f8b2f202SRichard Henderson             s->reg_to_temp[ts->reg] = NULL;
4436639368ddSAurelien Jarno         }
4437c896fe29Sbellard         ts->val_type = TEMP_VAL_REG;
4438c896fe29Sbellard         ts->reg = reg;
4439c896fe29Sbellard         ts->mem_coherent = 0;
4440f8b2f202SRichard Henderson         s->reg_to_temp[reg] = ts;
4441ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
444298b4e186SRichard Henderson             temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i));
444359d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4444f8bf00f1SRichard Henderson             temp_dead(s, ts);
4445c896fe29Sbellard         }
4446c896fe29Sbellard     }
44478c11ad25SAurelien Jarno }
4448c896fe29Sbellard 
4449c896fe29Sbellard #ifdef CONFIG_PROFILER
4450c896fe29Sbellard 
4451c3fac113SEmilio G. Cota /* avoid copy/paste errors */
4452c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field)                       \
4453c3fac113SEmilio G. Cota     do {                                                \
4454d73415a3SStefan Hajnoczi         (to)->field += qatomic_read(&((from)->field));  \
4455c3fac113SEmilio G. Cota     } while (0)
4456c896fe29Sbellard 
4457c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field)                                       \
4458c3fac113SEmilio G. Cota     do {                                                                \
4459d73415a3SStefan Hajnoczi         typeof((from)->field) val__ = qatomic_read(&((from)->field));   \
4460c3fac113SEmilio G. Cota         if (val__ > (to)->field) {                                      \
4461c3fac113SEmilio G. Cota             (to)->field = val__;                                        \
4462c3fac113SEmilio G. Cota         }                                                               \
4463c3fac113SEmilio G. Cota     } while (0)
4464c3fac113SEmilio G. Cota 
4465c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */
4466c3fac113SEmilio G. Cota static inline
4467c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
4468c896fe29Sbellard {
4469d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
4470c3fac113SEmilio G. Cota     unsigned int i;
4471c3fac113SEmilio G. Cota 
44723468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4473d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
44743468b59eSEmilio G. Cota         const TCGProfile *orig = &s->prof;
4475c3fac113SEmilio G. Cota 
4476c3fac113SEmilio G. Cota         if (counters) {
447772fd2efbSEmilio G. Cota             PROF_ADD(prof, orig, cpu_exec_time);
4478c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count1);
4479c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count);
4480c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, op_count);
4481c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, op_count_max);
4482c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, temp_count);
4483c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, temp_count_max);
4484c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, del_op_count);
4485c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_in_len);
4486c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_out_len);
4487c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, search_out_len);
4488c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, interm_time);
4489c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_time);
4490c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, la_time);
4491c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, opt_time);
4492c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_count);
4493c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_time);
4494c3fac113SEmilio G. Cota         }
4495c3fac113SEmilio G. Cota         if (table) {
4496c896fe29Sbellard             int i;
4497d70724ceSzhanghailiang 
449815fc7daaSRichard Henderson             for (i = 0; i < NB_OPS; i++) {
4499c3fac113SEmilio G. Cota                 PROF_ADD(prof, orig, table_op_count[i]);
4500c3fac113SEmilio G. Cota             }
4501c3fac113SEmilio G. Cota         }
4502c3fac113SEmilio G. Cota     }
4503c3fac113SEmilio G. Cota }
4504c3fac113SEmilio G. Cota 
4505c3fac113SEmilio G. Cota #undef PROF_ADD
4506c3fac113SEmilio G. Cota #undef PROF_MAX
4507c3fac113SEmilio G. Cota 
4508c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof)
4509c3fac113SEmilio G. Cota {
4510c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, true, false);
4511c3fac113SEmilio G. Cota }
4512c3fac113SEmilio G. Cota 
4513c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof)
4514c3fac113SEmilio G. Cota {
4515c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, false, true);
4516c3fac113SEmilio G. Cota }
4517c3fac113SEmilio G. Cota 
4518d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
4519c3fac113SEmilio G. Cota {
4520c3fac113SEmilio G. Cota     TCGProfile prof = {};
4521c3fac113SEmilio G. Cota     int i;
4522c3fac113SEmilio G. Cota 
4523c3fac113SEmilio G. Cota     tcg_profile_snapshot_table(&prof);
4524c3fac113SEmilio G. Cota     for (i = 0; i < NB_OPS; i++) {
4525d4c51a0aSMarkus Armbruster         qemu_printf("%s %" PRId64 "\n", tcg_op_defs[i].name,
4526c3fac113SEmilio G. Cota                     prof.table_op_count[i]);
4527c896fe29Sbellard     }
4528c896fe29Sbellard }
452972fd2efbSEmilio G. Cota 
453072fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
453172fd2efbSEmilio G. Cota {
4532d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
453372fd2efbSEmilio G. Cota     unsigned int i;
453472fd2efbSEmilio G. Cota     int64_t ret = 0;
453572fd2efbSEmilio G. Cota 
453672fd2efbSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4537d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
453872fd2efbSEmilio G. Cota         const TCGProfile *prof = &s->prof;
453972fd2efbSEmilio G. Cota 
4540d73415a3SStefan Hajnoczi         ret += qatomic_read(&prof->cpu_exec_time);
454172fd2efbSEmilio G. Cota     }
454272fd2efbSEmilio G. Cota     return ret;
454372fd2efbSEmilio G. Cota }
4544246ae24dSMax Filippov #else
4545d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
4546246ae24dSMax Filippov {
4547d4c51a0aSMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4548246ae24dSMax Filippov }
454972fd2efbSEmilio G. Cota 
455072fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
455172fd2efbSEmilio G. Cota {
455272fd2efbSEmilio G. Cota     error_report("%s: TCG profiler not compiled", __func__);
455372fd2efbSEmilio G. Cota     exit(EXIT_FAILURE);
455472fd2efbSEmilio G. Cota }
4555c896fe29Sbellard #endif
4556c896fe29Sbellard 
4557c896fe29Sbellard 
45585bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
4559c896fe29Sbellard {
4560c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER
4561c3fac113SEmilio G. Cota     TCGProfile *prof = &s->prof;
4562c3fac113SEmilio G. Cota #endif
456315fa08f8SRichard Henderson     int i, num_insns;
456415fa08f8SRichard Henderson     TCGOp *op;
4565c896fe29Sbellard 
456604fe6400SRichard Henderson #ifdef CONFIG_PROFILER
456704fe6400SRichard Henderson     {
4568c1f543b7SEmilio G. Cota         int n = 0;
456904fe6400SRichard Henderson 
457015fa08f8SRichard Henderson         QTAILQ_FOREACH(op, &s->ops, link) {
457115fa08f8SRichard Henderson             n++;
457215fa08f8SRichard Henderson         }
4573d73415a3SStefan Hajnoczi         qatomic_set(&prof->op_count, prof->op_count + n);
4574c3fac113SEmilio G. Cota         if (n > prof->op_count_max) {
4575d73415a3SStefan Hajnoczi             qatomic_set(&prof->op_count_max, n);
457604fe6400SRichard Henderson         }
457704fe6400SRichard Henderson 
457804fe6400SRichard Henderson         n = s->nb_temps;
4579d73415a3SStefan Hajnoczi         qatomic_set(&prof->temp_count, prof->temp_count + n);
4580c3fac113SEmilio G. Cota         if (n > prof->temp_count_max) {
4581d73415a3SStefan Hajnoczi             qatomic_set(&prof->temp_count_max, n);
458204fe6400SRichard Henderson         }
458304fe6400SRichard Henderson     }
458404fe6400SRichard Henderson #endif
458504fe6400SRichard Henderson 
4586c896fe29Sbellard #ifdef DEBUG_DISAS
4587d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
4588d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
4589fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
459093fcfe39Saliguori         qemu_log("OP:\n");
45911894f69aSRichard Henderson         tcg_dump_ops(s, false);
459293fcfe39Saliguori         qemu_log("\n");
4593fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
4594c896fe29Sbellard     }
4595c896fe29Sbellard #endif
4596c896fe29Sbellard 
4597bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
4598bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
4599bef16ab4SRichard Henderson     {
4600bef16ab4SRichard Henderson         TCGLabel *l;
4601bef16ab4SRichard Henderson         bool error = false;
4602bef16ab4SRichard Henderson 
4603bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
4604bef16ab4SRichard Henderson             if (unlikely(!l->present) && l->refs) {
4605bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
4606bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
4607bef16ab4SRichard Henderson                 error = true;
4608bef16ab4SRichard Henderson             }
4609bef16ab4SRichard Henderson         }
4610bef16ab4SRichard Henderson         assert(!error);
4611bef16ab4SRichard Henderson     }
4612bef16ab4SRichard Henderson #endif
4613bef16ab4SRichard Henderson 
4614c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
4615d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
4616c5cc28ffSAurelien Jarno #endif
4617c5cc28ffSAurelien Jarno 
46188f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
4619c45cb8bbSRichard Henderson     tcg_optimize(s);
46208f2e8c07SKirill Batuzov #endif
46218f2e8c07SKirill Batuzov 
4622a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4623d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
4624d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time - profile_getclock());
4625a23a9ec6Sbellard #endif
4626c5cc28ffSAurelien Jarno 
4627b4fc67c7SRichard Henderson     reachable_code_pass(s);
4628b83eabeaSRichard Henderson     liveness_pass_1(s);
46295a18407fSRichard Henderson 
46305a18407fSRichard Henderson     if (s->nb_indirects > 0) {
46315a18407fSRichard Henderson #ifdef DEBUG_DISAS
46325a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
46335a18407fSRichard Henderson                      && qemu_log_in_addr_range(tb->pc))) {
4634fc59d2d8SRobert Foley             FILE *logfile = qemu_log_lock();
46355a18407fSRichard Henderson             qemu_log("OP before indirect lowering:\n");
46361894f69aSRichard Henderson             tcg_dump_ops(s, false);
46375a18407fSRichard Henderson             qemu_log("\n");
4638fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
46395a18407fSRichard Henderson         }
46405a18407fSRichard Henderson #endif
46415a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
4642b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
46435a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
4644b83eabeaSRichard Henderson             liveness_pass_1(s);
46455a18407fSRichard Henderson         }
46465a18407fSRichard Henderson     }
4647c5cc28ffSAurelien Jarno 
4648a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4649d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time + profile_getclock());
4650a23a9ec6Sbellard #endif
4651c896fe29Sbellard 
4652c896fe29Sbellard #ifdef DEBUG_DISAS
4653d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
4654d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
4655fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
4656c5cc28ffSAurelien Jarno         qemu_log("OP after optimization and liveness analysis:\n");
46571894f69aSRichard Henderson         tcg_dump_ops(s, true);
465893fcfe39Saliguori         qemu_log("\n");
4659fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
4660c896fe29Sbellard     }
4661c896fe29Sbellard #endif
4662c896fe29Sbellard 
4663c896fe29Sbellard     tcg_reg_alloc_start(s);
4664c896fe29Sbellard 
4665db0c51a3SRichard Henderson     /*
4666db0c51a3SRichard Henderson      * Reset the buffer pointers when restarting after overflow.
4667db0c51a3SRichard Henderson      * TODO: Move this into translate-all.c with the rest of the
4668db0c51a3SRichard Henderson      * buffer management.  Having only this done here is confusing.
4669db0c51a3SRichard Henderson      */
4670db0c51a3SRichard Henderson     s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr);
4671db0c51a3SRichard Henderson     s->code_ptr = s->code_buf;
4672c896fe29Sbellard 
4673659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
46746001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
4675659ef5cbSRichard Henderson #endif
467657a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
467757a26946SRichard Henderson     s->pool_labels = NULL;
467857a26946SRichard Henderson #endif
46799ecefc84SRichard Henderson 
4680fca8a500SRichard Henderson     num_insns = -1;
468115fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
4682c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
4683b3db8758Sblueswir1 
4684c896fe29Sbellard #ifdef CONFIG_PROFILER
4685d73415a3SStefan Hajnoczi         qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
4686c896fe29Sbellard #endif
4687c45cb8bbSRichard Henderson 
4688c896fe29Sbellard         switch (opc) {
4689c896fe29Sbellard         case INDEX_op_mov_i32:
4690c896fe29Sbellard         case INDEX_op_mov_i64:
4691d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
4692dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
4693c896fe29Sbellard             break;
4694bab1671fSRichard Henderson         case INDEX_op_dup_vec:
4695bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
4696bab1671fSRichard Henderson             break;
4697765b842aSRichard Henderson         case INDEX_op_insn_start:
4698fca8a500SRichard Henderson             if (num_insns >= 0) {
46999f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
47009f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
47019f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
47029f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
4703fca8a500SRichard Henderson             }
4704fca8a500SRichard Henderson             num_insns++;
4705bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
4706bad729e2SRichard Henderson                 target_ulong a;
4707bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
4708efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
4709bad729e2SRichard Henderson #else
4710efee3746SRichard Henderson                 a = op->args[i];
4711bad729e2SRichard Henderson #endif
4712fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
4713bad729e2SRichard Henderson             }
4714c896fe29Sbellard             break;
47155ff9d6a4Sbellard         case INDEX_op_discard:
471643439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
47175ff9d6a4Sbellard             break;
4718c896fe29Sbellard         case INDEX_op_set_label:
4719e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
472092ab8e7dSRichard Henderson             tcg_out_label(s, arg_label(op->args[0]));
4721c896fe29Sbellard             break;
4722c896fe29Sbellard         case INDEX_op_call:
4723dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
4724c45cb8bbSRichard Henderson             break;
4725efe86b21SRichard Henderson         case INDEX_op_dup2_vec:
4726efe86b21SRichard Henderson             if (tcg_reg_alloc_dup2(s, op)) {
4727efe86b21SRichard Henderson                 break;
4728efe86b21SRichard Henderson             }
4729efe86b21SRichard Henderson             /* fall through */
4730c896fe29Sbellard         default:
473125c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
4732be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
4733c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
4734c896fe29Sbellard                faster to have specialized register allocator functions for
4735c896fe29Sbellard                some common argument patterns */
4736dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
4737c896fe29Sbellard             break;
4738c896fe29Sbellard         }
47398d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
4740c896fe29Sbellard         check_regs(s);
4741c896fe29Sbellard #endif
4742b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
4743b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
4744b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
4745b125f9dcSRichard Henderson            generating code without having to check during generation.  */
4746644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
4747b125f9dcSRichard Henderson             return -1;
4748b125f9dcSRichard Henderson         }
47496e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
47506e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
47516e6c4efeSRichard Henderson             return -2;
47526e6c4efeSRichard Henderson         }
4753c896fe29Sbellard     }
4754fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
4755fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
4756c45cb8bbSRichard Henderson 
4757b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
4758659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
4759aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
4760aeee05f5SRichard Henderson     if (i < 0) {
4761aeee05f5SRichard Henderson         return i;
476223dceda6SRichard Henderson     }
4763659ef5cbSRichard Henderson #endif
476457a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
47651768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
47661768987bSRichard Henderson     if (i < 0) {
47671768987bSRichard Henderson         return i;
476857a26946SRichard Henderson     }
476957a26946SRichard Henderson #endif
47707ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
47717ecd02a0SRichard Henderson         return -2;
47727ecd02a0SRichard Henderson     }
4773c896fe29Sbellard 
4774df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
4775c896fe29Sbellard     /* flush instruction cache */
4776db0c51a3SRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
4777db0c51a3SRichard Henderson                         (uintptr_t)s->code_buf,
47781da8de39SRichard Henderson                         tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
4779df5d2b16SRichard Henderson #endif
47802aeabc08SStefan Weil 
47811813e175SRichard Henderson     return tcg_current_code_size(s);
4782c896fe29Sbellard }
4783c896fe29Sbellard 
4784a23a9ec6Sbellard #ifdef CONFIG_PROFILER
47853de2faa9SMarkus Armbruster void tcg_dump_info(void)
4786a23a9ec6Sbellard {
4787c3fac113SEmilio G. Cota     TCGProfile prof = {};
4788c3fac113SEmilio G. Cota     const TCGProfile *s;
4789c3fac113SEmilio G. Cota     int64_t tb_count;
4790c3fac113SEmilio G. Cota     int64_t tb_div_count;
4791c3fac113SEmilio G. Cota     int64_t tot;
4792c3fac113SEmilio G. Cota 
4793c3fac113SEmilio G. Cota     tcg_profile_snapshot_counters(&prof);
4794c3fac113SEmilio G. Cota     s = &prof;
4795c3fac113SEmilio G. Cota     tb_count = s->tb_count;
4796c3fac113SEmilio G. Cota     tb_div_count = tb_count ? tb_count : 1;
4797c3fac113SEmilio G. Cota     tot = s->interm_time + s->code_time;
4798a23a9ec6Sbellard 
47993de2faa9SMarkus Armbruster     qemu_printf("JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
4800a23a9ec6Sbellard                 tot, tot / 2.4e9);
48013de2faa9SMarkus Armbruster     qemu_printf("translated TBs      %" PRId64 " (aborted=%" PRId64
48023de2faa9SMarkus Armbruster                 " %0.1f%%)\n",
4803fca8a500SRichard Henderson                 tb_count, s->tb_count1 - tb_count,
4804fca8a500SRichard Henderson                 (double)(s->tb_count1 - s->tb_count)
4805fca8a500SRichard Henderson                 / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
48063de2faa9SMarkus Armbruster     qemu_printf("avg ops/TB          %0.1f max=%d\n",
4807fca8a500SRichard Henderson                 (double)s->op_count / tb_div_count, s->op_count_max);
48083de2faa9SMarkus Armbruster     qemu_printf("deleted ops/TB      %0.2f\n",
4809fca8a500SRichard Henderson                 (double)s->del_op_count / tb_div_count);
48103de2faa9SMarkus Armbruster     qemu_printf("avg temps/TB        %0.2f max=%d\n",
4811fca8a500SRichard Henderson                 (double)s->temp_count / tb_div_count, s->temp_count_max);
48123de2faa9SMarkus Armbruster     qemu_printf("avg host code/TB    %0.1f\n",
4813fca8a500SRichard Henderson                 (double)s->code_out_len / tb_div_count);
48143de2faa9SMarkus Armbruster     qemu_printf("avg search data/TB  %0.1f\n",
4815fca8a500SRichard Henderson                 (double)s->search_out_len / tb_div_count);
4816a23a9ec6Sbellard 
48173de2faa9SMarkus Armbruster     qemu_printf("cycles/op           %0.1f\n",
4818a23a9ec6Sbellard                 s->op_count ? (double)tot / s->op_count : 0);
48193de2faa9SMarkus Armbruster     qemu_printf("cycles/in byte      %0.1f\n",
4820a23a9ec6Sbellard                 s->code_in_len ? (double)tot / s->code_in_len : 0);
48213de2faa9SMarkus Armbruster     qemu_printf("cycles/out byte     %0.1f\n",
4822a23a9ec6Sbellard                 s->code_out_len ? (double)tot / s->code_out_len : 0);
48233de2faa9SMarkus Armbruster     qemu_printf("cycles/search byte     %0.1f\n",
4824fca8a500SRichard Henderson                 s->search_out_len ? (double)tot / s->search_out_len : 0);
4825fca8a500SRichard Henderson     if (tot == 0) {
4826a23a9ec6Sbellard         tot = 1;
4827fca8a500SRichard Henderson     }
48283de2faa9SMarkus Armbruster     qemu_printf("  gen_interm time   %0.1f%%\n",
4829a23a9ec6Sbellard                 (double)s->interm_time / tot * 100.0);
48303de2faa9SMarkus Armbruster     qemu_printf("  gen_code time     %0.1f%%\n",
4831a23a9ec6Sbellard                 (double)s->code_time / tot * 100.0);
48323de2faa9SMarkus Armbruster     qemu_printf("optim./code time    %0.1f%%\n",
4833c5cc28ffSAurelien Jarno                 (double)s->opt_time / (s->code_time ? s->code_time : 1)
4834c5cc28ffSAurelien Jarno                 * 100.0);
48353de2faa9SMarkus Armbruster     qemu_printf("liveness/code time  %0.1f%%\n",
4836a23a9ec6Sbellard                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
48373de2faa9SMarkus Armbruster     qemu_printf("cpu_restore count   %" PRId64 "\n",
4838a23a9ec6Sbellard                 s->restore_count);
48393de2faa9SMarkus Armbruster     qemu_printf("  avg cycles        %0.1f\n",
4840a23a9ec6Sbellard                 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
4841a23a9ec6Sbellard }
4842a23a9ec6Sbellard #else
48433de2faa9SMarkus Armbruster void tcg_dump_info(void)
4844a23a9ec6Sbellard {
48453de2faa9SMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4846a23a9ec6Sbellard }
4847a23a9ec6Sbellard #endif
4848813da627SRichard Henderson 
4849813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
48505872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
48515872bbf2SRichard Henderson 
48525872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
48535872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
48545872bbf2SRichard Henderson 
48555872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
48565872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
48575872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
48585872bbf2SRichard Henderson 
48595872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
48605872bbf2SRichard Henderson */
4861813da627SRichard Henderson 
4862813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
4863813da627SRichard Henderson typedef enum {
4864813da627SRichard Henderson     JIT_NOACTION = 0,
4865813da627SRichard Henderson     JIT_REGISTER_FN,
4866813da627SRichard Henderson     JIT_UNREGISTER_FN
4867813da627SRichard Henderson } jit_actions_t;
4868813da627SRichard Henderson 
4869813da627SRichard Henderson struct jit_code_entry {
4870813da627SRichard Henderson     struct jit_code_entry *next_entry;
4871813da627SRichard Henderson     struct jit_code_entry *prev_entry;
4872813da627SRichard Henderson     const void *symfile_addr;
4873813da627SRichard Henderson     uint64_t symfile_size;
4874813da627SRichard Henderson };
4875813da627SRichard Henderson 
4876813da627SRichard Henderson struct jit_descriptor {
4877813da627SRichard Henderson     uint32_t version;
4878813da627SRichard Henderson     uint32_t action_flag;
4879813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
4880813da627SRichard Henderson     struct jit_code_entry *first_entry;
4881813da627SRichard Henderson };
4882813da627SRichard Henderson 
4883813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
4884813da627SRichard Henderson void __jit_debug_register_code(void)
4885813da627SRichard Henderson {
4886813da627SRichard Henderson     asm("");
4887813da627SRichard Henderson }
4888813da627SRichard Henderson 
4889813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
4890813da627SRichard Henderson    the version before we can set it.  */
4891813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
4892813da627SRichard Henderson 
4893813da627SRichard Henderson /* End GDB interface.  */
4894813da627SRichard Henderson 
4895813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
4896813da627SRichard Henderson {
4897813da627SRichard Henderson     const char *p = strtab + 1;
4898813da627SRichard Henderson 
4899813da627SRichard Henderson     while (1) {
4900813da627SRichard Henderson         if (strcmp(p, str) == 0) {
4901813da627SRichard Henderson             return p - strtab;
4902813da627SRichard Henderson         }
4903813da627SRichard Henderson         p += strlen(p) + 1;
4904813da627SRichard Henderson     }
4905813da627SRichard Henderson }
4906813da627SRichard Henderson 
4907755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size,
49082c90784aSRichard Henderson                                  const void *debug_frame,
49092c90784aSRichard Henderson                                  size_t debug_frame_size)
4910813da627SRichard Henderson {
49115872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
49125872bbf2SRichard Henderson         uint32_t  len;
49135872bbf2SRichard Henderson         uint16_t  version;
49145872bbf2SRichard Henderson         uint32_t  abbrev;
49155872bbf2SRichard Henderson         uint8_t   ptr_size;
49165872bbf2SRichard Henderson         uint8_t   cu_die;
49175872bbf2SRichard Henderson         uint16_t  cu_lang;
49185872bbf2SRichard Henderson         uintptr_t cu_low_pc;
49195872bbf2SRichard Henderson         uintptr_t cu_high_pc;
49205872bbf2SRichard Henderson         uint8_t   fn_die;
49215872bbf2SRichard Henderson         char      fn_name[16];
49225872bbf2SRichard Henderson         uintptr_t fn_low_pc;
49235872bbf2SRichard Henderson         uintptr_t fn_high_pc;
49245872bbf2SRichard Henderson         uint8_t   cu_eoc;
49255872bbf2SRichard Henderson     };
4926813da627SRichard Henderson 
4927813da627SRichard Henderson     struct ElfImage {
4928813da627SRichard Henderson         ElfW(Ehdr) ehdr;
4929813da627SRichard Henderson         ElfW(Phdr) phdr;
49305872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
49315872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
49325872bbf2SRichard Henderson         struct DebugInfo di;
49335872bbf2SRichard Henderson         uint8_t    da[24];
49345872bbf2SRichard Henderson         char       str[80];
49355872bbf2SRichard Henderson     };
49365872bbf2SRichard Henderson 
49375872bbf2SRichard Henderson     struct ElfImage *img;
49385872bbf2SRichard Henderson 
49395872bbf2SRichard Henderson     static const struct ElfImage img_template = {
49405872bbf2SRichard Henderson         .ehdr = {
49415872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
49425872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
49435872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
49445872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
49455872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
49465872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
49475872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
49485872bbf2SRichard Henderson             .e_type = ET_EXEC,
49495872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
49505872bbf2SRichard Henderson             .e_version = EV_CURRENT,
49515872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
49525872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
49535872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
49545872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
49555872bbf2SRichard Henderson             .e_phnum = 1,
49565872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
49575872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
49585872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
4959abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
4960abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
4961abbb3eaeSRichard Henderson #endif
4962abbb3eaeSRichard Henderson #ifdef ELF_OSABI
4963abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
4964abbb3eaeSRichard Henderson #endif
49655872bbf2SRichard Henderson         },
49665872bbf2SRichard Henderson         .phdr = {
49675872bbf2SRichard Henderson             .p_type = PT_LOAD,
49685872bbf2SRichard Henderson             .p_flags = PF_X,
49695872bbf2SRichard Henderson         },
49705872bbf2SRichard Henderson         .shdr = {
49715872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
49725872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
49735872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
49745872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
49755872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
49765872bbf2SRichard Henderson             [1] = { /* .text */
49775872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
49785872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
49795872bbf2SRichard Henderson             },
49805872bbf2SRichard Henderson             [2] = { /* .debug_info */
49815872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
49825872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
49835872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
49845872bbf2SRichard Henderson             },
49855872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
49865872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
49875872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
49885872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
49895872bbf2SRichard Henderson             },
49905872bbf2SRichard Henderson             [4] = { /* .debug_frame */
49915872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
49925872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
49935872bbf2SRichard Henderson             },
49945872bbf2SRichard Henderson             [5] = { /* .symtab */
49955872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
49965872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
49975872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
49985872bbf2SRichard Henderson                 .sh_info = 1,
49995872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
50005872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
50015872bbf2SRichard Henderson             },
50025872bbf2SRichard Henderson             [6] = { /* .strtab */
50035872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
50045872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
50055872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
50065872bbf2SRichard Henderson             }
50075872bbf2SRichard Henderson         },
50085872bbf2SRichard Henderson         .sym = {
50095872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
50105872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
50115872bbf2SRichard Henderson                 .st_shndx = 1,
50125872bbf2SRichard Henderson             }
50135872bbf2SRichard Henderson         },
50145872bbf2SRichard Henderson         .di = {
50155872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
50165872bbf2SRichard Henderson             .version = 2,
50175872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
50185872bbf2SRichard Henderson             .cu_die = 1,
50195872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
50205872bbf2SRichard Henderson             .fn_die = 2,
50215872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
50225872bbf2SRichard Henderson         },
50235872bbf2SRichard Henderson         .da = {
50245872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
50255872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
50265872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
50275872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
50285872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
50295872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
50305872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
50315872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
50325872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
50335872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
50345872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
50355872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
50365872bbf2SRichard Henderson             0           /* no more abbrev */
50375872bbf2SRichard Henderson         },
50385872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
50395872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
5040813da627SRichard Henderson     };
5041813da627SRichard Henderson 
5042813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
5043813da627SRichard Henderson     static struct jit_code_entry one_entry;
5044813da627SRichard Henderson 
50455872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
5046813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
50472c90784aSRichard Henderson     DebugFrameHeader *dfh;
5048813da627SRichard Henderson 
50495872bbf2SRichard Henderson     img = g_malloc(img_size);
50505872bbf2SRichard Henderson     *img = img_template;
5051813da627SRichard Henderson 
50525872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
50535872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
50545872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
5055813da627SRichard Henderson 
50565872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
50575872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
50585872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
5059813da627SRichard Henderson 
50605872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
50615872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
50625872bbf2SRichard Henderson 
50635872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
50645872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
50655872bbf2SRichard Henderson 
50665872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
50675872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
50685872bbf2SRichard Henderson 
50695872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
50705872bbf2SRichard Henderson     img->sym[1].st_value = buf;
50715872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
50725872bbf2SRichard Henderson 
50735872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
507445aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
50755872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
507645aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
5077813da627SRichard Henderson 
50782c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
50792c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
50802c90784aSRichard Henderson     dfh->fde.func_start = buf;
50812c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
50822c90784aSRichard Henderson 
5083813da627SRichard Henderson #ifdef DEBUG_JIT
5084813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
5085813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
5086813da627SRichard Henderson     {
5087813da627SRichard Henderson         FILE *f = fopen("/tmp/qemu.jit", "w+b");
5088813da627SRichard Henderson         if (f) {
50895872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
5090813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
5091813da627SRichard Henderson             }
5092813da627SRichard Henderson             fclose(f);
5093813da627SRichard Henderson         }
5094813da627SRichard Henderson     }
5095813da627SRichard Henderson #endif
5096813da627SRichard Henderson 
5097813da627SRichard Henderson     one_entry.symfile_addr = img;
5098813da627SRichard Henderson     one_entry.symfile_size = img_size;
5099813da627SRichard Henderson 
5100813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
5101813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
5102813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
5103813da627SRichard Henderson     __jit_debug_register_code();
5104813da627SRichard Henderson }
5105813da627SRichard Henderson #else
51065872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
51075872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
5108813da627SRichard Henderson 
5109755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
51102c90784aSRichard Henderson                                  const void *debug_frame,
51112c90784aSRichard Henderson                                  size_t debug_frame_size)
5112813da627SRichard Henderson {
5113813da627SRichard Henderson }
5114813da627SRichard Henderson 
5115755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size)
5116813da627SRichard Henderson {
5117813da627SRichard Henderson }
5118813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
5119db432672SRichard Henderson 
5120db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
5121db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
5122db432672SRichard Henderson {
5123db432672SRichard Henderson     g_assert_not_reached();
5124db432672SRichard Henderson }
5125db432672SRichard Henderson #endif
5126