xref: /qemu/tcg/tcg.c (revision 15c4e8fe44e34eee4a13135eeb121b3b26e4cd1b)
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 #include "cpu.h"
45c896fe29Sbellard 
4663c91552SPaolo Bonzini #include "exec/exec-all.h"
4763c91552SPaolo Bonzini 
485cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY)
495cc8767dSLike Xu #include "hw/boards.h"
505cc8767dSLike Xu #endif
515cc8767dSLike Xu 
52dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
53813da627SRichard Henderson 
54edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX
55813da627SRichard Henderson # define ELF_CLASS  ELFCLASS32
56edee2579SRichard Henderson #else
57edee2579SRichard Henderson # define ELF_CLASS  ELFCLASS64
58813da627SRichard Henderson #endif
59813da627SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
60813da627SRichard Henderson # define ELF_DATA   ELFDATA2MSB
61813da627SRichard Henderson #else
62813da627SRichard Henderson # define ELF_DATA   ELFDATA2LSB
63813da627SRichard Henderson #endif
64813da627SRichard Henderson 
65c896fe29Sbellard #include "elf.h"
66508127e2SPaolo Bonzini #include "exec/log.h"
673468b59eSEmilio G. Cota #include "sysemu/sysemu.h"
68c896fe29Sbellard 
69139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and
70ce151109SPeter Maydell    used here. */
71e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s);
72e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
736ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
742ba7fae2SRichard Henderson                         intptr_t value, intptr_t addend);
75c896fe29Sbellard 
76497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts.  */
77497a22ebSRichard Henderson typedef struct {
78497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
79497a22ebSRichard Henderson     uint32_t id;
80497a22ebSRichard Henderson     uint8_t version;
81497a22ebSRichard Henderson     char augmentation[1];
82497a22ebSRichard Henderson     uint8_t code_align;
83497a22ebSRichard Henderson     uint8_t data_align;
84497a22ebSRichard Henderson     uint8_t return_column;
85497a22ebSRichard Henderson } DebugFrameCIE;
86497a22ebSRichard Henderson 
87497a22ebSRichard Henderson typedef struct QEMU_PACKED {
88497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
89497a22ebSRichard Henderson     uint32_t cie_offset;
90edee2579SRichard Henderson     uintptr_t func_start;
91edee2579SRichard Henderson     uintptr_t func_len;
92497a22ebSRichard Henderson } DebugFrameFDEHeader;
93497a22ebSRichard Henderson 
942c90784aSRichard Henderson typedef struct QEMU_PACKED {
952c90784aSRichard Henderson     DebugFrameCIE cie;
962c90784aSRichard Henderson     DebugFrameFDEHeader fde;
972c90784aSRichard Henderson } DebugFrameHeader;
982c90784aSRichard Henderson 
99755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
1002c90784aSRichard Henderson                                  const void *debug_frame,
1012c90784aSRichard Henderson                                  size_t debug_frame_size)
102813da627SRichard Henderson     __attribute__((unused));
103813da627SRichard Henderson 
104139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */
1052a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
106a05b5b9bSRichard Henderson                        intptr_t arg2);
10778113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
108c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1092a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
1105e8892dbSMiroslav Rezanina static void tcg_out_op(TCGContext *s, TCGOpcode opc,
1115e8892dbSMiroslav Rezanina                        const TCGArg args[TCG_MAX_OP_ARGS],
1125e8892dbSMiroslav Rezanina                        const int const_args[TCG_MAX_OP_ARGS]);
113d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec
114e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
115e7632cfaSRichard Henderson                             TCGReg dst, TCGReg src);
116d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
117d6ecb4a9SRichard Henderson                              TCGReg dst, TCGReg base, intptr_t offset);
1184e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1194e186175SRichard Henderson                              TCGReg dst, int64_t arg);
1205e8892dbSMiroslav Rezanina static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1215e8892dbSMiroslav Rezanina                            unsigned vecl, unsigned vece,
1225e8892dbSMiroslav Rezanina                            const TCGArg args[TCG_MAX_OP_ARGS],
1235e8892dbSMiroslav Rezanina                            const int const_args[TCG_MAX_OP_ARGS]);
124d2fd745fSRichard Henderson #else
125e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
126e7632cfaSRichard Henderson                                    TCGReg dst, TCGReg src)
127e7632cfaSRichard Henderson {
128e7632cfaSRichard Henderson     g_assert_not_reached();
129e7632cfaSRichard Henderson }
130d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
131d6ecb4a9SRichard Henderson                                     TCGReg dst, TCGReg base, intptr_t offset)
132d6ecb4a9SRichard Henderson {
133d6ecb4a9SRichard Henderson     g_assert_not_reached();
134d6ecb4a9SRichard Henderson }
1354e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1364e186175SRichard Henderson                                     TCGReg dst, int64_t arg)
137e7632cfaSRichard Henderson {
138e7632cfaSRichard Henderson     g_assert_not_reached();
139e7632cfaSRichard Henderson }
1405e8892dbSMiroslav Rezanina static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
1415e8892dbSMiroslav Rezanina                                   unsigned vecl, unsigned vece,
1425e8892dbSMiroslav Rezanina                                   const TCGArg args[TCG_MAX_OP_ARGS],
1435e8892dbSMiroslav Rezanina                                   const int const_args[TCG_MAX_OP_ARGS])
144d2fd745fSRichard Henderson {
145d2fd745fSRichard Henderson     g_assert_not_reached();
146d2fd745fSRichard Henderson }
147d2fd745fSRichard Henderson #endif
1482a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
149a05b5b9bSRichard Henderson                        intptr_t arg2);
15059d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
15159d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
1522be7d76bSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target);
153f6c6afc1SRichard Henderson static int tcg_target_const_match(tcg_target_long val, TCGType type,
154c0ad3001SStefan Weil                                   const TCGArgConstraint *arg_ct);
155659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
156aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s);
157659ef5cbSRichard Henderson #endif
158c896fe29Sbellard 
159a505785cSEmilio G. Cota #define TCG_HIGHWATER 1024
160a505785cSEmilio G. Cota 
161df2cce29SEmilio G. Cota static TCGContext **tcg_ctxs;
162df2cce29SEmilio G. Cota static unsigned int n_tcg_ctxs;
1631c2adb95SRichard Henderson TCGv_env cpu_env = 0;
164c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue;
165db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff;
166df2cce29SEmilio G. Cota 
167b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
168b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec;
169b91ccb31SRichard Henderson #endif
170b91ccb31SRichard Henderson 
171be2cdc5eSEmilio G. Cota struct tcg_region_tree {
172be2cdc5eSEmilio G. Cota     QemuMutex lock;
173be2cdc5eSEmilio G. Cota     GTree *tree;
174be2cdc5eSEmilio G. Cota     /* padding to avoid false sharing is computed at run-time */
175be2cdc5eSEmilio G. Cota };
176be2cdc5eSEmilio G. Cota 
177e8feb96fSEmilio G. Cota /*
178e8feb96fSEmilio G. Cota  * We divide code_gen_buffer into equally-sized "regions" that TCG threads
179e8feb96fSEmilio G. Cota  * dynamically allocate from as demand dictates. Given appropriate region
180e8feb96fSEmilio G. Cota  * sizing, this minimizes flushes even when some TCG threads generate a lot
181e8feb96fSEmilio G. Cota  * more code than others.
182e8feb96fSEmilio G. Cota  */
183e8feb96fSEmilio G. Cota struct tcg_region_state {
184e8feb96fSEmilio G. Cota     QemuMutex lock;
185e8feb96fSEmilio G. Cota 
186e8feb96fSEmilio G. Cota     /* fields set at init time */
187e8feb96fSEmilio G. Cota     void *start;
188e8feb96fSEmilio G. Cota     void *start_aligned;
189e8feb96fSEmilio G. Cota     void *end;
190e8feb96fSEmilio G. Cota     size_t n;
191e8feb96fSEmilio G. Cota     size_t size; /* size of one region */
192e8feb96fSEmilio G. Cota     size_t stride; /* .size + guard size */
193e8feb96fSEmilio G. Cota 
194e8feb96fSEmilio G. Cota     /* fields protected by the lock */
195e8feb96fSEmilio G. Cota     size_t current; /* current region index */
196e8feb96fSEmilio G. Cota     size_t agg_size_full; /* aggregate size of full regions */
197e8feb96fSEmilio G. Cota };
198e8feb96fSEmilio G. Cota 
199e8feb96fSEmilio G. Cota static struct tcg_region_state region;
200be2cdc5eSEmilio G. Cota /*
201be2cdc5eSEmilio G. Cota  * This is an array of struct tcg_region_tree's, with padding.
202be2cdc5eSEmilio G. Cota  * We use void * to simplify the computation of region_trees[i]; each
203be2cdc5eSEmilio G. Cota  * struct is found every tree_size bytes.
204be2cdc5eSEmilio G. Cota  */
205be2cdc5eSEmilio G. Cota static void *region_trees;
206be2cdc5eSEmilio G. Cota static size_t tree_size;
207d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
208b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
209c896fe29Sbellard 
2101813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
2114196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
212c896fe29Sbellard {
213c896fe29Sbellard     *s->code_ptr++ = v;
214c896fe29Sbellard }
215c896fe29Sbellard 
2164196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
2174196dca6SPeter Maydell                                                       uint8_t v)
2185c53bb81SPeter Maydell {
2191813e175SRichard Henderson     *p = v;
2205c53bb81SPeter Maydell }
2211813e175SRichard Henderson #endif
2225c53bb81SPeter Maydell 
2231813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
2244196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
225c896fe29Sbellard {
2261813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2271813e175SRichard Henderson         *s->code_ptr++ = v;
2281813e175SRichard Henderson     } else {
2291813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2304387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2311813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
2321813e175SRichard Henderson     }
233c896fe29Sbellard }
234c896fe29Sbellard 
2354196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2364196dca6SPeter Maydell                                                        uint16_t v)
2375c53bb81SPeter Maydell {
2381813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2391813e175SRichard Henderson         *p = v;
2401813e175SRichard Henderson     } else {
2415c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2425c53bb81SPeter Maydell     }
2431813e175SRichard Henderson }
2441813e175SRichard Henderson #endif
2455c53bb81SPeter Maydell 
2461813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
2474196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
248c896fe29Sbellard {
2491813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2501813e175SRichard Henderson         *s->code_ptr++ = v;
2511813e175SRichard Henderson     } else {
2521813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2534387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2541813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
2551813e175SRichard Henderson     }
256c896fe29Sbellard }
257c896fe29Sbellard 
2584196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
2594196dca6SPeter Maydell                                                        uint32_t v)
2605c53bb81SPeter Maydell {
2611813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2621813e175SRichard Henderson         *p = v;
2631813e175SRichard Henderson     } else {
2645c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2655c53bb81SPeter Maydell     }
2661813e175SRichard Henderson }
2671813e175SRichard Henderson #endif
2685c53bb81SPeter Maydell 
2691813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
2704196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
271ac26eb69SRichard Henderson {
2721813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2731813e175SRichard Henderson         *s->code_ptr++ = v;
2741813e175SRichard Henderson     } else {
2751813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2764387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2771813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
2781813e175SRichard Henderson     }
279ac26eb69SRichard Henderson }
280ac26eb69SRichard Henderson 
2814196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
2824196dca6SPeter Maydell                                                        uint64_t v)
2835c53bb81SPeter Maydell {
2841813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2851813e175SRichard Henderson         *p = v;
2861813e175SRichard Henderson     } else {
2875c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2885c53bb81SPeter Maydell     }
2891813e175SRichard Henderson }
2901813e175SRichard Henderson #endif
2915c53bb81SPeter Maydell 
292c896fe29Sbellard /* label relocation processing */
293c896fe29Sbellard 
2941813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
295bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
296c896fe29Sbellard {
2977ecd02a0SRichard Henderson     TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation));
298c896fe29Sbellard 
299c896fe29Sbellard     r->type = type;
300c896fe29Sbellard     r->ptr = code_ptr;
301c896fe29Sbellard     r->addend = addend;
3027ecd02a0SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
303c896fe29Sbellard }
304c896fe29Sbellard 
30592ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l)
306c896fe29Sbellard {
307eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
308c896fe29Sbellard     l->has_value = 1;
30992ab8e7dSRichard Henderson     l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr);
310c896fe29Sbellard }
311c896fe29Sbellard 
31242a268c2SRichard Henderson TCGLabel *gen_new_label(void)
313c896fe29Sbellard {
314b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
31551e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
316c896fe29Sbellard 
3177ecd02a0SRichard Henderson     memset(l, 0, sizeof(TCGLabel));
3187ecd02a0SRichard Henderson     l->id = s->nb_labels++;
3197ecd02a0SRichard Henderson     QSIMPLEQ_INIT(&l->relocs);
3207ecd02a0SRichard Henderson 
321bef16ab4SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
32242a268c2SRichard Henderson 
32342a268c2SRichard Henderson     return l;
324c896fe29Sbellard }
325c896fe29Sbellard 
3267ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s)
3277ecd02a0SRichard Henderson {
3287ecd02a0SRichard Henderson     TCGLabel *l;
3297ecd02a0SRichard Henderson 
3307ecd02a0SRichard Henderson     QSIMPLEQ_FOREACH(l, &s->labels, next) {
3317ecd02a0SRichard Henderson         TCGRelocation *r;
3327ecd02a0SRichard Henderson         uintptr_t value = l->u.value;
3337ecd02a0SRichard Henderson 
3347ecd02a0SRichard Henderson         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
3357ecd02a0SRichard Henderson             if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
3367ecd02a0SRichard Henderson                 return false;
3377ecd02a0SRichard Henderson             }
3387ecd02a0SRichard Henderson         }
3397ecd02a0SRichard Henderson     }
3407ecd02a0SRichard Henderson     return true;
3417ecd02a0SRichard Henderson }
3427ecd02a0SRichard Henderson 
3439f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3449f754620SRichard Henderson {
345f14bed3fSRichard Henderson     /*
346f14bed3fSRichard Henderson      * We will check for overflow at the end of the opcode loop in
347f14bed3fSRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
348f14bed3fSRichard Henderson      */
349f14bed3fSRichard Henderson     s->tb_jmp_reset_offset[which] = tcg_current_code_size(s);
3509f754620SRichard Henderson }
3519f754620SRichard Henderson 
352db6b7d0cSRichard Henderson /* Signal overflow, starting over with fewer guest insns. */
353db6b7d0cSRichard Henderson static void QEMU_NORETURN tcg_raise_tb_overflow(TCGContext *s)
354db6b7d0cSRichard Henderson {
355db6b7d0cSRichard Henderson     siglongjmp(s->jmp_trans, -2);
356db6b7d0cSRichard Henderson }
357db6b7d0cSRichard Henderson 
3584c22e840SRichard Henderson #define C_PFX1(P, A)                    P##A
3594c22e840SRichard Henderson #define C_PFX2(P, A, B)                 P##A##_##B
3604c22e840SRichard Henderson #define C_PFX3(P, A, B, C)              P##A##_##B##_##C
3614c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D)           P##A##_##B##_##C##_##D
3624c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E)        P##A##_##B##_##C##_##D##_##E
3634c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F)     P##A##_##B##_##C##_##D##_##E##_##F
3644c22e840SRichard Henderson 
3654c22e840SRichard Henderson /* Define an enumeration for the various combinations. */
3664c22e840SRichard Henderson 
3674c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1),
3684c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2),
3694c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3),
3704c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4),
3714c22e840SRichard Henderson 
3724c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1),
3734c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2),
3744c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3),
3754c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4),
3764c22e840SRichard Henderson 
3774c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2),
3784c22e840SRichard Henderson 
3794c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1),
3804c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2),
3814c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3),
3824c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4),
3834c22e840SRichard Henderson 
3844c22e840SRichard Henderson typedef enum {
3854c22e840SRichard Henderson #include "tcg-target-con-set.h"
3864c22e840SRichard Henderson } TCGConstraintSetIndex;
3874c22e840SRichard Henderson 
3884c22e840SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode);
3894c22e840SRichard Henderson 
3904c22e840SRichard Henderson #undef C_O0_I1
3914c22e840SRichard Henderson #undef C_O0_I2
3924c22e840SRichard Henderson #undef C_O0_I3
3934c22e840SRichard Henderson #undef C_O0_I4
3944c22e840SRichard Henderson #undef C_O1_I1
3954c22e840SRichard Henderson #undef C_O1_I2
3964c22e840SRichard Henderson #undef C_O1_I3
3974c22e840SRichard Henderson #undef C_O1_I4
3984c22e840SRichard Henderson #undef C_N1_I2
3994c22e840SRichard Henderson #undef C_O2_I1
4004c22e840SRichard Henderson #undef C_O2_I2
4014c22e840SRichard Henderson #undef C_O2_I3
4024c22e840SRichard Henderson #undef C_O2_I4
4034c22e840SRichard Henderson 
4044c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */
4054c22e840SRichard Henderson 
4064c22e840SRichard Henderson #define C_O0_I1(I1)                     { .args_ct_str = { #I1 } },
4074c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 { .args_ct_str = { #I1, #I2 } },
4084c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             { .args_ct_str = { #I1, #I2, #I3 } },
4094c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         { .args_ct_str = { #I1, #I2, #I3, #I4 } },
4104c22e840SRichard Henderson 
4114c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 { .args_ct_str = { #O1, #I1 } },
4124c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             { .args_ct_str = { #O1, #I1, #I2 } },
4134c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         { .args_ct_str = { #O1, #I1, #I2, #I3 } },
4144c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } },
4154c22e840SRichard Henderson 
4164c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             { .args_ct_str = { "&" #O1, #I1, #I2 } },
4174c22e840SRichard Henderson 
4184c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             { .args_ct_str = { #O1, #O2, #I1 } },
4194c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         { .args_ct_str = { #O1, #O2, #I1, #I2 } },
4204c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } },
4214c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } },
4224c22e840SRichard Henderson 
4234c22e840SRichard Henderson static const TCGTargetOpDef constraint_sets[] = {
4244c22e840SRichard Henderson #include "tcg-target-con-set.h"
4254c22e840SRichard Henderson };
4264c22e840SRichard Henderson 
4274c22e840SRichard Henderson 
4284c22e840SRichard Henderson #undef C_O0_I1
4294c22e840SRichard Henderson #undef C_O0_I2
4304c22e840SRichard Henderson #undef C_O0_I3
4314c22e840SRichard Henderson #undef C_O0_I4
4324c22e840SRichard Henderson #undef C_O1_I1
4334c22e840SRichard Henderson #undef C_O1_I2
4344c22e840SRichard Henderson #undef C_O1_I3
4354c22e840SRichard Henderson #undef C_O1_I4
4364c22e840SRichard Henderson #undef C_N1_I2
4374c22e840SRichard Henderson #undef C_O2_I1
4384c22e840SRichard Henderson #undef C_O2_I2
4394c22e840SRichard Henderson #undef C_O2_I3
4404c22e840SRichard Henderson #undef C_O2_I4
4414c22e840SRichard Henderson 
4424c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */
4434c22e840SRichard Henderson 
4444c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1)
4454c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2)
4464c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3)
4474c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4)
4484c22e840SRichard Henderson 
4494c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1)
4504c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2)
4514c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3)
4524c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4)
4534c22e840SRichard Henderson 
4544c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2)
4554c22e840SRichard Henderson 
4564c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1)
4574c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2)
4584c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3)
4594c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4)
4604c22e840SRichard Henderson 
461139c1837SPaolo Bonzini #include "tcg-target.c.inc"
462c896fe29Sbellard 
463be2cdc5eSEmilio G. Cota /* compare a pointer @ptr and a tb_tc @s */
464be2cdc5eSEmilio G. Cota static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s)
465be2cdc5eSEmilio G. Cota {
466be2cdc5eSEmilio G. Cota     if (ptr >= s->ptr + s->size) {
467be2cdc5eSEmilio G. Cota         return 1;
468be2cdc5eSEmilio G. Cota     } else if (ptr < s->ptr) {
469be2cdc5eSEmilio G. Cota         return -1;
470be2cdc5eSEmilio G. Cota     }
471be2cdc5eSEmilio G. Cota     return 0;
472be2cdc5eSEmilio G. Cota }
473be2cdc5eSEmilio G. Cota 
474be2cdc5eSEmilio G. Cota static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp)
475be2cdc5eSEmilio G. Cota {
476be2cdc5eSEmilio G. Cota     const struct tb_tc *a = ap;
477be2cdc5eSEmilio G. Cota     const struct tb_tc *b = bp;
478be2cdc5eSEmilio G. Cota 
479be2cdc5eSEmilio G. Cota     /*
480be2cdc5eSEmilio G. Cota      * When both sizes are set, we know this isn't a lookup.
481be2cdc5eSEmilio G. Cota      * This is the most likely case: every TB must be inserted; lookups
482be2cdc5eSEmilio G. Cota      * are a lot less frequent.
483be2cdc5eSEmilio G. Cota      */
484be2cdc5eSEmilio G. Cota     if (likely(a->size && b->size)) {
485be2cdc5eSEmilio G. Cota         if (a->ptr > b->ptr) {
486be2cdc5eSEmilio G. Cota             return 1;
487be2cdc5eSEmilio G. Cota         } else if (a->ptr < b->ptr) {
488be2cdc5eSEmilio G. Cota             return -1;
489be2cdc5eSEmilio G. Cota         }
490be2cdc5eSEmilio G. Cota         /* a->ptr == b->ptr should happen only on deletions */
491be2cdc5eSEmilio G. Cota         g_assert(a->size == b->size);
492be2cdc5eSEmilio G. Cota         return 0;
493be2cdc5eSEmilio G. Cota     }
494be2cdc5eSEmilio G. Cota     /*
495be2cdc5eSEmilio G. Cota      * All lookups have either .size field set to 0.
496be2cdc5eSEmilio G. Cota      * From the glib sources we see that @ap is always the lookup key. However
497be2cdc5eSEmilio G. Cota      * the docs provide no guarantee, so we just mark this case as likely.
498be2cdc5eSEmilio G. Cota      */
499be2cdc5eSEmilio G. Cota     if (likely(a->size == 0)) {
500be2cdc5eSEmilio G. Cota         return ptr_cmp_tb_tc(a->ptr, b);
501be2cdc5eSEmilio G. Cota     }
502be2cdc5eSEmilio G. Cota     return ptr_cmp_tb_tc(b->ptr, a);
503be2cdc5eSEmilio G. Cota }
504be2cdc5eSEmilio G. Cota 
505be2cdc5eSEmilio G. Cota static void tcg_region_trees_init(void)
506be2cdc5eSEmilio G. Cota {
507be2cdc5eSEmilio G. Cota     size_t i;
508be2cdc5eSEmilio G. Cota 
509be2cdc5eSEmilio G. Cota     tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize);
510be2cdc5eSEmilio G. Cota     region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size);
511be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
512be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
513be2cdc5eSEmilio G. Cota 
514be2cdc5eSEmilio G. Cota         qemu_mutex_init(&rt->lock);
515be2cdc5eSEmilio G. Cota         rt->tree = g_tree_new(tb_tc_cmp);
516be2cdc5eSEmilio G. Cota     }
517be2cdc5eSEmilio G. Cota }
518be2cdc5eSEmilio G. Cota 
5190610067eSRichard Henderson static struct tcg_region_tree *tc_ptr_to_region_tree(const void *p)
520be2cdc5eSEmilio G. Cota {
521be2cdc5eSEmilio G. Cota     size_t region_idx;
522be2cdc5eSEmilio G. Cota 
5230610067eSRichard Henderson     /*
5240610067eSRichard Henderson      * Like tcg_splitwx_to_rw, with no assert.  The pc may come from
5250610067eSRichard Henderson      * a signal handler over which the caller has no control.
5260610067eSRichard Henderson      */
5270610067eSRichard Henderson     if (!in_code_gen_buffer(p)) {
5280610067eSRichard Henderson         p -= tcg_splitwx_diff;
5290610067eSRichard Henderson         if (!in_code_gen_buffer(p)) {
5300610067eSRichard Henderson             return NULL;
5310610067eSRichard Henderson         }
5320610067eSRichard Henderson     }
5330610067eSRichard Henderson 
534be2cdc5eSEmilio G. Cota     if (p < region.start_aligned) {
535be2cdc5eSEmilio G. Cota         region_idx = 0;
536be2cdc5eSEmilio G. Cota     } else {
537be2cdc5eSEmilio G. Cota         ptrdiff_t offset = p - region.start_aligned;
538be2cdc5eSEmilio G. Cota 
539be2cdc5eSEmilio G. Cota         if (offset > region.stride * (region.n - 1)) {
540be2cdc5eSEmilio G. Cota             region_idx = region.n - 1;
541be2cdc5eSEmilio G. Cota         } else {
542be2cdc5eSEmilio G. Cota             region_idx = offset / region.stride;
543be2cdc5eSEmilio G. Cota         }
544be2cdc5eSEmilio G. Cota     }
545be2cdc5eSEmilio G. Cota     return region_trees + region_idx * tree_size;
546be2cdc5eSEmilio G. Cota }
547be2cdc5eSEmilio G. Cota 
548be2cdc5eSEmilio G. Cota void tcg_tb_insert(TranslationBlock *tb)
549be2cdc5eSEmilio G. Cota {
550be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
551be2cdc5eSEmilio G. Cota 
5520610067eSRichard Henderson     g_assert(rt != NULL);
553be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
554be2cdc5eSEmilio G. Cota     g_tree_insert(rt->tree, &tb->tc, tb);
555be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
556be2cdc5eSEmilio G. Cota }
557be2cdc5eSEmilio G. Cota 
558be2cdc5eSEmilio G. Cota void tcg_tb_remove(TranslationBlock *tb)
559be2cdc5eSEmilio G. Cota {
560be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
561be2cdc5eSEmilio G. Cota 
5620610067eSRichard Henderson     g_assert(rt != NULL);
563be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
564be2cdc5eSEmilio G. Cota     g_tree_remove(rt->tree, &tb->tc);
565be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
566be2cdc5eSEmilio G. Cota }
567be2cdc5eSEmilio G. Cota 
568be2cdc5eSEmilio G. Cota /*
569be2cdc5eSEmilio G. Cota  * Find the TB 'tb' such that
570be2cdc5eSEmilio G. Cota  * tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size
571be2cdc5eSEmilio G. Cota  * Return NULL if not found.
572be2cdc5eSEmilio G. Cota  */
573be2cdc5eSEmilio G. Cota TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr)
574be2cdc5eSEmilio G. Cota {
575be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr);
576be2cdc5eSEmilio G. Cota     TranslationBlock *tb;
577be2cdc5eSEmilio G. Cota     struct tb_tc s = { .ptr = (void *)tc_ptr };
578be2cdc5eSEmilio G. Cota 
5790610067eSRichard Henderson     if (rt == NULL) {
5800610067eSRichard Henderson         return NULL;
5810610067eSRichard Henderson     }
5820610067eSRichard Henderson 
583be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
584be2cdc5eSEmilio G. Cota     tb = g_tree_lookup(rt->tree, &s);
585be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
586be2cdc5eSEmilio G. Cota     return tb;
587be2cdc5eSEmilio G. Cota }
588be2cdc5eSEmilio G. Cota 
589be2cdc5eSEmilio G. Cota static void tcg_region_tree_lock_all(void)
590be2cdc5eSEmilio G. Cota {
591be2cdc5eSEmilio G. Cota     size_t i;
592be2cdc5eSEmilio G. Cota 
593be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
594be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
595be2cdc5eSEmilio G. Cota 
596be2cdc5eSEmilio G. Cota         qemu_mutex_lock(&rt->lock);
597be2cdc5eSEmilio G. Cota     }
598be2cdc5eSEmilio G. Cota }
599be2cdc5eSEmilio G. Cota 
600be2cdc5eSEmilio G. Cota static void tcg_region_tree_unlock_all(void)
601be2cdc5eSEmilio G. Cota {
602be2cdc5eSEmilio G. Cota     size_t i;
603be2cdc5eSEmilio G. Cota 
604be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
605be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
606be2cdc5eSEmilio G. Cota 
607be2cdc5eSEmilio G. Cota         qemu_mutex_unlock(&rt->lock);
608be2cdc5eSEmilio G. Cota     }
609be2cdc5eSEmilio G. Cota }
610be2cdc5eSEmilio G. Cota 
611be2cdc5eSEmilio G. Cota void tcg_tb_foreach(GTraverseFunc func, gpointer user_data)
612be2cdc5eSEmilio G. Cota {
613be2cdc5eSEmilio G. Cota     size_t i;
614be2cdc5eSEmilio G. Cota 
615be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
616be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
617be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
618be2cdc5eSEmilio G. Cota 
619be2cdc5eSEmilio G. Cota         g_tree_foreach(rt->tree, func, user_data);
620be2cdc5eSEmilio G. Cota     }
621be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
622be2cdc5eSEmilio G. Cota }
623be2cdc5eSEmilio G. Cota 
624be2cdc5eSEmilio G. Cota size_t tcg_nb_tbs(void)
625be2cdc5eSEmilio G. Cota {
626be2cdc5eSEmilio G. Cota     size_t nb_tbs = 0;
627be2cdc5eSEmilio G. Cota     size_t i;
628be2cdc5eSEmilio G. Cota 
629be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
630be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
631be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
632be2cdc5eSEmilio G. Cota 
633be2cdc5eSEmilio G. Cota         nb_tbs += g_tree_nnodes(rt->tree);
634be2cdc5eSEmilio G. Cota     }
635be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
636be2cdc5eSEmilio G. Cota     return nb_tbs;
637be2cdc5eSEmilio G. Cota }
638be2cdc5eSEmilio G. Cota 
639938e897aSEmilio G. Cota static gboolean tcg_region_tree_traverse(gpointer k, gpointer v, gpointer data)
640938e897aSEmilio G. Cota {
641938e897aSEmilio G. Cota     TranslationBlock *tb = v;
642938e897aSEmilio G. Cota 
643938e897aSEmilio G. Cota     tb_destroy(tb);
644938e897aSEmilio G. Cota     return FALSE;
645938e897aSEmilio G. Cota }
646938e897aSEmilio G. Cota 
647be2cdc5eSEmilio G. Cota static void tcg_region_tree_reset_all(void)
648be2cdc5eSEmilio G. Cota {
649be2cdc5eSEmilio G. Cota     size_t i;
650be2cdc5eSEmilio G. Cota 
651be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
652be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
653be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
654be2cdc5eSEmilio G. Cota 
655938e897aSEmilio G. Cota         g_tree_foreach(rt->tree, tcg_region_tree_traverse, NULL);
656be2cdc5eSEmilio G. Cota         /* Increment the refcount first so that destroy acts as a reset */
657be2cdc5eSEmilio G. Cota         g_tree_ref(rt->tree);
658be2cdc5eSEmilio G. Cota         g_tree_destroy(rt->tree);
659be2cdc5eSEmilio G. Cota     }
660be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
661be2cdc5eSEmilio G. Cota }
662be2cdc5eSEmilio G. Cota 
663e8feb96fSEmilio G. Cota static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend)
664e8feb96fSEmilio G. Cota {
665e8feb96fSEmilio G. Cota     void *start, *end;
666e8feb96fSEmilio G. Cota 
667e8feb96fSEmilio G. Cota     start = region.start_aligned + curr_region * region.stride;
668e8feb96fSEmilio G. Cota     end = start + region.size;
669e8feb96fSEmilio G. Cota 
670e8feb96fSEmilio G. Cota     if (curr_region == 0) {
671e8feb96fSEmilio G. Cota         start = region.start;
672e8feb96fSEmilio G. Cota     }
673e8feb96fSEmilio G. Cota     if (curr_region == region.n - 1) {
674e8feb96fSEmilio G. Cota         end = region.end;
675e8feb96fSEmilio G. Cota     }
676e8feb96fSEmilio G. Cota 
677e8feb96fSEmilio G. Cota     *pstart = start;
678e8feb96fSEmilio G. Cota     *pend = end;
679e8feb96fSEmilio G. Cota }
680e8feb96fSEmilio G. Cota 
681e8feb96fSEmilio G. Cota static void tcg_region_assign(TCGContext *s, size_t curr_region)
682e8feb96fSEmilio G. Cota {
683e8feb96fSEmilio G. Cota     void *start, *end;
684e8feb96fSEmilio G. Cota 
685e8feb96fSEmilio G. Cota     tcg_region_bounds(curr_region, &start, &end);
686e8feb96fSEmilio G. Cota 
687e8feb96fSEmilio G. Cota     s->code_gen_buffer = start;
688e8feb96fSEmilio G. Cota     s->code_gen_ptr = start;
689e8feb96fSEmilio G. Cota     s->code_gen_buffer_size = end - start;
690e8feb96fSEmilio G. Cota     s->code_gen_highwater = end - TCG_HIGHWATER;
691e8feb96fSEmilio G. Cota }
692e8feb96fSEmilio G. Cota 
693e8feb96fSEmilio G. Cota static bool tcg_region_alloc__locked(TCGContext *s)
694e8feb96fSEmilio G. Cota {
695e8feb96fSEmilio G. Cota     if (region.current == region.n) {
696e8feb96fSEmilio G. Cota         return true;
697e8feb96fSEmilio G. Cota     }
698e8feb96fSEmilio G. Cota     tcg_region_assign(s, region.current);
699e8feb96fSEmilio G. Cota     region.current++;
700e8feb96fSEmilio G. Cota     return false;
701e8feb96fSEmilio G. Cota }
702e8feb96fSEmilio G. Cota 
703e8feb96fSEmilio G. Cota /*
704e8feb96fSEmilio G. Cota  * Request a new region once the one in use has filled up.
705e8feb96fSEmilio G. Cota  * Returns true on error.
706e8feb96fSEmilio G. Cota  */
707e8feb96fSEmilio G. Cota static bool tcg_region_alloc(TCGContext *s)
708e8feb96fSEmilio G. Cota {
709e8feb96fSEmilio G. Cota     bool err;
710e8feb96fSEmilio G. Cota     /* read the region size now; alloc__locked will overwrite it on success */
711e8feb96fSEmilio G. Cota     size_t size_full = s->code_gen_buffer_size;
712e8feb96fSEmilio G. Cota 
713e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
714e8feb96fSEmilio G. Cota     err = tcg_region_alloc__locked(s);
715e8feb96fSEmilio G. Cota     if (!err) {
716e8feb96fSEmilio G. Cota         region.agg_size_full += size_full - TCG_HIGHWATER;
717e8feb96fSEmilio G. Cota     }
718e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
719e8feb96fSEmilio G. Cota     return err;
720e8feb96fSEmilio G. Cota }
721e8feb96fSEmilio G. Cota 
722e8feb96fSEmilio G. Cota /*
723e8feb96fSEmilio G. Cota  * Perform a context's first region allocation.
724e8feb96fSEmilio G. Cota  * This function does _not_ increment region.agg_size_full.
725e8feb96fSEmilio G. Cota  */
726e8feb96fSEmilio G. Cota static inline bool tcg_region_initial_alloc__locked(TCGContext *s)
727e8feb96fSEmilio G. Cota {
728e8feb96fSEmilio G. Cota     return tcg_region_alloc__locked(s);
729e8feb96fSEmilio G. Cota }
730e8feb96fSEmilio G. Cota 
731e8feb96fSEmilio G. Cota /* Call from a safe-work context */
732e8feb96fSEmilio G. Cota void tcg_region_reset_all(void)
733e8feb96fSEmilio G. Cota {
734d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
735e8feb96fSEmilio G. Cota     unsigned int i;
736e8feb96fSEmilio G. Cota 
737e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
738e8feb96fSEmilio G. Cota     region.current = 0;
739e8feb96fSEmilio G. Cota     region.agg_size_full = 0;
740e8feb96fSEmilio G. Cota 
7413468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
742d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
7433468b59eSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(s);
744e8feb96fSEmilio G. Cota 
745e8feb96fSEmilio G. Cota         g_assert(!err);
746e8feb96fSEmilio G. Cota     }
747e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
748be2cdc5eSEmilio G. Cota 
749be2cdc5eSEmilio G. Cota     tcg_region_tree_reset_all();
750e8feb96fSEmilio G. Cota }
751e8feb96fSEmilio G. Cota 
7523468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
7533468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
7543468b59eSEmilio G. Cota {
7553468b59eSEmilio G. Cota     return 1;
7563468b59eSEmilio G. Cota }
7573468b59eSEmilio G. Cota #else
7583468b59eSEmilio G. Cota /*
7593468b59eSEmilio G. Cota  * It is likely that some vCPUs will translate more code than others, so we
7603468b59eSEmilio G. Cota  * first try to set more regions than max_cpus, with those regions being of
7613468b59eSEmilio G. Cota  * reasonable size. If that's not possible we make do by evenly dividing
7623468b59eSEmilio G. Cota  * the code_gen_buffer among the vCPUs.
7633468b59eSEmilio G. Cota  */
7643468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
7653468b59eSEmilio G. Cota {
7663468b59eSEmilio G. Cota     size_t i;
7673468b59eSEmilio G. Cota 
7683468b59eSEmilio G. Cota     /* Use a single region if all we have is one vCPU thread */
7695cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY)
7705cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
7715cc8767dSLike Xu     unsigned int max_cpus = ms->smp.max_cpus;
7725cc8767dSLike Xu #endif
7733468b59eSEmilio G. Cota     if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) {
7743468b59eSEmilio G. Cota         return 1;
7753468b59eSEmilio G. Cota     }
7763468b59eSEmilio G. Cota 
7773468b59eSEmilio G. Cota     /* Try to have more regions than max_cpus, with each region being >= 2 MB */
7783468b59eSEmilio G. Cota     for (i = 8; i > 0; i--) {
7793468b59eSEmilio G. Cota         size_t regions_per_thread = i;
7803468b59eSEmilio G. Cota         size_t region_size;
7813468b59eSEmilio G. Cota 
7823468b59eSEmilio G. Cota         region_size = tcg_init_ctx.code_gen_buffer_size;
7833468b59eSEmilio G. Cota         region_size /= max_cpus * regions_per_thread;
7843468b59eSEmilio G. Cota 
7853468b59eSEmilio G. Cota         if (region_size >= 2 * 1024u * 1024) {
7863468b59eSEmilio G. Cota             return max_cpus * regions_per_thread;
7873468b59eSEmilio G. Cota         }
7883468b59eSEmilio G. Cota     }
7893468b59eSEmilio G. Cota     /* If we can't, then just allocate one region per vCPU thread */
7903468b59eSEmilio G. Cota     return max_cpus;
7913468b59eSEmilio G. Cota }
7923468b59eSEmilio G. Cota #endif
7933468b59eSEmilio G. Cota 
794e8feb96fSEmilio G. Cota /*
795e8feb96fSEmilio G. Cota  * Initializes region partitioning.
796e8feb96fSEmilio G. Cota  *
797e8feb96fSEmilio G. Cota  * Called at init time from the parent thread (i.e. the one calling
798e8feb96fSEmilio G. Cota  * tcg_context_init), after the target's TCG globals have been set.
7993468b59eSEmilio G. Cota  *
8003468b59eSEmilio G. Cota  * Region partitioning works by splitting code_gen_buffer into separate regions,
8013468b59eSEmilio G. Cota  * and then assigning regions to TCG threads so that the threads can translate
8023468b59eSEmilio G. Cota  * code in parallel without synchronization.
8033468b59eSEmilio G. Cota  *
8043468b59eSEmilio G. Cota  * In softmmu the number of TCG threads is bounded by max_cpus, so we use at
8053468b59eSEmilio G. Cota  * least max_cpus regions in MTTCG. In !MTTCG we use a single region.
8063468b59eSEmilio G. Cota  * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...])
8073468b59eSEmilio G. Cota  * must have been parsed before calling this function, since it calls
8083468b59eSEmilio G. Cota  * qemu_tcg_mttcg_enabled().
8093468b59eSEmilio G. Cota  *
8103468b59eSEmilio G. Cota  * In user-mode we use a single region.  Having multiple regions in user-mode
8113468b59eSEmilio G. Cota  * is not supported, because the number of vCPU threads (recall that each thread
8123468b59eSEmilio G. Cota  * spawned by the guest corresponds to a vCPU thread) is only bounded by the
8133468b59eSEmilio G. Cota  * OS, and usually this number is huge (tens of thousands is not uncommon).
8143468b59eSEmilio G. Cota  * Thus, given this large bound on the number of vCPU threads and the fact
8153468b59eSEmilio G. Cota  * that code_gen_buffer is allocated at compile-time, we cannot guarantee
8163468b59eSEmilio G. Cota  * that the availability of at least one region per vCPU thread.
8173468b59eSEmilio G. Cota  *
8183468b59eSEmilio G. Cota  * However, this user-mode limitation is unlikely to be a significant problem
8193468b59eSEmilio G. Cota  * in practice. Multi-threaded guests share most if not all of their translated
8203468b59eSEmilio G. Cota  * code, which makes parallel code generation less appealing than in softmmu.
821e8feb96fSEmilio G. Cota  */
822e8feb96fSEmilio G. Cota void tcg_region_init(void)
823e8feb96fSEmilio G. Cota {
824e8feb96fSEmilio G. Cota     void *buf = tcg_init_ctx.code_gen_buffer;
825e8feb96fSEmilio G. Cota     void *aligned;
826e8feb96fSEmilio G. Cota     size_t size = tcg_init_ctx.code_gen_buffer_size;
827e8feb96fSEmilio G. Cota     size_t page_size = qemu_real_host_page_size;
828e8feb96fSEmilio G. Cota     size_t region_size;
829e8feb96fSEmilio G. Cota     size_t n_regions;
830e8feb96fSEmilio G. Cota     size_t i;
831e8feb96fSEmilio G. Cota 
8323468b59eSEmilio G. Cota     n_regions = tcg_n_regions();
833e8feb96fSEmilio G. Cota 
834e8feb96fSEmilio G. Cota     /* The first region will be 'aligned - buf' bytes larger than the others */
835e8feb96fSEmilio G. Cota     aligned = QEMU_ALIGN_PTR_UP(buf, page_size);
836e8feb96fSEmilio G. Cota     g_assert(aligned < tcg_init_ctx.code_gen_buffer + size);
837e8feb96fSEmilio G. Cota     /*
838e8feb96fSEmilio G. Cota      * Make region_size a multiple of page_size, using aligned as the start.
839e8feb96fSEmilio G. Cota      * As a result of this we might end up with a few extra pages at the end of
840e8feb96fSEmilio G. Cota      * the buffer; we will assign those to the last region.
841e8feb96fSEmilio G. Cota      */
842e8feb96fSEmilio G. Cota     region_size = (size - (aligned - buf)) / n_regions;
843e8feb96fSEmilio G. Cota     region_size = QEMU_ALIGN_DOWN(region_size, page_size);
844e8feb96fSEmilio G. Cota 
845e8feb96fSEmilio G. Cota     /* A region must have at least 2 pages; one code, one guard */
846e8feb96fSEmilio G. Cota     g_assert(region_size >= 2 * page_size);
847e8feb96fSEmilio G. Cota 
848e8feb96fSEmilio G. Cota     /* init the region struct */
849e8feb96fSEmilio G. Cota     qemu_mutex_init(&region.lock);
850e8feb96fSEmilio G. Cota     region.n = n_regions;
851e8feb96fSEmilio G. Cota     region.size = region_size - page_size;
852e8feb96fSEmilio G. Cota     region.stride = region_size;
853e8feb96fSEmilio G. Cota     region.start = buf;
854e8feb96fSEmilio G. Cota     region.start_aligned = aligned;
855e8feb96fSEmilio G. Cota     /* page-align the end, since its last page will be a guard page */
856e8feb96fSEmilio G. Cota     region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size);
857e8feb96fSEmilio G. Cota     /* account for that last guard page */
858e8feb96fSEmilio G. Cota     region.end -= page_size;
859e8feb96fSEmilio G. Cota 
860*15c4e8feSRichard Henderson     /*
861*15c4e8feSRichard Henderson      * Set guard pages in the rw buffer, as that's the one into which
862*15c4e8feSRichard Henderson      * buffer overruns could occur.  Do not set guard pages in the rx
863*15c4e8feSRichard Henderson      * buffer -- let that one use hugepages throughout.
864*15c4e8feSRichard Henderson      */
865e8feb96fSEmilio G. Cota     for (i = 0; i < region.n; i++) {
866e8feb96fSEmilio G. Cota         void *start, *end;
867e8feb96fSEmilio G. Cota         int rc;
868e8feb96fSEmilio G. Cota 
869e8feb96fSEmilio G. Cota         tcg_region_bounds(i, &start, &end);
870e8feb96fSEmilio G. Cota         rc = qemu_mprotect_none(end, page_size);
871e8feb96fSEmilio G. Cota         g_assert(!rc);
872e8feb96fSEmilio G. Cota     }
873e8feb96fSEmilio G. Cota 
874be2cdc5eSEmilio G. Cota     tcg_region_trees_init();
875be2cdc5eSEmilio G. Cota 
8763468b59eSEmilio G. Cota     /* In user-mode we support only one ctx, so do the initial allocation now */
8773468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
878e8feb96fSEmilio G. Cota     {
879e8feb96fSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(tcg_ctx);
880e8feb96fSEmilio G. Cota 
881e8feb96fSEmilio G. Cota         g_assert(!err);
882e8feb96fSEmilio G. Cota     }
8833468b59eSEmilio G. Cota #endif
884e8feb96fSEmilio G. Cota }
885e8feb96fSEmilio G. Cota 
886db0c51a3SRichard Henderson #ifdef CONFIG_DEBUG_TCG
887db0c51a3SRichard Henderson const void *tcg_splitwx_to_rx(void *rw)
888db0c51a3SRichard Henderson {
889db0c51a3SRichard Henderson     /* Pass NULL pointers unchanged. */
890db0c51a3SRichard Henderson     if (rw) {
891db0c51a3SRichard Henderson         g_assert(in_code_gen_buffer(rw));
892db0c51a3SRichard Henderson         rw += tcg_splitwx_diff;
893db0c51a3SRichard Henderson     }
894db0c51a3SRichard Henderson     return rw;
895db0c51a3SRichard Henderson }
896db0c51a3SRichard Henderson 
897db0c51a3SRichard Henderson void *tcg_splitwx_to_rw(const void *rx)
898db0c51a3SRichard Henderson {
899db0c51a3SRichard Henderson     /* Pass NULL pointers unchanged. */
900db0c51a3SRichard Henderson     if (rx) {
901db0c51a3SRichard Henderson         rx -= tcg_splitwx_diff;
902db0c51a3SRichard Henderson         /* Assert that we end with a pointer in the rw region. */
903db0c51a3SRichard Henderson         g_assert(in_code_gen_buffer(rx));
904db0c51a3SRichard Henderson     }
905db0c51a3SRichard Henderson     return (void *)rx;
906db0c51a3SRichard Henderson }
907db0c51a3SRichard Henderson #endif /* CONFIG_DEBUG_TCG */
908db0c51a3SRichard Henderson 
90938b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s)
91038b47b19SEmilio G. Cota {
91138b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
91238b47b19SEmilio G. Cota     s->plugin_tb = g_new0(struct qemu_plugin_tb, 1);
91338b47b19SEmilio G. Cota     s->plugin_tb->insns =
91438b47b19SEmilio G. Cota         g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn);
91538b47b19SEmilio G. Cota #endif
91638b47b19SEmilio G. Cota }
91738b47b19SEmilio G. Cota 
918e8feb96fSEmilio G. Cota /*
9193468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
9203468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
9213468b59eSEmilio G. Cota  * before initiating translation.
9223468b59eSEmilio G. Cota  *
9233468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
9243468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
9253468b59eSEmilio G. Cota  *
9263468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
9273468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
9283468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
9293468b59eSEmilio G. Cota  *
9303468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
9313468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
9323468b59eSEmilio G. Cota  */
9333468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
9343468b59eSEmilio G. Cota void tcg_register_thread(void)
9353468b59eSEmilio G. Cota {
9363468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
9373468b59eSEmilio G. Cota }
9383468b59eSEmilio G. Cota #else
9393468b59eSEmilio G. Cota void tcg_register_thread(void)
9403468b59eSEmilio G. Cota {
9415cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
9423468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
9433468b59eSEmilio G. Cota     unsigned int i, n;
9443468b59eSEmilio G. Cota     bool err;
9453468b59eSEmilio G. Cota 
9463468b59eSEmilio G. Cota     *s = tcg_init_ctx;
9473468b59eSEmilio G. Cota 
9483468b59eSEmilio G. Cota     /* Relink mem_base.  */
9493468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
9503468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
9513468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
9523468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
9533468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
9543468b59eSEmilio G. Cota         }
9553468b59eSEmilio G. Cota     }
9563468b59eSEmilio G. Cota 
9573468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
958d73415a3SStefan Hajnoczi     n = qatomic_fetch_inc(&n_tcg_ctxs);
9595cc8767dSLike Xu     g_assert(n < ms->smp.max_cpus);
960d73415a3SStefan Hajnoczi     qatomic_set(&tcg_ctxs[n], s);
9613468b59eSEmilio G. Cota 
96238b47b19SEmilio G. Cota     if (n > 0) {
96338b47b19SEmilio G. Cota         alloc_tcg_plugin_context(s);
96438b47b19SEmilio G. Cota     }
96538b47b19SEmilio G. Cota 
9663468b59eSEmilio G. Cota     tcg_ctx = s;
9673468b59eSEmilio G. Cota     qemu_mutex_lock(&region.lock);
9683468b59eSEmilio G. Cota     err = tcg_region_initial_alloc__locked(tcg_ctx);
9693468b59eSEmilio G. Cota     g_assert(!err);
9703468b59eSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
9713468b59eSEmilio G. Cota }
9723468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
9733468b59eSEmilio G. Cota 
9743468b59eSEmilio G. Cota /*
975e8feb96fSEmilio G. Cota  * Returns the size (in bytes) of all translated code (i.e. from all regions)
976e8feb96fSEmilio G. Cota  * currently in the cache.
977e8feb96fSEmilio G. Cota  * See also: tcg_code_capacity()
978e8feb96fSEmilio G. Cota  * Do not confuse with tcg_current_code_size(); that one applies to a single
979e8feb96fSEmilio G. Cota  * TCG context.
980e8feb96fSEmilio G. Cota  */
981e8feb96fSEmilio G. Cota size_t tcg_code_size(void)
982e8feb96fSEmilio G. Cota {
983d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
984e8feb96fSEmilio G. Cota     unsigned int i;
985e8feb96fSEmilio G. Cota     size_t total;
986e8feb96fSEmilio G. Cota 
987e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
988e8feb96fSEmilio G. Cota     total = region.agg_size_full;
9893468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
990d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
991e8feb96fSEmilio G. Cota         size_t size;
992e8feb96fSEmilio G. Cota 
993d73415a3SStefan Hajnoczi         size = qatomic_read(&s->code_gen_ptr) - s->code_gen_buffer;
994e8feb96fSEmilio G. Cota         g_assert(size <= s->code_gen_buffer_size);
995e8feb96fSEmilio G. Cota         total += size;
996e8feb96fSEmilio G. Cota     }
997e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
998e8feb96fSEmilio G. Cota     return total;
999e8feb96fSEmilio G. Cota }
1000e8feb96fSEmilio G. Cota 
1001e8feb96fSEmilio G. Cota /*
1002e8feb96fSEmilio G. Cota  * Returns the code capacity (in bytes) of the entire cache, i.e. including all
1003e8feb96fSEmilio G. Cota  * regions.
1004e8feb96fSEmilio G. Cota  * See also: tcg_code_size()
1005e8feb96fSEmilio G. Cota  */
1006e8feb96fSEmilio G. Cota size_t tcg_code_capacity(void)
1007e8feb96fSEmilio G. Cota {
1008e8feb96fSEmilio G. Cota     size_t guard_size, capacity;
1009e8feb96fSEmilio G. Cota 
1010e8feb96fSEmilio G. Cota     /* no need for synchronization; these variables are set at init time */
1011e8feb96fSEmilio G. Cota     guard_size = region.stride - region.size;
1012e8feb96fSEmilio G. Cota     capacity = region.end + guard_size - region.start;
1013e8feb96fSEmilio G. Cota     capacity -= region.n * (guard_size + TCG_HIGHWATER);
1014e8feb96fSEmilio G. Cota     return capacity;
1015e8feb96fSEmilio G. Cota }
1016e8feb96fSEmilio G. Cota 
1017128ed227SEmilio G. Cota size_t tcg_tb_phys_invalidate_count(void)
1018128ed227SEmilio G. Cota {
1019d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
1020128ed227SEmilio G. Cota     unsigned int i;
1021128ed227SEmilio G. Cota     size_t total = 0;
1022128ed227SEmilio G. Cota 
1023128ed227SEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
1024d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
1025128ed227SEmilio G. Cota 
1026d73415a3SStefan Hajnoczi         total += qatomic_read(&s->tb_phys_invalidate_count);
1027128ed227SEmilio G. Cota     }
1028128ed227SEmilio G. Cota     return total;
1029128ed227SEmilio G. Cota }
1030128ed227SEmilio G. Cota 
1031c896fe29Sbellard /* pool based memory allocation */
1032c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
1033c896fe29Sbellard {
1034c896fe29Sbellard     TCGPool *p;
1035c896fe29Sbellard     int pool_size;
1036c896fe29Sbellard 
1037c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
1038c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
10397267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
1040c896fe29Sbellard         p->size = size;
10414055299eSKirill Batuzov         p->next = s->pool_first_large;
10424055299eSKirill Batuzov         s->pool_first_large = p;
10434055299eSKirill Batuzov         return p->data;
1044c896fe29Sbellard     } else {
1045c896fe29Sbellard         p = s->pool_current;
1046c896fe29Sbellard         if (!p) {
1047c896fe29Sbellard             p = s->pool_first;
1048c896fe29Sbellard             if (!p)
1049c896fe29Sbellard                 goto new_pool;
1050c896fe29Sbellard         } else {
1051c896fe29Sbellard             if (!p->next) {
1052c896fe29Sbellard             new_pool:
1053c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
10547267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
1055c896fe29Sbellard                 p->size = pool_size;
1056c896fe29Sbellard                 p->next = NULL;
1057c896fe29Sbellard                 if (s->pool_current)
1058c896fe29Sbellard                     s->pool_current->next = p;
1059c896fe29Sbellard                 else
1060c896fe29Sbellard                     s->pool_first = p;
1061c896fe29Sbellard             } else {
1062c896fe29Sbellard                 p = p->next;
1063c896fe29Sbellard             }
1064c896fe29Sbellard         }
1065c896fe29Sbellard     }
1066c896fe29Sbellard     s->pool_current = p;
1067c896fe29Sbellard     s->pool_cur = p->data + size;
1068c896fe29Sbellard     s->pool_end = p->data + p->size;
1069c896fe29Sbellard     return p->data;
1070c896fe29Sbellard }
1071c896fe29Sbellard 
1072c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
1073c896fe29Sbellard {
10744055299eSKirill Batuzov     TCGPool *p, *t;
10754055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
10764055299eSKirill Batuzov         t = p->next;
10774055299eSKirill Batuzov         g_free(p);
10784055299eSKirill Batuzov     }
10794055299eSKirill Batuzov     s->pool_first_large = NULL;
1080c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
1081c896fe29Sbellard     s->pool_current = NULL;
1082c896fe29Sbellard }
1083c896fe29Sbellard 
1084100b5e01SRichard Henderson typedef struct TCGHelperInfo {
1085100b5e01SRichard Henderson     void *func;
1086100b5e01SRichard Henderson     const char *name;
1087afb49896SRichard Henderson     unsigned flags;
1088afb49896SRichard Henderson     unsigned sizemask;
1089100b5e01SRichard Henderson } TCGHelperInfo;
1090100b5e01SRichard Henderson 
10912ef6175aSRichard Henderson #include "exec/helper-proto.h"
10922ef6175aSRichard Henderson 
1093100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = {
10942ef6175aSRichard Henderson #include "exec/helper-tcg.h"
1095100b5e01SRichard Henderson };
1096619205fdSEmilio G. Cota static GHashTable *helper_table;
1097100b5e01SRichard Henderson 
109891478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
1099f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
11001c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
11011c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
110291478cefSRichard Henderson 
1103c896fe29Sbellard void tcg_context_init(TCGContext *s)
1104c896fe29Sbellard {
1105100b5e01SRichard Henderson     int op, total_args, n, i;
1106c896fe29Sbellard     TCGOpDef *def;
1107c896fe29Sbellard     TCGArgConstraint *args_ct;
11081c2adb95SRichard Henderson     TCGTemp *ts;
1109c896fe29Sbellard 
1110c896fe29Sbellard     memset(s, 0, sizeof(*s));
1111c896fe29Sbellard     s->nb_globals = 0;
1112c896fe29Sbellard 
1113c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
1114c896fe29Sbellard        space */
1115c896fe29Sbellard     total_args = 0;
1116c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
1117c896fe29Sbellard         def = &tcg_op_defs[op];
1118c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
1119c896fe29Sbellard         total_args += n;
1120c896fe29Sbellard     }
1121c896fe29Sbellard 
1122bc2b17e6SRichard Henderson     args_ct = g_new0(TCGArgConstraint, total_args);
1123c896fe29Sbellard 
1124c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
1125c896fe29Sbellard         def = &tcg_op_defs[op];
1126c896fe29Sbellard         def->args_ct = args_ct;
1127c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
1128c896fe29Sbellard         args_ct += n;
1129c896fe29Sbellard     }
1130c896fe29Sbellard 
11315cd8f621SRichard Henderson     /* Register helpers.  */
113284fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
1133619205fdSEmilio G. Cota     helper_table = g_hash_table_new(NULL, NULL);
113484fd9dd3SRichard Henderson 
1135100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
113684fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
113772866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
1138100b5e01SRichard Henderson     }
11395cd8f621SRichard Henderson 
1140c896fe29Sbellard     tcg_target_init(s);
1141f69d277eSRichard Henderson     process_op_defs(s);
114291478cefSRichard Henderson 
114391478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
114491478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
114591478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
114691478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
114791478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
114891478cefSRichard Henderson             break;
114991478cefSRichard Henderson         }
115091478cefSRichard Henderson     }
115191478cefSRichard Henderson     for (i = 0; i < n; ++i) {
115291478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
115391478cefSRichard Henderson     }
115491478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
115591478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
115691478cefSRichard Henderson     }
1157b1311c4aSEmilio G. Cota 
115838b47b19SEmilio G. Cota     alloc_tcg_plugin_context(s);
115938b47b19SEmilio G. Cota 
1160b1311c4aSEmilio G. Cota     tcg_ctx = s;
11613468b59eSEmilio G. Cota     /*
11623468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
11633468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
11643468b59eSEmilio G. Cota      * reasoning behind this.
11653468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
11663468b59eSEmilio G. Cota      */
11673468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
1168df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
1169df2cce29SEmilio G. Cota     n_tcg_ctxs = 1;
11703468b59eSEmilio G. Cota #else
11715cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
11725cc8767dSLike Xu     unsigned int max_cpus = ms->smp.max_cpus;
11733468b59eSEmilio G. Cota     tcg_ctxs = g_new(TCGContext *, max_cpus);
11743468b59eSEmilio G. Cota #endif
11751c2adb95SRichard Henderson 
11761c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
11771c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
11781c2adb95SRichard Henderson     cpu_env = temp_tcgv_ptr(ts);
11799002ec79SRichard Henderson }
1180b03cce8eSbellard 
11816e3b2bfdSEmilio G. Cota /*
11826e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
11836e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
11846e3b2bfdSEmilio G. Cota  */
11856e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
11866e3b2bfdSEmilio G. Cota {
11876e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
11886e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
11896e3b2bfdSEmilio G. Cota     void *next;
11906e3b2bfdSEmilio G. Cota 
1191e8feb96fSEmilio G. Cota  retry:
11926e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
11936e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
11946e3b2bfdSEmilio G. Cota 
11956e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
1196e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
11976e3b2bfdSEmilio G. Cota             return NULL;
11986e3b2bfdSEmilio G. Cota         }
1199e8feb96fSEmilio G. Cota         goto retry;
1200e8feb96fSEmilio G. Cota     }
1201d73415a3SStefan Hajnoczi     qatomic_set(&s->code_gen_ptr, next);
120257a26946SRichard Henderson     s->data_gen_ptr = NULL;
12036e3b2bfdSEmilio G. Cota     return tb;
12046e3b2bfdSEmilio G. Cota }
12056e3b2bfdSEmilio G. Cota 
12069002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
12079002ec79SRichard Henderson {
12088163b749SRichard Henderson     size_t prologue_size, total_size;
12098163b749SRichard Henderson     void *buf0, *buf1;
12108163b749SRichard Henderson 
12118163b749SRichard Henderson     /* Put the prologue at the beginning of code_gen_buffer.  */
12128163b749SRichard Henderson     buf0 = s->code_gen_buffer;
12135b38ee31SRichard Henderson     total_size = s->code_gen_buffer_size;
12148163b749SRichard Henderson     s->code_ptr = buf0;
12158163b749SRichard Henderson     s->code_buf = buf0;
12165b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
1217b91ccb31SRichard Henderson 
1218db0c51a3SRichard Henderson     /*
1219db0c51a3SRichard Henderson      * The region trees are not yet configured, but tcg_splitwx_to_rx
1220db0c51a3SRichard Henderson      * needs the bounds for an assert.
1221db0c51a3SRichard Henderson      */
1222db0c51a3SRichard Henderson     region.start = buf0;
1223db0c51a3SRichard Henderson     region.end = buf0 + total_size;
1224db0c51a3SRichard Henderson 
1225b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1226db0c51a3SRichard Henderson     tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(buf0);
1227b91ccb31SRichard Henderson #endif
12288163b749SRichard Henderson 
12295b38ee31SRichard Henderson     /* Compute a high-water mark, at which we voluntarily flush the buffer
12305b38ee31SRichard Henderson        and start over.  The size here is arbitrary, significantly larger
12315b38ee31SRichard Henderson        than we expect the code generation for any one opcode to require.  */
12325b38ee31SRichard Henderson     s->code_gen_highwater = s->code_gen_buffer + (total_size - TCG_HIGHWATER);
12335b38ee31SRichard Henderson 
12345b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
12355b38ee31SRichard Henderson     s->pool_labels = NULL;
12365b38ee31SRichard Henderson #endif
12375b38ee31SRichard Henderson 
1238653b87ebSRoman Bolshakov     qemu_thread_jit_write();
12398163b749SRichard Henderson     /* Generate the prologue.  */
1240b03cce8eSbellard     tcg_target_qemu_prologue(s);
12415b38ee31SRichard Henderson 
12425b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
12435b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
12445b38ee31SRichard Henderson     {
12451768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
12461768987bSRichard Henderson         tcg_debug_assert(result == 0);
12475b38ee31SRichard Henderson     }
12485b38ee31SRichard Henderson #endif
12495b38ee31SRichard Henderson 
12508163b749SRichard Henderson     buf1 = s->code_ptr;
1251df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1252db0c51a3SRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(buf0), (uintptr_t)buf0,
12531da8de39SRichard Henderson                         tcg_ptr_byte_diff(buf1, buf0));
1254df5d2b16SRichard Henderson #endif
12558163b749SRichard Henderson 
12568163b749SRichard Henderson     /* Deduct the prologue from the buffer.  */
12578163b749SRichard Henderson     prologue_size = tcg_current_code_size(s);
12588163b749SRichard Henderson     s->code_gen_ptr = buf1;
12598163b749SRichard Henderson     s->code_gen_buffer = buf1;
12608163b749SRichard Henderson     s->code_buf = buf1;
12615b38ee31SRichard Henderson     total_size -= prologue_size;
12628163b749SRichard Henderson     s->code_gen_buffer_size = total_size;
12638163b749SRichard Henderson 
1264755bf9e5SRichard Henderson     tcg_register_jit(tcg_splitwx_to_rx(s->code_gen_buffer), total_size);
1265d6b64b2bSRichard Henderson 
1266d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
1267d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
1268fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
12698163b749SRichard Henderson         qemu_log("PROLOGUE: [size=%zu]\n", prologue_size);
12705b38ee31SRichard Henderson         if (s->data_gen_ptr) {
12715b38ee31SRichard Henderson             size_t code_size = s->data_gen_ptr - buf0;
12725b38ee31SRichard Henderson             size_t data_size = prologue_size - code_size;
12735b38ee31SRichard Henderson             size_t i;
12745b38ee31SRichard Henderson 
12754c389f6eSRichard Henderson             log_disas(buf0, code_size);
12765b38ee31SRichard Henderson 
12775b38ee31SRichard Henderson             for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
12785b38ee31SRichard Henderson                 if (sizeof(tcg_target_ulong) == 8) {
12795b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
12805b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
12815b38ee31SRichard Henderson                              *(uint64_t *)(s->data_gen_ptr + i));
12825b38ee31SRichard Henderson                 } else {
12835b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .long  0x%08x\n",
12845b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
12855b38ee31SRichard Henderson                              *(uint32_t *)(s->data_gen_ptr + i));
12865b38ee31SRichard Henderson                 }
12875b38ee31SRichard Henderson             }
12885b38ee31SRichard Henderson         } else {
12894c389f6eSRichard Henderson             log_disas(buf0, prologue_size);
12905b38ee31SRichard Henderson         }
1291d6b64b2bSRichard Henderson         qemu_log("\n");
1292d6b64b2bSRichard Henderson         qemu_log_flush();
1293fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
1294d6b64b2bSRichard Henderson     }
1295d6b64b2bSRichard Henderson #endif
1296cedbcb01SEmilio G. Cota 
1297cedbcb01SEmilio G. Cota     /* Assert that goto_ptr is implemented completely.  */
1298cedbcb01SEmilio G. Cota     if (TCG_TARGET_HAS_goto_ptr) {
12998b5c2b62SRichard Henderson         tcg_debug_assert(tcg_code_gen_epilogue != NULL);
1300cedbcb01SEmilio G. Cota     }
1301c896fe29Sbellard }
1302c896fe29Sbellard 
1303c896fe29Sbellard void tcg_func_start(TCGContext *s)
1304c896fe29Sbellard {
1305c896fe29Sbellard     tcg_pool_reset(s);
1306c896fe29Sbellard     s->nb_temps = s->nb_globals;
13070ec9eabcSRichard Henderson 
13080ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
13090ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
13100ec9eabcSRichard Henderson 
1311c0522136SRichard Henderson     /* No constant temps have been previously allocated. */
1312c0522136SRichard Henderson     for (int i = 0; i < TCG_TYPE_COUNT; ++i) {
1313c0522136SRichard Henderson         if (s->const_table[i]) {
1314c0522136SRichard Henderson             g_hash_table_remove_all(s->const_table[i]);
1315c0522136SRichard Henderson         }
1316c0522136SRichard Henderson     }
1317c0522136SRichard Henderson 
1318abebf925SRichard Henderson     s->nb_ops = 0;
1319c896fe29Sbellard     s->nb_labels = 0;
1320c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1321c896fe29Sbellard 
13220a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
13230a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
13240a209d4bSRichard Henderson #endif
13250a209d4bSRichard Henderson 
132615fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
132715fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
1328bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
1329c896fe29Sbellard }
1330c896fe29Sbellard 
1331ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s)
13327ca4b752SRichard Henderson {
13337ca4b752SRichard Henderson     int n = s->nb_temps++;
1334ae30e866SRichard Henderson 
1335ae30e866SRichard Henderson     if (n >= TCG_MAX_TEMPS) {
1336db6b7d0cSRichard Henderson         tcg_raise_tb_overflow(s);
1337ae30e866SRichard Henderson     }
13387ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
13397ca4b752SRichard Henderson }
13407ca4b752SRichard Henderson 
1341ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s)
13427ca4b752SRichard Henderson {
1343fa477d25SRichard Henderson     TCGTemp *ts;
1344fa477d25SRichard Henderson 
13457ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
1346ae30e866SRichard Henderson     tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS);
13477ca4b752SRichard Henderson     s->nb_globals++;
1348fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1349ee17db83SRichard Henderson     ts->kind = TEMP_GLOBAL;
1350fa477d25SRichard Henderson 
1351fa477d25SRichard Henderson     return ts;
1352c896fe29Sbellard }
1353c896fe29Sbellard 
1354085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1355b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1356c896fe29Sbellard {
1357c896fe29Sbellard     TCGTemp *ts;
1358c896fe29Sbellard 
1359b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
1360c896fe29Sbellard         tcg_abort();
1361b3a62939SRichard Henderson     }
13627ca4b752SRichard Henderson 
13637ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1364c896fe29Sbellard     ts->base_type = type;
1365c896fe29Sbellard     ts->type = type;
1366ee17db83SRichard Henderson     ts->kind = TEMP_FIXED;
1367c896fe29Sbellard     ts->reg = reg;
1368c896fe29Sbellard     ts->name = name;
1369c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
13707ca4b752SRichard Henderson 
1371085272b3SRichard Henderson     return ts;
1372a7812ae4Spbrook }
1373a7812ae4Spbrook 
1374b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1375a7812ae4Spbrook {
1376b3a62939SRichard Henderson     s->frame_start = start;
1377b3a62939SRichard Henderson     s->frame_end = start + size;
1378085272b3SRichard Henderson     s->frame_temp
1379085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1380b3a62939SRichard Henderson }
1381a7812ae4Spbrook 
1382085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
1383e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
1384c896fe29Sbellard {
1385b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1386dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
13877ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1388b3915dbbSRichard Henderson     int indirect_reg = 0, bigendian = 0;
13897ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
13907ca4b752SRichard Henderson     bigendian = 1;
13917ca4b752SRichard Henderson #endif
1392c896fe29Sbellard 
1393c0522136SRichard Henderson     switch (base_ts->kind) {
1394c0522136SRichard Henderson     case TEMP_FIXED:
1395c0522136SRichard Henderson         break;
1396c0522136SRichard Henderson     case TEMP_GLOBAL:
13975a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
13985a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1399b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
14005a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
14015a18407fSRichard Henderson                             ? 2 : 1);
14025a18407fSRichard Henderson         indirect_reg = 1;
1403c0522136SRichard Henderson         break;
1404c0522136SRichard Henderson     default:
1405c0522136SRichard Henderson         g_assert_not_reached();
1406b3915dbbSRichard Henderson     }
1407b3915dbbSRichard Henderson 
14087ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
14097ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1410c896fe29Sbellard         char buf[64];
14117ca4b752SRichard Henderson 
14127ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1413c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1414b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1415c896fe29Sbellard         ts->mem_allocated = 1;
1416b3a62939SRichard Henderson         ts->mem_base = base_ts;
14177ca4b752SRichard Henderson         ts->mem_offset = offset + bigendian * 4;
1418c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1419c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1420c896fe29Sbellard         ts->name = strdup(buf);
1421c896fe29Sbellard 
14227ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
14237ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
14247ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1425b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
14267ca4b752SRichard Henderson         ts2->mem_allocated = 1;
14277ca4b752SRichard Henderson         ts2->mem_base = base_ts;
14287ca4b752SRichard Henderson         ts2->mem_offset = offset + (1 - bigendian) * 4;
1429c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1430c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1431120c1084SRichard Henderson         ts2->name = strdup(buf);
14327ca4b752SRichard Henderson     } else {
1433c896fe29Sbellard         ts->base_type = type;
1434c896fe29Sbellard         ts->type = type;
1435b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1436c896fe29Sbellard         ts->mem_allocated = 1;
1437b3a62939SRichard Henderson         ts->mem_base = base_ts;
1438c896fe29Sbellard         ts->mem_offset = offset;
1439c896fe29Sbellard         ts->name = name;
1440c896fe29Sbellard     }
1441085272b3SRichard Henderson     return ts;
1442c896fe29Sbellard }
1443c896fe29Sbellard 
14445bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local)
1445c896fe29Sbellard {
1446b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1447ee17db83SRichard Henderson     TCGTempKind kind = temp_local ? TEMP_LOCAL : TEMP_NORMAL;
1448c896fe29Sbellard     TCGTemp *ts;
1449641d5fbeSbellard     int idx, k;
1450c896fe29Sbellard 
14510ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
14520ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
14530ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
14540ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
14550ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
14560ec9eabcSRichard Henderson 
1457e8996ee0Sbellard         ts = &s->temps[idx];
1458e8996ee0Sbellard         ts->temp_allocated = 1;
14597ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
1460ee17db83SRichard Henderson         tcg_debug_assert(ts->kind == kind);
1461e8996ee0Sbellard     } else {
14627ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
14637ca4b752SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
14647ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
14657ca4b752SRichard Henderson 
1466c896fe29Sbellard             ts->base_type = type;
1467c896fe29Sbellard             ts->type = TCG_TYPE_I32;
1468e8996ee0Sbellard             ts->temp_allocated = 1;
1469ee17db83SRichard Henderson             ts->kind = kind;
14707ca4b752SRichard Henderson 
14717ca4b752SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
14727ca4b752SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
14737ca4b752SRichard Henderson             ts2->type = TCG_TYPE_I32;
14747ca4b752SRichard Henderson             ts2->temp_allocated = 1;
1475ee17db83SRichard Henderson             ts2->kind = kind;
14767ca4b752SRichard Henderson         } else {
1477c896fe29Sbellard             ts->base_type = type;
1478c896fe29Sbellard             ts->type = type;
1479e8996ee0Sbellard             ts->temp_allocated = 1;
1480ee17db83SRichard Henderson             ts->kind = kind;
1481c896fe29Sbellard         }
1482e8996ee0Sbellard     }
148327bfd83cSPeter Maydell 
148427bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
148527bfd83cSPeter Maydell     s->temps_in_use++;
148627bfd83cSPeter Maydell #endif
1487085272b3SRichard Henderson     return ts;
1488c896fe29Sbellard }
1489c896fe29Sbellard 
1490d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1491d2fd745fSRichard Henderson {
1492d2fd745fSRichard Henderson     TCGTemp *t;
1493d2fd745fSRichard Henderson 
1494d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1495d2fd745fSRichard Henderson     switch (type) {
1496d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1497d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1498d2fd745fSRichard Henderson         break;
1499d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1500d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1501d2fd745fSRichard Henderson         break;
1502d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1503d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1504d2fd745fSRichard Henderson         break;
1505d2fd745fSRichard Henderson     default:
1506d2fd745fSRichard Henderson         g_assert_not_reached();
1507d2fd745fSRichard Henderson     }
1508d2fd745fSRichard Henderson #endif
1509d2fd745fSRichard Henderson 
1510d2fd745fSRichard Henderson     t = tcg_temp_new_internal(type, 0);
1511d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1512d2fd745fSRichard Henderson }
1513d2fd745fSRichard Henderson 
1514d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1515d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1516d2fd745fSRichard Henderson {
1517d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1518d2fd745fSRichard Henderson 
1519d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1520d2fd745fSRichard Henderson 
1521d2fd745fSRichard Henderson     t = tcg_temp_new_internal(t->base_type, 0);
1522d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1523d2fd745fSRichard Henderson }
1524d2fd745fSRichard Henderson 
15255bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1526c896fe29Sbellard {
1527b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1528085272b3SRichard Henderson     int k, idx;
1529c896fe29Sbellard 
1530c0522136SRichard Henderson     /* In order to simplify users of tcg_constant_*, silently ignore free. */
1531c0522136SRichard Henderson     if (ts->kind == TEMP_CONST) {
1532c0522136SRichard Henderson         return;
1533c0522136SRichard Henderson     }
1534c0522136SRichard Henderson 
153527bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
153627bfd83cSPeter Maydell     s->temps_in_use--;
153727bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
153827bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
153927bfd83cSPeter Maydell     }
154027bfd83cSPeter Maydell #endif
154127bfd83cSPeter Maydell 
1542ee17db83SRichard Henderson     tcg_debug_assert(ts->kind < TEMP_GLOBAL);
1543eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
1544e8996ee0Sbellard     ts->temp_allocated = 0;
15450ec9eabcSRichard Henderson 
1546085272b3SRichard Henderson     idx = temp_idx(ts);
1547ee17db83SRichard Henderson     k = ts->base_type + (ts->kind == TEMP_NORMAL ? 0 : TCG_TYPE_COUNT);
15480ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
1549e8996ee0Sbellard }
1550e8996ee0Sbellard 
1551c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val)
1552c0522136SRichard Henderson {
1553c0522136SRichard Henderson     TCGContext *s = tcg_ctx;
1554c0522136SRichard Henderson     GHashTable *h = s->const_table[type];
1555c0522136SRichard Henderson     TCGTemp *ts;
1556c0522136SRichard Henderson 
1557c0522136SRichard Henderson     if (h == NULL) {
1558c0522136SRichard Henderson         h = g_hash_table_new(g_int64_hash, g_int64_equal);
1559c0522136SRichard Henderson         s->const_table[type] = h;
1560c0522136SRichard Henderson     }
1561c0522136SRichard Henderson 
1562c0522136SRichard Henderson     ts = g_hash_table_lookup(h, &val);
1563c0522136SRichard Henderson     if (ts == NULL) {
1564c0522136SRichard Henderson         ts = tcg_temp_alloc(s);
1565c0522136SRichard Henderson 
1566c0522136SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
1567c0522136SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
1568c0522136SRichard Henderson 
1569c0522136SRichard Henderson             ts->base_type = TCG_TYPE_I64;
1570c0522136SRichard Henderson             ts->type = TCG_TYPE_I32;
1571c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1572c0522136SRichard Henderson             ts->temp_allocated = 1;
1573c0522136SRichard Henderson             /*
1574c0522136SRichard Henderson              * Retain the full value of the 64-bit constant in the low
1575c0522136SRichard Henderson              * part, so that the hash table works.  Actual uses will
1576c0522136SRichard Henderson              * truncate the value to the low part.
1577c0522136SRichard Henderson              */
1578c0522136SRichard Henderson             ts->val = val;
1579c0522136SRichard Henderson 
1580c0522136SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
1581c0522136SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
1582c0522136SRichard Henderson             ts2->type = TCG_TYPE_I32;
1583c0522136SRichard Henderson             ts2->kind = TEMP_CONST;
1584c0522136SRichard Henderson             ts2->temp_allocated = 1;
1585c0522136SRichard Henderson             ts2->val = val >> 32;
1586c0522136SRichard Henderson         } else {
1587c0522136SRichard Henderson             ts->base_type = type;
1588c0522136SRichard Henderson             ts->type = type;
1589c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1590c0522136SRichard Henderson             ts->temp_allocated = 1;
1591c0522136SRichard Henderson             ts->val = val;
1592c0522136SRichard Henderson         }
1593c0522136SRichard Henderson         g_hash_table_insert(h, &ts->val, ts);
1594c0522136SRichard Henderson     }
1595c0522136SRichard Henderson 
1596c0522136SRichard Henderson     return ts;
1597c0522136SRichard Henderson }
1598c0522136SRichard Henderson 
1599c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val)
1600c0522136SRichard Henderson {
1601c0522136SRichard Henderson     val = dup_const(vece, val);
1602c0522136SRichard Henderson     return temp_tcgv_vec(tcg_constant_internal(type, val));
1603c0522136SRichard Henderson }
1604c0522136SRichard Henderson 
160588d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val)
160688d4005bSRichard Henderson {
160788d4005bSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
160888d4005bSRichard Henderson 
160988d4005bSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
161088d4005bSRichard Henderson     return tcg_constant_vec(t->base_type, vece, val);
161188d4005bSRichard Henderson }
161288d4005bSRichard Henderson 
1613a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
1614a7812ae4Spbrook {
1615a7812ae4Spbrook     TCGv_i32 t0;
1616a7812ae4Spbrook     t0 = tcg_temp_new_i32();
1617e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
1618e8996ee0Sbellard     return t0;
1619c896fe29Sbellard }
1620c896fe29Sbellard 
1621a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
1622c896fe29Sbellard {
1623a7812ae4Spbrook     TCGv_i64 t0;
1624a7812ae4Spbrook     t0 = tcg_temp_new_i64();
1625e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
1626e8996ee0Sbellard     return t0;
1627c896fe29Sbellard }
1628c896fe29Sbellard 
1629a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
1630bdffd4a9Saurel32 {
1631a7812ae4Spbrook     TCGv_i32 t0;
1632a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
1633bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
1634bdffd4a9Saurel32     return t0;
1635bdffd4a9Saurel32 }
1636bdffd4a9Saurel32 
1637a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
1638bdffd4a9Saurel32 {
1639a7812ae4Spbrook     TCGv_i64 t0;
1640a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
1641bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
1642bdffd4a9Saurel32     return t0;
1643bdffd4a9Saurel32 }
1644bdffd4a9Saurel32 
164527bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
164627bfd83cSPeter Maydell void tcg_clear_temp_count(void)
164727bfd83cSPeter Maydell {
1648b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
164927bfd83cSPeter Maydell     s->temps_in_use = 0;
165027bfd83cSPeter Maydell }
165127bfd83cSPeter Maydell 
165227bfd83cSPeter Maydell int tcg_check_temp_count(void)
165327bfd83cSPeter Maydell {
1654b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
165527bfd83cSPeter Maydell     if (s->temps_in_use) {
165627bfd83cSPeter Maydell         /* Clear the count so that we don't give another
165727bfd83cSPeter Maydell          * warning immediately next time around.
165827bfd83cSPeter Maydell          */
165927bfd83cSPeter Maydell         s->temps_in_use = 0;
166027bfd83cSPeter Maydell         return 1;
166127bfd83cSPeter Maydell     }
166227bfd83cSPeter Maydell     return 0;
166327bfd83cSPeter Maydell }
166427bfd83cSPeter Maydell #endif
166527bfd83cSPeter Maydell 
1666be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1667be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1668be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1669be0f34b5SRichard Henderson {
1670d2fd745fSRichard Henderson     const bool have_vec
1671d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1672d2fd745fSRichard Henderson 
1673be0f34b5SRichard Henderson     switch (op) {
1674be0f34b5SRichard Henderson     case INDEX_op_discard:
1675be0f34b5SRichard Henderson     case INDEX_op_set_label:
1676be0f34b5SRichard Henderson     case INDEX_op_call:
1677be0f34b5SRichard Henderson     case INDEX_op_br:
1678be0f34b5SRichard Henderson     case INDEX_op_mb:
1679be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1680be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1681be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1682be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i32:
1683be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i32:
1684be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i64:
1685be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i64:
1686be0f34b5SRichard Henderson         return true;
1687be0f34b5SRichard Henderson 
168807ce0b05SRichard Henderson     case INDEX_op_qemu_st8_i32:
168907ce0b05SRichard Henderson         return TCG_TARGET_HAS_qemu_st8_i32;
169007ce0b05SRichard Henderson 
1691be0f34b5SRichard Henderson     case INDEX_op_goto_ptr:
1692be0f34b5SRichard Henderson         return TCG_TARGET_HAS_goto_ptr;
1693be0f34b5SRichard Henderson 
1694be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1695be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1696be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1697be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1698be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1699be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1700be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1701be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1702be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1703be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1704be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1705be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1706be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1707be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1708be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1709be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1710be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1711be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1712be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1713be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1714be0f34b5SRichard Henderson         return true;
1715be0f34b5SRichard Henderson 
1716be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1717be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1718be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1719be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1720be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1721be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1722be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1723be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1724be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1725be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1726be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1727be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1728be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1729be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1730be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1731be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1732be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1733be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1734be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1735be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1736fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
1737fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
1738be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1739be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1740be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1741be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1742be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1743be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1744be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1745be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1746be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1747be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1748be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1749be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1750be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1751be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1752be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1753be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1754be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1755be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1756be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1757be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1758be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1759be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1760be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1761be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1762be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1763be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1764be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1765be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1766be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1767be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1768be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1769be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1770be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1771be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1772be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1773be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1774be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1775be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1776be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1777be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1778be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1779be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1780be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1781be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1782be0f34b5SRichard Henderson 
1783be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1784be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1785be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1786be0f34b5SRichard Henderson 
1787be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1788be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1789be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1790be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1791be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1792be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1793be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1794be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1795be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1796be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1797be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1798be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1799be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1800be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1801be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1802be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1803be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1804be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1805be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1806be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1807be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1808be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1809be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1810be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1811be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1812be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1813be0f34b5SRichard Henderson 
1814be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1815be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1816be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1817be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1818be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1819be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1820be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1821be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1822be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1823be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
1824be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
1825be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
1826be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
1827be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
1828be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
1829be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
1830be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
1831be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
1832be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
1833be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
1834fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
1835fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
1836be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
1837be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrl_i64_i32;
1838be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
1839be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrh_i64_i32;
1840be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
1841be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
1842be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
1843be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
1844be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
1845be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
1846be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
1847be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
1848be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
1849be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
1850be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
1851be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
1852be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
1853be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
1854be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
1855be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
1856be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
1857be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
1858be0f34b5SRichard Henderson     case INDEX_op_not_i64:
1859be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
1860be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
1861be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
1862be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
1863be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
1864be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
1865be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
1866be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
1867be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
1868be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
1869be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
1870be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
1871be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
1872be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
1873be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
1874be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
1875be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
1876be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
1877be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
1878be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
1879be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
1880be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
1881be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
1882be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
1883be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
1884be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
1885be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
1886be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
1887be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
1888be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
1889be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
1890be0f34b5SRichard Henderson 
1891d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
1892d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
189337ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
1894d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
1895d2fd745fSRichard Henderson     case INDEX_op_st_vec:
1896d2fd745fSRichard Henderson     case INDEX_op_add_vec:
1897d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
1898d2fd745fSRichard Henderson     case INDEX_op_and_vec:
1899d2fd745fSRichard Henderson     case INDEX_op_or_vec:
1900d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
1901212be173SRichard Henderson     case INDEX_op_cmp_vec:
1902d2fd745fSRichard Henderson         return have_vec;
1903d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
1904d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
1905d2fd745fSRichard Henderson     case INDEX_op_not_vec:
1906d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
1907d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
1908d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
1909bcefc902SRichard Henderson     case INDEX_op_abs_vec:
1910bcefc902SRichard Henderson         return have_vec && TCG_TARGET_HAS_abs_vec;
1911d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
1912d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
1913d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
1914d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
19153774030aSRichard Henderson     case INDEX_op_mul_vec:
19163774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
1917d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
1918d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
1919d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
1920d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
1921d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
1922d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
1923d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
1924d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
1925d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
1926d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
1927d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
1928d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
1929b0f7e744SRichard Henderson     case INDEX_op_rotli_vec:
1930b0f7e744SRichard Henderson         return have_vec && TCG_TARGET_HAS_roti_vec;
193123850a74SRichard Henderson     case INDEX_op_rotls_vec:
193223850a74SRichard Henderson         return have_vec && TCG_TARGET_HAS_rots_vec;
19335d0ceda9SRichard Henderson     case INDEX_op_rotlv_vec:
19345d0ceda9SRichard Henderson     case INDEX_op_rotrv_vec:
19355d0ceda9SRichard Henderson         return have_vec && TCG_TARGET_HAS_rotv_vec;
19368afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
19378afaf050SRichard Henderson     case INDEX_op_usadd_vec:
19388afaf050SRichard Henderson     case INDEX_op_sssub_vec:
19398afaf050SRichard Henderson     case INDEX_op_ussub_vec:
19408afaf050SRichard Henderson         return have_vec && TCG_TARGET_HAS_sat_vec;
1941dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
1942dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
1943dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
1944dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
1945dd0a0fcdSRichard Henderson         return have_vec && TCG_TARGET_HAS_minmax_vec;
194638dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
194738dc1294SRichard Henderson         return have_vec && TCG_TARGET_HAS_bitsel_vec;
1948f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
1949f75da298SRichard Henderson         return have_vec && TCG_TARGET_HAS_cmpsel_vec;
1950d2fd745fSRichard Henderson 
1951db432672SRichard Henderson     default:
1952db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
1953db432672SRichard Henderson         return true;
1954be0f34b5SRichard Henderson     }
1955be0f34b5SRichard Henderson }
1956be0f34b5SRichard Henderson 
195739cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment
195839cf05d3Sbellard    and endian swap. Maybe it would be better to do the alignment
195939cf05d3Sbellard    and endian swap in tcg_reg_alloc_call(). */
1960ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
1961c896fe29Sbellard {
196275e8b9b7SRichard Henderson     int i, real_args, nb_rets, pi;
1963bbb8a1b4SRichard Henderson     unsigned sizemask, flags;
1964afb49896SRichard Henderson     TCGHelperInfo *info;
196575e8b9b7SRichard Henderson     TCGOp *op;
1966afb49896SRichard Henderson 
1967619205fdSEmilio G. Cota     info = g_hash_table_lookup(helper_table, (gpointer)func);
1968bbb8a1b4SRichard Henderson     flags = info->flags;
1969bbb8a1b4SRichard Henderson     sizemask = info->sizemask;
19702bece2c8SRichard Henderson 
197138b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
197238b47b19SEmilio G. Cota     /* detect non-plugin helpers */
197338b47b19SEmilio G. Cota     if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) {
197438b47b19SEmilio G. Cota         tcg_ctx->plugin_insn->calls_helpers = true;
197538b47b19SEmilio G. Cota     }
197638b47b19SEmilio G. Cota #endif
197738b47b19SEmilio G. Cota 
197834b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
197934b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
198034b1a49cSRichard Henderson     /* We have 64-bit values in one register, but need to pass as two
198134b1a49cSRichard Henderson        separate parameters.  Split them.  */
198234b1a49cSRichard Henderson     int orig_sizemask = sizemask;
198334b1a49cSRichard Henderson     int orig_nargs = nargs;
198434b1a49cSRichard Henderson     TCGv_i64 retl, reth;
1985ae8b75dcSRichard Henderson     TCGTemp *split_args[MAX_OPC_PARAM];
198634b1a49cSRichard Henderson 
1987f764718dSRichard Henderson     retl = NULL;
1988f764718dSRichard Henderson     reth = NULL;
198934b1a49cSRichard Henderson     if (sizemask != 0) {
199034b1a49cSRichard Henderson         for (i = real_args = 0; i < nargs; ++i) {
199134b1a49cSRichard Henderson             int is_64bit = sizemask & (1 << (i+1)*2);
199234b1a49cSRichard Henderson             if (is_64bit) {
1993085272b3SRichard Henderson                 TCGv_i64 orig = temp_tcgv_i64(args[i]);
199434b1a49cSRichard Henderson                 TCGv_i32 h = tcg_temp_new_i32();
199534b1a49cSRichard Henderson                 TCGv_i32 l = tcg_temp_new_i32();
199634b1a49cSRichard Henderson                 tcg_gen_extr_i64_i32(l, h, orig);
1997ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(h);
1998ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(l);
199934b1a49cSRichard Henderson             } else {
200034b1a49cSRichard Henderson                 split_args[real_args++] = args[i];
200134b1a49cSRichard Henderson             }
200234b1a49cSRichard Henderson         }
200334b1a49cSRichard Henderson         nargs = real_args;
200434b1a49cSRichard Henderson         args = split_args;
200534b1a49cSRichard Henderson         sizemask = 0;
200634b1a49cSRichard Henderson     }
200734b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
20082bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
20092bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
20102bece2c8SRichard Henderson         int is_signed = sizemask & (2 << (i+1)*2);
20112bece2c8SRichard Henderson         if (!is_64bit) {
20122bece2c8SRichard Henderson             TCGv_i64 temp = tcg_temp_new_i64();
2013085272b3SRichard Henderson             TCGv_i64 orig = temp_tcgv_i64(args[i]);
20142bece2c8SRichard Henderson             if (is_signed) {
20152bece2c8SRichard Henderson                 tcg_gen_ext32s_i64(temp, orig);
20162bece2c8SRichard Henderson             } else {
20172bece2c8SRichard Henderson                 tcg_gen_ext32u_i64(temp, orig);
20182bece2c8SRichard Henderson             }
2019ae8b75dcSRichard Henderson             args[i] = tcgv_i64_temp(temp);
20202bece2c8SRichard Henderson         }
20212bece2c8SRichard Henderson     }
20222bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
20232bece2c8SRichard Henderson 
202415fa08f8SRichard Henderson     op = tcg_emit_op(INDEX_op_call);
202575e8b9b7SRichard Henderson 
202675e8b9b7SRichard Henderson     pi = 0;
2027ae8b75dcSRichard Henderson     if (ret != NULL) {
202834b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
202934b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
203034b1a49cSRichard Henderson         if (orig_sizemask & 1) {
203134b1a49cSRichard Henderson             /* The 32-bit ABI is going to return the 64-bit value in
203234b1a49cSRichard Henderson                the %o0/%o1 register pair.  Prepare for this by using
203334b1a49cSRichard Henderson                two return temporaries, and reassemble below.  */
203434b1a49cSRichard Henderson             retl = tcg_temp_new_i64();
203534b1a49cSRichard Henderson             reth = tcg_temp_new_i64();
2036ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(reth);
2037ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(retl);
203834b1a49cSRichard Henderson             nb_rets = 2;
203934b1a49cSRichard Henderson         } else {
2040ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
204134b1a49cSRichard Henderson             nb_rets = 1;
204234b1a49cSRichard Henderson         }
204334b1a49cSRichard Henderson #else
204434b1a49cSRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) {
204502eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
2046ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
2047ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
2048a7812ae4Spbrook #else
2049ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
2050ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
2051a7812ae4Spbrook #endif
2052a7812ae4Spbrook             nb_rets = 2;
205334b1a49cSRichard Henderson         } else {
2054ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
2055a7812ae4Spbrook             nb_rets = 1;
2056a7812ae4Spbrook         }
205734b1a49cSRichard Henderson #endif
2058a7812ae4Spbrook     } else {
2059a7812ae4Spbrook         nb_rets = 0;
2060a7812ae4Spbrook     }
2061cd9090aaSRichard Henderson     TCGOP_CALLO(op) = nb_rets;
206275e8b9b7SRichard Henderson 
2063a7812ae4Spbrook     real_args = 0;
2064a7812ae4Spbrook     for (i = 0; i < nargs; i++) {
20652bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
2066bbb8a1b4SRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
206739cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS
206839cf05d3Sbellard             /* some targets want aligned 64 bit args */
2069ebd486d5Smalc             if (real_args & 1) {
207075e8b9b7SRichard Henderson                 op->args[pi++] = TCG_CALL_DUMMY_ARG;
2071ebd486d5Smalc                 real_args++;
207239cf05d3Sbellard             }
207339cf05d3Sbellard #endif
20743f90f252SRichard Henderson            /* If stack grows up, then we will be placing successive
20753f90f252SRichard Henderson               arguments at lower addresses, which means we need to
20763f90f252SRichard Henderson               reverse the order compared to how we would normally
20773f90f252SRichard Henderson               treat either big or little-endian.  For those arguments
20783f90f252SRichard Henderson               that will wind up in registers, this still works for
20793f90f252SRichard Henderson               HPPA (the only current STACK_GROWSUP target) since the
20803f90f252SRichard Henderson               argument registers are *also* allocated in decreasing
20813f90f252SRichard Henderson               order.  If another such target is added, this logic may
20823f90f252SRichard Henderson               have to get more complicated to differentiate between
20833f90f252SRichard Henderson               stack arguments and register arguments.  */
208402eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
2085ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
2086ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
2087c896fe29Sbellard #else
2088ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
2089ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
2090c896fe29Sbellard #endif
2091a7812ae4Spbrook             real_args += 2;
20922bece2c8SRichard Henderson             continue;
20932bece2c8SRichard Henderson         }
20942bece2c8SRichard Henderson 
2095ae8b75dcSRichard Henderson         op->args[pi++] = temp_arg(args[i]);
2096a7812ae4Spbrook         real_args++;
2097c896fe29Sbellard     }
209875e8b9b7SRichard Henderson     op->args[pi++] = (uintptr_t)func;
209975e8b9b7SRichard Henderson     op->args[pi++] = flags;
2100cd9090aaSRichard Henderson     TCGOP_CALLI(op) = real_args;
2101a7812ae4Spbrook 
210275e8b9b7SRichard Henderson     /* Make sure the fields didn't overflow.  */
2103cd9090aaSRichard Henderson     tcg_debug_assert(TCGOP_CALLI(op) == real_args);
210475e8b9b7SRichard Henderson     tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
21052bece2c8SRichard Henderson 
210634b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
210734b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
210834b1a49cSRichard Henderson     /* Free all of the parts we allocated above.  */
210934b1a49cSRichard Henderson     for (i = real_args = 0; i < orig_nargs; ++i) {
211034b1a49cSRichard Henderson         int is_64bit = orig_sizemask & (1 << (i+1)*2);
211134b1a49cSRichard Henderson         if (is_64bit) {
2112085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
2113085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
211434b1a49cSRichard Henderson         } else {
211534b1a49cSRichard Henderson             real_args++;
211634b1a49cSRichard Henderson         }
211734b1a49cSRichard Henderson     }
211834b1a49cSRichard Henderson     if (orig_sizemask & 1) {
211934b1a49cSRichard Henderson         /* The 32-bit ABI returned two 32-bit pieces.  Re-assemble them.
212034b1a49cSRichard Henderson            Note that describing these as TCGv_i64 eliminates an unnecessary
212134b1a49cSRichard Henderson            zero-extension that tcg_gen_concat_i32_i64 would create.  */
2122085272b3SRichard Henderson         tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth);
212334b1a49cSRichard Henderson         tcg_temp_free_i64(retl);
212434b1a49cSRichard Henderson         tcg_temp_free_i64(reth);
212534b1a49cSRichard Henderson     }
212634b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
21272bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
21282bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
21292bece2c8SRichard Henderson         if (!is_64bit) {
2130085272b3SRichard Henderson             tcg_temp_free_internal(args[i]);
21312bece2c8SRichard Henderson         }
21322bece2c8SRichard Henderson     }
21332bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
2134a7812ae4Spbrook }
2135c896fe29Sbellard 
21368fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
2137c896fe29Sbellard {
2138ac3b8891SRichard Henderson     int i, n;
2139ac3b8891SRichard Henderson 
2140ee17db83SRichard Henderson     for (i = 0, n = s->nb_temps; i < n; i++) {
2141ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2142ee17db83SRichard Henderson         TCGTempVal val = TEMP_VAL_MEM;
2143ee17db83SRichard Henderson 
2144ee17db83SRichard Henderson         switch (ts->kind) {
2145c0522136SRichard Henderson         case TEMP_CONST:
2146c0522136SRichard Henderson             val = TEMP_VAL_CONST;
2147c0522136SRichard Henderson             break;
2148ee17db83SRichard Henderson         case TEMP_FIXED:
2149ee17db83SRichard Henderson             val = TEMP_VAL_REG;
2150ee17db83SRichard Henderson             break;
2151ee17db83SRichard Henderson         case TEMP_GLOBAL:
2152ee17db83SRichard Henderson             break;
2153ee17db83SRichard Henderson         case TEMP_NORMAL:
2154ee17db83SRichard Henderson             val = TEMP_VAL_DEAD;
2155ee17db83SRichard Henderson             /* fall through */
2156ee17db83SRichard Henderson         case TEMP_LOCAL:
2157e8996ee0Sbellard             ts->mem_allocated = 0;
2158ee17db83SRichard Henderson             break;
2159ee17db83SRichard Henderson         default:
2160ee17db83SRichard Henderson             g_assert_not_reached();
2161ee17db83SRichard Henderson         }
2162ee17db83SRichard Henderson         ts->val_type = val;
2163e8996ee0Sbellard     }
2164f8b2f202SRichard Henderson 
2165f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
2166c896fe29Sbellard }
2167c896fe29Sbellard 
2168f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
2169f8b2f202SRichard Henderson                                  TCGTemp *ts)
2170c896fe29Sbellard {
21711807f4c4SRichard Henderson     int idx = temp_idx(ts);
2172ac56dd48Spbrook 
2173ee17db83SRichard Henderson     switch (ts->kind) {
2174ee17db83SRichard Henderson     case TEMP_FIXED:
2175ee17db83SRichard Henderson     case TEMP_GLOBAL:
2176ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
2177ee17db83SRichard Henderson         break;
2178ee17db83SRichard Henderson     case TEMP_LOCAL:
2179641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
2180ee17db83SRichard Henderson         break;
2181ee17db83SRichard Henderson     case TEMP_NORMAL:
2182ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
2183ee17db83SRichard Henderson         break;
2184c0522136SRichard Henderson     case TEMP_CONST:
2185c0522136SRichard Henderson         switch (ts->type) {
2186c0522136SRichard Henderson         case TCG_TYPE_I32:
2187c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val);
2188c0522136SRichard Henderson             break;
2189c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32
2190c0522136SRichard Henderson         case TCG_TYPE_I64:
2191c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%" PRIx64, ts->val);
2192c0522136SRichard Henderson             break;
2193c0522136SRichard Henderson #endif
2194c0522136SRichard Henderson         case TCG_TYPE_V64:
2195c0522136SRichard Henderson         case TCG_TYPE_V128:
2196c0522136SRichard Henderson         case TCG_TYPE_V256:
2197c0522136SRichard Henderson             snprintf(buf, buf_size, "v%d$0x%" PRIx64,
2198c0522136SRichard Henderson                      64 << (ts->type - TCG_TYPE_V64), ts->val);
2199c0522136SRichard Henderson             break;
2200c0522136SRichard Henderson         default:
2201c0522136SRichard Henderson             g_assert_not_reached();
2202c0522136SRichard Henderson         }
2203c0522136SRichard Henderson         break;
2204c896fe29Sbellard     }
2205c896fe29Sbellard     return buf;
2206c896fe29Sbellard }
2207c896fe29Sbellard 
220843439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
220943439139SRichard Henderson                              int buf_size, TCGArg arg)
2210f8b2f202SRichard Henderson {
221143439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
2212f8b2f202SRichard Henderson }
2213f8b2f202SRichard Henderson 
22146e085f72SRichard Henderson /* Find helper name.  */
22156e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val)
2216e8996ee0Sbellard {
22176e085f72SRichard Henderson     const char *ret = NULL;
2218619205fdSEmilio G. Cota     if (helper_table) {
2219619205fdSEmilio G. Cota         TCGHelperInfo *info = g_hash_table_lookup(helper_table, (gpointer)val);
222072866e82SRichard Henderson         if (info) {
222172866e82SRichard Henderson             ret = info->name;
222272866e82SRichard Henderson         }
2223e8996ee0Sbellard     }
22246e085f72SRichard Henderson     return ret;
22254dc81f28Sbellard }
22264dc81f28Sbellard 
2227f48f3edeSblueswir1 static const char * const cond_name[] =
2228f48f3edeSblueswir1 {
22290aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
22300aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
2231f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
2232f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
2233f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
2234f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
2235f48f3edeSblueswir1     [TCG_COND_LE] = "le",
2236f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
2237f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
2238f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
2239f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
2240f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
2241f48f3edeSblueswir1 };
2242f48f3edeSblueswir1 
2243f713d6adSRichard Henderson static const char * const ldst_name[] =
2244f713d6adSRichard Henderson {
2245f713d6adSRichard Henderson     [MO_UB]   = "ub",
2246f713d6adSRichard Henderson     [MO_SB]   = "sb",
2247f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
2248f713d6adSRichard Henderson     [MO_LESW] = "lesw",
2249f713d6adSRichard Henderson     [MO_LEUL] = "leul",
2250f713d6adSRichard Henderson     [MO_LESL] = "lesl",
2251f713d6adSRichard Henderson     [MO_LEQ]  = "leq",
2252f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
2253f713d6adSRichard Henderson     [MO_BESW] = "besw",
2254f713d6adSRichard Henderson     [MO_BEUL] = "beul",
2255f713d6adSRichard Henderson     [MO_BESL] = "besl",
2256f713d6adSRichard Henderson     [MO_BEQ]  = "beq",
2257f713d6adSRichard Henderson };
2258f713d6adSRichard Henderson 
22591f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
226052bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY
22611f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
22621f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
22631f00b27fSSergey Sorokin #else
22641f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
22651f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
22661f00b27fSSergey Sorokin #endif
22671f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
22681f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
22691f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
22701f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
22711f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
22721f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
22731f00b27fSSergey Sorokin };
22741f00b27fSSergey Sorokin 
2275b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
2276b016486eSRichard Henderson {
2277b016486eSRichard Henderson     return (d & (d - 1)) == 0;
2278b016486eSRichard Henderson }
2279b016486eSRichard Henderson 
2280b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
2281b016486eSRichard Henderson {
2282b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
2283b016486eSRichard Henderson         return ctz32(d);
2284b016486eSRichard Henderson     } else {
2285b016486eSRichard Henderson         return ctz64(d);
2286b016486eSRichard Henderson     }
2287b016486eSRichard Henderson }
2288b016486eSRichard Henderson 
22891894f69aSRichard Henderson static void tcg_dump_ops(TCGContext *s, bool have_prefs)
2290c896fe29Sbellard {
2291c896fe29Sbellard     char buf[128];
2292c45cb8bbSRichard Henderson     TCGOp *op;
2293c896fe29Sbellard 
229415fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
2295c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
2296c45cb8bbSRichard Henderson         const TCGOpDef *def;
2297c45cb8bbSRichard Henderson         TCGOpcode c;
2298bdfb460eSRichard Henderson         int col = 0;
2299c45cb8bbSRichard Henderson 
2300c45cb8bbSRichard Henderson         c = op->opc;
2301c896fe29Sbellard         def = &tcg_op_defs[c];
2302c45cb8bbSRichard Henderson 
2303765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
2304b016486eSRichard Henderson             nb_oargs = 0;
230515fa08f8SRichard Henderson             col += qemu_log("\n ----");
23069aef40edSRichard Henderson 
23079aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
23089aef40edSRichard Henderson                 target_ulong a;
23097e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
2310efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
23117e4597d7Sbellard #else
2312efee3746SRichard Henderson                 a = op->args[i];
23137e4597d7Sbellard #endif
2314bdfb460eSRichard Henderson                 col += qemu_log(" " TARGET_FMT_lx, a);
2315eeacee4dSBlue Swirl             }
23167e4597d7Sbellard         } else if (c == INDEX_op_call) {
2317c896fe29Sbellard             /* variable number of arguments */
2318cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2319cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2320c896fe29Sbellard             nb_cargs = def->nb_cargs;
2321b03cce8eSbellard 
2322cf066674SRichard Henderson             /* function name, flags, out args */
2323bdfb460eSRichard Henderson             col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name,
2324efee3746SRichard Henderson                             tcg_find_helper(s, op->args[nb_oargs + nb_iargs]),
2325efee3746SRichard Henderson                             op->args[nb_oargs + nb_iargs + 1], nb_oargs);
2326b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
232743439139SRichard Henderson                 col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf),
2328efee3746SRichard Henderson                                                        op->args[i]));
2329b03cce8eSbellard             }
2330cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
2331efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
2332cf066674SRichard Henderson                 const char *t = "<dummy>";
2333cf066674SRichard Henderson                 if (arg != TCG_CALL_DUMMY_ARG) {
233443439139SRichard Henderson                     t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
2335b03cce8eSbellard                 }
2336bdfb460eSRichard Henderson                 col += qemu_log(",%s", t);
2337e8996ee0Sbellard             }
2338b03cce8eSbellard         } else {
2339bdfb460eSRichard Henderson             col += qemu_log(" %s ", def->name);
2340c45cb8bbSRichard Henderson 
2341c896fe29Sbellard             nb_oargs = def->nb_oargs;
2342c896fe29Sbellard             nb_iargs = def->nb_iargs;
2343c896fe29Sbellard             nb_cargs = def->nb_cargs;
2344c896fe29Sbellard 
2345d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
2346d2fd745fSRichard Henderson                 col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op),
2347d2fd745fSRichard Henderson                                 8 << TCGOP_VECE(op));
2348d2fd745fSRichard Henderson             }
2349d2fd745fSRichard Henderson 
2350c896fe29Sbellard             k = 0;
2351c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
2352eeacee4dSBlue Swirl                 if (k != 0) {
2353bdfb460eSRichard Henderson                     col += qemu_log(",");
2354eeacee4dSBlue Swirl                 }
235543439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2356efee3746SRichard Henderson                                                       op->args[k++]));
2357c896fe29Sbellard             }
2358c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
2359eeacee4dSBlue Swirl                 if (k != 0) {
2360bdfb460eSRichard Henderson                     col += qemu_log(",");
2361eeacee4dSBlue Swirl                 }
236243439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2363efee3746SRichard Henderson                                                       op->args[k++]));
2364c896fe29Sbellard             }
2365be210acbSRichard Henderson             switch (c) {
2366be210acbSRichard Henderson             case INDEX_op_brcond_i32:
2367ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
2368ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
2369be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
2370be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
2371ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
2372be210acbSRichard Henderson             case INDEX_op_setcond_i64:
2373ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
2374212be173SRichard Henderson             case INDEX_op_cmp_vec:
2375f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
2376efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
2377efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
2378efee3746SRichard Henderson                     col += qemu_log(",%s", cond_name[op->args[k++]]);
2379eeacee4dSBlue Swirl                 } else {
2380efee3746SRichard Henderson                     col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]);
2381eeacee4dSBlue Swirl                 }
2382f48f3edeSblueswir1                 i = 1;
2383be210acbSRichard Henderson                 break;
2384f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
2385f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
238607ce0b05SRichard Henderson             case INDEX_op_qemu_st8_i32:
2387f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
2388f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
238959227d5dSRichard Henderson                 {
2390efee3746SRichard Henderson                     TCGMemOpIdx oi = op->args[k++];
239114776ab5STony Nguyen                     MemOp op = get_memop(oi);
239259227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
239359227d5dSRichard Henderson 
239459c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
2395bdfb460eSRichard Henderson                         col += qemu_log(",$0x%x,%u", op, ix);
239659c4b7e8SRichard Henderson                     } else {
23971f00b27fSSergey Sorokin                         const char *s_al, *s_op;
23981f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
239959c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
2400bdfb460eSRichard Henderson                         col += qemu_log(",%s%s,%u", s_al, s_op, ix);
2401f713d6adSRichard Henderson                     }
2402f713d6adSRichard Henderson                     i = 1;
240359227d5dSRichard Henderson                 }
2404f713d6adSRichard Henderson                 break;
2405be210acbSRichard Henderson             default:
2406f48f3edeSblueswir1                 i = 0;
2407be210acbSRichard Henderson                 break;
2408be210acbSRichard Henderson             }
240951e3972cSRichard Henderson             switch (c) {
241051e3972cSRichard Henderson             case INDEX_op_set_label:
241151e3972cSRichard Henderson             case INDEX_op_br:
241251e3972cSRichard Henderson             case INDEX_op_brcond_i32:
241351e3972cSRichard Henderson             case INDEX_op_brcond_i64:
241451e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2415efee3746SRichard Henderson                 col += qemu_log("%s$L%d", k ? "," : "",
2416efee3746SRichard Henderson                                 arg_label(op->args[k])->id);
241751e3972cSRichard Henderson                 i++, k++;
241851e3972cSRichard Henderson                 break;
241951e3972cSRichard Henderson             default:
242051e3972cSRichard Henderson                 break;
2421eeacee4dSBlue Swirl             }
242251e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
2423efee3746SRichard Henderson                 col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]);
2424bdfb460eSRichard Henderson             }
2425bdfb460eSRichard Henderson         }
2426bdfb460eSRichard Henderson 
24271894f69aSRichard Henderson         if (have_prefs || op->life) {
24287606488cSRobert Foley 
24297606488cSRobert Foley             QemuLogFile *logfile;
24307606488cSRobert Foley 
24317606488cSRobert Foley             rcu_read_lock();
2432d73415a3SStefan Hajnoczi             logfile = qatomic_rcu_read(&qemu_logfile);
24337606488cSRobert Foley             if (logfile) {
24341894f69aSRichard Henderson                 for (; col < 40; ++col) {
24357606488cSRobert Foley                     putc(' ', logfile->fd);
2436bdfb460eSRichard Henderson                 }
24371894f69aSRichard Henderson             }
24387606488cSRobert Foley             rcu_read_unlock();
24397606488cSRobert Foley         }
24401894f69aSRichard Henderson 
24411894f69aSRichard Henderson         if (op->life) {
24421894f69aSRichard Henderson             unsigned life = op->life;
2443bdfb460eSRichard Henderson 
2444bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
2445bdfb460eSRichard Henderson                 qemu_log("  sync:");
2446bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
2447bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
2448bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2449bdfb460eSRichard Henderson                     }
2450bdfb460eSRichard Henderson                 }
2451bdfb460eSRichard Henderson             }
2452bdfb460eSRichard Henderson             life /= DEAD_ARG;
2453bdfb460eSRichard Henderson             if (life) {
2454bdfb460eSRichard Henderson                 qemu_log("  dead:");
2455bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
2456bdfb460eSRichard Henderson                     if (life & 1) {
2457bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2458bdfb460eSRichard Henderson                     }
2459bdfb460eSRichard Henderson                 }
2460c896fe29Sbellard             }
2461b03cce8eSbellard         }
24621894f69aSRichard Henderson 
24631894f69aSRichard Henderson         if (have_prefs) {
24641894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
24651894f69aSRichard Henderson                 TCGRegSet set = op->output_pref[i];
24661894f69aSRichard Henderson 
24671894f69aSRichard Henderson                 if (i == 0) {
24681894f69aSRichard Henderson                     qemu_log("  pref=");
24691894f69aSRichard Henderson                 } else {
24701894f69aSRichard Henderson                     qemu_log(",");
24711894f69aSRichard Henderson                 }
24721894f69aSRichard Henderson                 if (set == 0) {
24731894f69aSRichard Henderson                     qemu_log("none");
24741894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
24751894f69aSRichard Henderson                     qemu_log("all");
24761894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
24771894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
24781894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
24791894f69aSRichard Henderson                     qemu_log("%s", tcg_target_reg_names[reg]);
24801894f69aSRichard Henderson #endif
24811894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
24821894f69aSRichard Henderson                     qemu_log("%#x", (uint32_t)set);
24831894f69aSRichard Henderson                 } else {
24841894f69aSRichard Henderson                     qemu_log("%#" PRIx64, (uint64_t)set);
24851894f69aSRichard Henderson                 }
24861894f69aSRichard Henderson             }
24871894f69aSRichard Henderson         }
24881894f69aSRichard Henderson 
2489eeacee4dSBlue Swirl         qemu_log("\n");
2490c896fe29Sbellard     }
2491c896fe29Sbellard }
2492c896fe29Sbellard 
2493c896fe29Sbellard /* we give more priority to constraints with less registers */
2494c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2495c896fe29Sbellard {
249674a11790SRichard Henderson     const TCGArgConstraint *arg_ct = &def->args_ct[k];
249774a11790SRichard Henderson     int n;
2498c896fe29Sbellard 
2499bc2b17e6SRichard Henderson     if (arg_ct->oalias) {
2500c896fe29Sbellard         /* an alias is equivalent to a single register */
2501c896fe29Sbellard         n = 1;
2502c896fe29Sbellard     } else {
250374a11790SRichard Henderson         n = ctpop64(arg_ct->regs);
2504c896fe29Sbellard     }
2505c896fe29Sbellard     return TCG_TARGET_NB_REGS - n + 1;
2506c896fe29Sbellard }
2507c896fe29Sbellard 
2508c896fe29Sbellard /* sort from highest priority to lowest */
2509c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2510c896fe29Sbellard {
251166792f90SRichard Henderson     int i, j;
251266792f90SRichard Henderson     TCGArgConstraint *a = def->args_ct;
2513c896fe29Sbellard 
251466792f90SRichard Henderson     for (i = 0; i < n; i++) {
251566792f90SRichard Henderson         a[start + i].sort_index = start + i;
251666792f90SRichard Henderson     }
251766792f90SRichard Henderson     if (n <= 1) {
2518c896fe29Sbellard         return;
251966792f90SRichard Henderson     }
2520c896fe29Sbellard     for (i = 0; i < n - 1; i++) {
2521c896fe29Sbellard         for (j = i + 1; j < n; j++) {
252266792f90SRichard Henderson             int p1 = get_constraint_priority(def, a[start + i].sort_index);
252366792f90SRichard Henderson             int p2 = get_constraint_priority(def, a[start + j].sort_index);
2524c896fe29Sbellard             if (p1 < p2) {
252566792f90SRichard Henderson                 int tmp = a[start + i].sort_index;
252666792f90SRichard Henderson                 a[start + i].sort_index = a[start + j].sort_index;
252766792f90SRichard Henderson                 a[start + j].sort_index = tmp;
2528c896fe29Sbellard             }
2529c896fe29Sbellard         }
2530c896fe29Sbellard     }
2531c896fe29Sbellard }
2532c896fe29Sbellard 
2533f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2534c896fe29Sbellard {
2535a9751609SRichard Henderson     TCGOpcode op;
2536c896fe29Sbellard 
2537f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
2538f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
2539f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
2540069ea736SRichard Henderson         int i, nb_args;
2541f69d277eSRichard Henderson 
2542f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
2543f69d277eSRichard Henderson             continue;
2544f69d277eSRichard Henderson         }
2545f69d277eSRichard Henderson 
2546c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
2547f69d277eSRichard Henderson         if (nb_args == 0) {
2548f69d277eSRichard Henderson             continue;
2549f69d277eSRichard Henderson         }
2550f69d277eSRichard Henderson 
25514c22e840SRichard Henderson         /*
25524c22e840SRichard Henderson          * Macro magic should make it impossible, but double-check that
25534c22e840SRichard Henderson          * the array index is in range.  Since the signness of an enum
25544c22e840SRichard Henderson          * is implementation defined, force the result to unsigned.
25554c22e840SRichard Henderson          */
25564c22e840SRichard Henderson         unsigned con_set = tcg_target_op_def(op);
25574c22e840SRichard Henderson         tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets));
25584c22e840SRichard Henderson         tdefs = &constraint_sets[con_set];
2559f69d277eSRichard Henderson 
2560c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2561f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
2562f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2563eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2564f69d277eSRichard Henderson 
256517280ff4SRichard Henderson             while (*ct_str != '\0') {
256617280ff4SRichard Henderson                 switch(*ct_str) {
256717280ff4SRichard Henderson                 case '0' ... '9':
256817280ff4SRichard Henderson                     {
256917280ff4SRichard Henderson                         int oarg = *ct_str - '0';
257017280ff4SRichard Henderson                         tcg_debug_assert(ct_str == tdefs->args_ct_str[i]);
2571eabb7b91SAurelien Jarno                         tcg_debug_assert(oarg < def->nb_oargs);
257274a11790SRichard Henderson                         tcg_debug_assert(def->args_ct[oarg].regs != 0);
2573c896fe29Sbellard                         def->args_ct[i] = def->args_ct[oarg];
2574bc2b17e6SRichard Henderson                         /* The output sets oalias.  */
2575bc2b17e6SRichard Henderson                         def->args_ct[oarg].oalias = true;
25765ff9d6a4Sbellard                         def->args_ct[oarg].alias_index = i;
2577bc2b17e6SRichard Henderson                         /* The input sets ialias. */
2578bc2b17e6SRichard Henderson                         def->args_ct[i].ialias = true;
25795ff9d6a4Sbellard                         def->args_ct[i].alias_index = oarg;
258017280ff4SRichard Henderson                     }
258117280ff4SRichard Henderson                     ct_str++;
2582c896fe29Sbellard                     break;
258382790a87SRichard Henderson                 case '&':
2584bc2b17e6SRichard Henderson                     def->args_ct[i].newreg = true;
258582790a87SRichard Henderson                     ct_str++;
258682790a87SRichard Henderson                     break;
2587c896fe29Sbellard                 case 'i':
2588c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2589c896fe29Sbellard                     ct_str++;
2590c896fe29Sbellard                     break;
2591358b4923SRichard Henderson 
2592358b4923SRichard Henderson                 /* Include all of the target-specific constraints. */
2593358b4923SRichard Henderson 
2594358b4923SRichard Henderson #undef CONST
2595358b4923SRichard Henderson #define CONST(CASE, MASK) \
2596358b4923SRichard Henderson     case CASE: def->args_ct[i].ct |= MASK; ct_str++; break;
2597358b4923SRichard Henderson #define REGS(CASE, MASK) \
2598358b4923SRichard Henderson     case CASE: def->args_ct[i].regs |= MASK; ct_str++; break;
2599358b4923SRichard Henderson 
2600358b4923SRichard Henderson #include "tcg-target-con-str.h"
2601358b4923SRichard Henderson 
2602358b4923SRichard Henderson #undef REGS
2603358b4923SRichard Henderson #undef CONST
2604c896fe29Sbellard                 default:
2605358b4923SRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2606358b4923SRichard Henderson                     g_assert_not_reached();
2607358b4923SRichard Henderson                 }
2608c896fe29Sbellard             }
2609c896fe29Sbellard         }
2610c896fe29Sbellard 
2611c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2612eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2613c68aaa18SStefan Weil 
2614c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
2615c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
2616c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
2617c896fe29Sbellard     }
2618c896fe29Sbellard }
2619c896fe29Sbellard 
26200c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
26210c627cdcSRichard Henderson {
2622d88a117eSRichard Henderson     TCGLabel *label;
2623d88a117eSRichard Henderson 
2624d88a117eSRichard Henderson     switch (op->opc) {
2625d88a117eSRichard Henderson     case INDEX_op_br:
2626d88a117eSRichard Henderson         label = arg_label(op->args[0]);
2627d88a117eSRichard Henderson         label->refs--;
2628d88a117eSRichard Henderson         break;
2629d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
2630d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
2631d88a117eSRichard Henderson         label = arg_label(op->args[3]);
2632d88a117eSRichard Henderson         label->refs--;
2633d88a117eSRichard Henderson         break;
2634d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
2635d88a117eSRichard Henderson         label = arg_label(op->args[5]);
2636d88a117eSRichard Henderson         label->refs--;
2637d88a117eSRichard Henderson         break;
2638d88a117eSRichard Henderson     default:
2639d88a117eSRichard Henderson         break;
2640d88a117eSRichard Henderson     }
2641d88a117eSRichard Henderson 
264215fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
264315fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
2644abebf925SRichard Henderson     s->nb_ops--;
26450c627cdcSRichard Henderson 
26460c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
2647d73415a3SStefan Hajnoczi     qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
26480c627cdcSRichard Henderson #endif
26490c627cdcSRichard Henderson }
26500c627cdcSRichard Henderson 
265115fa08f8SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc)
265215fa08f8SRichard Henderson {
265315fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
265415fa08f8SRichard Henderson     TCGOp *op;
265515fa08f8SRichard Henderson 
265615fa08f8SRichard Henderson     if (likely(QTAILQ_EMPTY(&s->free_ops))) {
265715fa08f8SRichard Henderson         op = tcg_malloc(sizeof(TCGOp));
265815fa08f8SRichard Henderson     } else {
265915fa08f8SRichard Henderson         op = QTAILQ_FIRST(&s->free_ops);
266015fa08f8SRichard Henderson         QTAILQ_REMOVE(&s->free_ops, op, link);
266115fa08f8SRichard Henderson     }
266215fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
266315fa08f8SRichard Henderson     op->opc = opc;
2664abebf925SRichard Henderson     s->nb_ops++;
266515fa08f8SRichard Henderson 
266615fa08f8SRichard Henderson     return op;
266715fa08f8SRichard Henderson }
266815fa08f8SRichard Henderson 
266915fa08f8SRichard Henderson TCGOp *tcg_emit_op(TCGOpcode opc)
267015fa08f8SRichard Henderson {
267115fa08f8SRichard Henderson     TCGOp *op = tcg_op_alloc(opc);
267215fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
267315fa08f8SRichard Henderson     return op;
267415fa08f8SRichard Henderson }
267515fa08f8SRichard Henderson 
2676ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
26775a18407fSRichard Henderson {
267815fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
267915fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
26805a18407fSRichard Henderson     return new_op;
26815a18407fSRichard Henderson }
26825a18407fSRichard Henderson 
2683ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
26845a18407fSRichard Henderson {
268515fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
268615fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
26875a18407fSRichard Henderson     return new_op;
26885a18407fSRichard Henderson }
26895a18407fSRichard Henderson 
2690b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
2691b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s)
2692b4fc67c7SRichard Henderson {
2693b4fc67c7SRichard Henderson     TCGOp *op, *op_next;
2694b4fc67c7SRichard Henderson     bool dead = false;
2695b4fc67c7SRichard Henderson 
2696b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
2697b4fc67c7SRichard Henderson         bool remove = dead;
2698b4fc67c7SRichard Henderson         TCGLabel *label;
2699b4fc67c7SRichard Henderson         int call_flags;
2700b4fc67c7SRichard Henderson 
2701b4fc67c7SRichard Henderson         switch (op->opc) {
2702b4fc67c7SRichard Henderson         case INDEX_op_set_label:
2703b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
2704b4fc67c7SRichard Henderson             if (label->refs == 0) {
2705b4fc67c7SRichard Henderson                 /*
2706b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
2707b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
2708b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
2709b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
2710b4fc67c7SRichard Henderson                  * little to be gained by iterating.
2711b4fc67c7SRichard Henderson                  */
2712b4fc67c7SRichard Henderson                 remove = true;
2713b4fc67c7SRichard Henderson             } else {
2714b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
2715b4fc67c7SRichard Henderson                 dead = false;
2716b4fc67c7SRichard Henderson                 remove = false;
2717b4fc67c7SRichard Henderson 
2718b4fc67c7SRichard Henderson                 /*
2719b4fc67c7SRichard Henderson                  * Optimization can fold conditional branches to unconditional.
2720b4fc67c7SRichard Henderson                  * If we find a label with one reference which is preceded by
2721b4fc67c7SRichard Henderson                  * an unconditional branch to it, remove both.  This needed to
2722b4fc67c7SRichard Henderson                  * wait until the dead code in between them was removed.
2723b4fc67c7SRichard Henderson                  */
2724b4fc67c7SRichard Henderson                 if (label->refs == 1) {
2725eae3eb3eSPaolo Bonzini                     TCGOp *op_prev = QTAILQ_PREV(op, link);
2726b4fc67c7SRichard Henderson                     if (op_prev->opc == INDEX_op_br &&
2727b4fc67c7SRichard Henderson                         label == arg_label(op_prev->args[0])) {
2728b4fc67c7SRichard Henderson                         tcg_op_remove(s, op_prev);
2729b4fc67c7SRichard Henderson                         remove = true;
2730b4fc67c7SRichard Henderson                     }
2731b4fc67c7SRichard Henderson                 }
2732b4fc67c7SRichard Henderson             }
2733b4fc67c7SRichard Henderson             break;
2734b4fc67c7SRichard Henderson 
2735b4fc67c7SRichard Henderson         case INDEX_op_br:
2736b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
2737b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
2738b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
2739b4fc67c7SRichard Henderson             dead = true;
2740b4fc67c7SRichard Henderson             break;
2741b4fc67c7SRichard Henderson 
2742b4fc67c7SRichard Henderson         case INDEX_op_call:
2743b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
2744b4fc67c7SRichard Henderson             call_flags = op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1];
2745b4fc67c7SRichard Henderson             if (call_flags & TCG_CALL_NO_RETURN) {
2746b4fc67c7SRichard Henderson                 dead = true;
2747b4fc67c7SRichard Henderson             }
2748b4fc67c7SRichard Henderson             break;
2749b4fc67c7SRichard Henderson 
2750b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
2751b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
2752b4fc67c7SRichard Henderson             remove = false;
2753b4fc67c7SRichard Henderson             break;
2754b4fc67c7SRichard Henderson 
2755b4fc67c7SRichard Henderson         default:
2756b4fc67c7SRichard Henderson             break;
2757b4fc67c7SRichard Henderson         }
2758b4fc67c7SRichard Henderson 
2759b4fc67c7SRichard Henderson         if (remove) {
2760b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
2761b4fc67c7SRichard Henderson         }
2762b4fc67c7SRichard Henderson     }
2763b4fc67c7SRichard Henderson }
2764b4fc67c7SRichard Henderson 
2765c70fbf0aSRichard Henderson #define TS_DEAD  1
2766c70fbf0aSRichard Henderson #define TS_MEM   2
2767c70fbf0aSRichard Henderson 
27685a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
27695a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
27705a18407fSRichard Henderson 
277125f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
277225f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
277325f49c5fSRichard Henderson {
277425f49c5fSRichard Henderson     return ts->state_ptr;
277525f49c5fSRichard Henderson }
277625f49c5fSRichard Henderson 
277725f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
277825f49c5fSRichard Henderson  * maximal regset for its type.
277925f49c5fSRichard Henderson  */
278025f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
278125f49c5fSRichard Henderson {
278225f49c5fSRichard Henderson     *la_temp_pref(ts)
278325f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
278425f49c5fSRichard Henderson }
278525f49c5fSRichard Henderson 
27869c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
27879c43b68dSAurelien Jarno    should be in memory. */
27882616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
2789c896fe29Sbellard {
2790b83eabeaSRichard Henderson     int i;
2791b83eabeaSRichard Henderson 
2792b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2793b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
279425f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2795b83eabeaSRichard Henderson     }
2796b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2797b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
279825f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2799b83eabeaSRichard Henderson     }
2800c896fe29Sbellard }
2801c896fe29Sbellard 
28029c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
28039c43b68dSAurelien Jarno    and local temps should be in memory. */
28042616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
2805641d5fbeSbellard {
2806b83eabeaSRichard Henderson     int i;
2807641d5fbeSbellard 
2808ee17db83SRichard Henderson     for (i = 0; i < nt; ++i) {
2809ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2810ee17db83SRichard Henderson         int state;
2811ee17db83SRichard Henderson 
2812ee17db83SRichard Henderson         switch (ts->kind) {
2813ee17db83SRichard Henderson         case TEMP_FIXED:
2814ee17db83SRichard Henderson         case TEMP_GLOBAL:
2815ee17db83SRichard Henderson         case TEMP_LOCAL:
2816ee17db83SRichard Henderson             state = TS_DEAD | TS_MEM;
2817ee17db83SRichard Henderson             break;
2818ee17db83SRichard Henderson         case TEMP_NORMAL:
2819c0522136SRichard Henderson         case TEMP_CONST:
2820ee17db83SRichard Henderson             state = TS_DEAD;
2821ee17db83SRichard Henderson             break;
2822ee17db83SRichard Henderson         default:
2823ee17db83SRichard Henderson             g_assert_not_reached();
2824c70fbf0aSRichard Henderson         }
2825ee17db83SRichard Henderson         ts->state = state;
2826ee17db83SRichard Henderson         la_reset_pref(ts);
2827641d5fbeSbellard     }
2828641d5fbeSbellard }
2829641d5fbeSbellard 
2830f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
2831f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
2832f65a061cSRichard Henderson {
2833f65a061cSRichard Henderson     int i;
2834f65a061cSRichard Henderson 
2835f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
283625f49c5fSRichard Henderson         int state = s->temps[i].state;
283725f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
283825f49c5fSRichard Henderson         if (state == TS_DEAD) {
283925f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
284025f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
284125f49c5fSRichard Henderson         }
2842f65a061cSRichard Henderson     }
2843f65a061cSRichard Henderson }
2844f65a061cSRichard Henderson 
2845b4cb76e6SRichard Henderson /*
2846b4cb76e6SRichard Henderson  * liveness analysis: conditional branch: all temps are dead,
2847b4cb76e6SRichard Henderson  * globals and local temps should be synced.
2848b4cb76e6SRichard Henderson  */
2849b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
2850b4cb76e6SRichard Henderson {
2851b4cb76e6SRichard Henderson     la_global_sync(s, ng);
2852b4cb76e6SRichard Henderson 
2853b4cb76e6SRichard Henderson     for (int i = ng; i < nt; ++i) {
2854c0522136SRichard Henderson         TCGTemp *ts = &s->temps[i];
2855c0522136SRichard Henderson         int state;
2856c0522136SRichard Henderson 
2857c0522136SRichard Henderson         switch (ts->kind) {
2858c0522136SRichard Henderson         case TEMP_LOCAL:
2859c0522136SRichard Henderson             state = ts->state;
2860c0522136SRichard Henderson             ts->state = state | TS_MEM;
2861b4cb76e6SRichard Henderson             if (state != TS_DEAD) {
2862b4cb76e6SRichard Henderson                 continue;
2863b4cb76e6SRichard Henderson             }
2864c0522136SRichard Henderson             break;
2865c0522136SRichard Henderson         case TEMP_NORMAL:
2866b4cb76e6SRichard Henderson             s->temps[i].state = TS_DEAD;
2867c0522136SRichard Henderson             break;
2868c0522136SRichard Henderson         case TEMP_CONST:
2869c0522136SRichard Henderson             continue;
2870c0522136SRichard Henderson         default:
2871c0522136SRichard Henderson             g_assert_not_reached();
2872b4cb76e6SRichard Henderson         }
2873b4cb76e6SRichard Henderson         la_reset_pref(&s->temps[i]);
2874b4cb76e6SRichard Henderson     }
2875b4cb76e6SRichard Henderson }
2876b4cb76e6SRichard Henderson 
2877f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
2878f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
2879f65a061cSRichard Henderson {
2880f65a061cSRichard Henderson     int i;
2881f65a061cSRichard Henderson 
2882f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
2883f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
288425f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
288525f49c5fSRichard Henderson     }
288625f49c5fSRichard Henderson }
288725f49c5fSRichard Henderson 
288825f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
288925f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
289025f49c5fSRichard Henderson {
289125f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
289225f49c5fSRichard Henderson     int i;
289325f49c5fSRichard Henderson 
289425f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
289525f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
289625f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
289725f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
289825f49c5fSRichard Henderson             TCGRegSet set = *pset;
289925f49c5fSRichard Henderson 
290025f49c5fSRichard Henderson             set &= mask;
290125f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
290225f49c5fSRichard Henderson             if (set == 0) {
290325f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
290425f49c5fSRichard Henderson             }
290525f49c5fSRichard Henderson             *pset = set;
290625f49c5fSRichard Henderson         }
2907f65a061cSRichard Henderson     }
2908f65a061cSRichard Henderson }
2909f65a061cSRichard Henderson 
2910a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
2911c896fe29Sbellard    given input arguments is dead. Instructions updating dead
2912c896fe29Sbellard    temporaries are removed. */
2913b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s)
2914c896fe29Sbellard {
2915c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
29162616c808SRichard Henderson     int nb_temps = s->nb_temps;
291715fa08f8SRichard Henderson     TCGOp *op, *op_prev;
291825f49c5fSRichard Henderson     TCGRegSet *prefs;
291925f49c5fSRichard Henderson     int i;
292025f49c5fSRichard Henderson 
292125f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
292225f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
292325f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
292425f49c5fSRichard Henderson     }
2925c896fe29Sbellard 
2926ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
29272616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
2928c896fe29Sbellard 
2929eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
293025f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
2931c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
2932c45cb8bbSRichard Henderson         bool have_opc_new2;
2933a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
293425f49c5fSRichard Henderson         TCGTemp *ts;
2935c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2936c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2937c45cb8bbSRichard Henderson 
2938c45cb8bbSRichard Henderson         switch (opc) {
2939c896fe29Sbellard         case INDEX_op_call:
2940c6e113f5Sbellard             {
2941c6e113f5Sbellard                 int call_flags;
294225f49c5fSRichard Henderson                 int nb_call_regs;
2943c6e113f5Sbellard 
2944cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
2945cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
2946efee3746SRichard Henderson                 call_flags = op->args[nb_oargs + nb_iargs + 1];
2947c6e113f5Sbellard 
2948c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
294978505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
2950c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
295125f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
295225f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
2953c6e113f5Sbellard                             goto do_not_remove_call;
2954c6e113f5Sbellard                         }
29559c43b68dSAurelien Jarno                     }
2956c45cb8bbSRichard Henderson                     goto do_remove;
2957152c35aaSRichard Henderson                 }
2958c6e113f5Sbellard             do_not_remove_call:
2959c896fe29Sbellard 
296025f49c5fSRichard Henderson                 /* Output args are dead.  */
2961c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
296225f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
296325f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
2964a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
29656b64b624SAurelien Jarno                     }
296625f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
2967a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
29689c43b68dSAurelien Jarno                     }
296925f49c5fSRichard Henderson                     ts->state = TS_DEAD;
297025f49c5fSRichard Henderson                     la_reset_pref(ts);
297125f49c5fSRichard Henderson 
297225f49c5fSRichard Henderson                     /* Not used -- it will be tcg_target_call_oarg_regs[i].  */
297325f49c5fSRichard Henderson                     op->output_pref[i] = 0;
2974c896fe29Sbellard                 }
2975c896fe29Sbellard 
297678505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
297778505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
2978f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
2979c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
2980f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
2981b9c18f56Saurel32                 }
2982c896fe29Sbellard 
298325f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
2984866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
298525f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
298625f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
2987a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
2988c896fe29Sbellard                     }
2989c896fe29Sbellard                 }
299025f49c5fSRichard Henderson 
299125f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
299225f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
299325f49c5fSRichard Henderson 
299425f49c5fSRichard Henderson                 nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
299525f49c5fSRichard Henderson 
299625f49c5fSRichard Henderson                 /* Input arguments are live for preceding opcodes.  */
299725f49c5fSRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
299825f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
299925f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
300025f49c5fSRichard Henderson                         /* For those arguments that die, and will be allocated
300125f49c5fSRichard Henderson                          * in registers, clear the register set for that arg,
300225f49c5fSRichard Henderson                          * to be filled in below.  For args that will be on
300325f49c5fSRichard Henderson                          * the stack, reset to any available reg.
300425f49c5fSRichard Henderson                          */
300525f49c5fSRichard Henderson                         *la_temp_pref(ts)
300625f49c5fSRichard Henderson                             = (i < nb_call_regs ? 0 :
300725f49c5fSRichard Henderson                                tcg_target_available_regs[ts->type]);
300825f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
300925f49c5fSRichard Henderson                     }
301025f49c5fSRichard Henderson                 }
301125f49c5fSRichard Henderson 
301225f49c5fSRichard Henderson                 /* For each input argument, add its input register to prefs.
301325f49c5fSRichard Henderson                    If a temp is used once, this produces a single set bit.  */
301425f49c5fSRichard Henderson                 for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) {
301525f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
301625f49c5fSRichard Henderson                     if (ts) {
301725f49c5fSRichard Henderson                         tcg_regset_set_reg(*la_temp_pref(ts),
301825f49c5fSRichard Henderson                                            tcg_target_call_iarg_regs[i]);
3019c70fbf0aSRichard Henderson                     }
3020c19f47bfSAurelien Jarno                 }
3021c6e113f5Sbellard             }
3022c896fe29Sbellard             break;
3023765b842aSRichard Henderson         case INDEX_op_insn_start:
3024c896fe29Sbellard             break;
30255ff9d6a4Sbellard         case INDEX_op_discard:
30265ff9d6a4Sbellard             /* mark the temporary as dead */
302725f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
302825f49c5fSRichard Henderson             ts->state = TS_DEAD;
302925f49c5fSRichard Henderson             la_reset_pref(ts);
30305ff9d6a4Sbellard             break;
30311305c451SRichard Henderson 
30321305c451SRichard Henderson         case INDEX_op_add2_i32:
3033c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
3034f1fae40cSRichard Henderson             goto do_addsub2;
30351305c451SRichard Henderson         case INDEX_op_sub2_i32:
3036c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
3037f1fae40cSRichard Henderson             goto do_addsub2;
3038f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
3039c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
3040f1fae40cSRichard Henderson             goto do_addsub2;
3041f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
3042c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
3043f1fae40cSRichard Henderson         do_addsub2:
30441305c451SRichard Henderson             nb_iargs = 4;
30451305c451SRichard Henderson             nb_oargs = 2;
30461305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
30471305c451SRichard Henderson                the low part.  The result can be optimized to a simple
30481305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
30491305c451SRichard Henderson                cpu mode is set to 32 bit.  */
3050b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
3051b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
30521305c451SRichard Henderson                     goto do_remove;
30531305c451SRichard Henderson                 }
3054c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
3055c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
3056c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
3057efee3746SRichard Henderson                 op->args[1] = op->args[2];
3058efee3746SRichard Henderson                 op->args[2] = op->args[4];
30591305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
30601305c451SRichard Henderson                 nb_iargs = 2;
30611305c451SRichard Henderson                 nb_oargs = 1;
30621305c451SRichard Henderson             }
30631305c451SRichard Henderson             goto do_not_remove;
30641305c451SRichard Henderson 
30651414968aSRichard Henderson         case INDEX_op_mulu2_i32:
3066c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
3067c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
3068c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
306903271524SRichard Henderson             goto do_mul2;
3070f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
3071c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
3072c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
3073c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
3074f1fae40cSRichard Henderson             goto do_mul2;
3075f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
3076c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
3077c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
3078c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
307903271524SRichard Henderson             goto do_mul2;
3080f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
3081c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
3082c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
3083c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
308403271524SRichard Henderson             goto do_mul2;
3085f1fae40cSRichard Henderson         do_mul2:
30861414968aSRichard Henderson             nb_iargs = 2;
30871414968aSRichard Henderson             nb_oargs = 2;
3088b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
3089b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
309003271524SRichard Henderson                     /* Both parts of the operation are dead.  */
30911414968aSRichard Henderson                     goto do_remove;
30921414968aSRichard Henderson                 }
309303271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
3094c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
3095efee3746SRichard Henderson                 op->args[1] = op->args[2];
3096efee3746SRichard Henderson                 op->args[2] = op->args[3];
3097b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
309803271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
3099c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
3100efee3746SRichard Henderson                 op->args[0] = op->args[1];
3101efee3746SRichard Henderson                 op->args[1] = op->args[2];
3102efee3746SRichard Henderson                 op->args[2] = op->args[3];
310303271524SRichard Henderson             } else {
310403271524SRichard Henderson                 goto do_not_remove;
310503271524SRichard Henderson             }
310603271524SRichard Henderson             /* Mark the single-word operation live.  */
31071414968aSRichard Henderson             nb_oargs = 1;
31081414968aSRichard Henderson             goto do_not_remove;
31091414968aSRichard Henderson 
3110c896fe29Sbellard         default:
31111305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
3112c896fe29Sbellard             nb_iargs = def->nb_iargs;
3113c896fe29Sbellard             nb_oargs = def->nb_oargs;
3114c896fe29Sbellard 
3115c896fe29Sbellard             /* Test if the operation can be removed because all
31165ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
31175ff9d6a4Sbellard                implies side effects */
31185ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
3119c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
3120b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
3121c896fe29Sbellard                         goto do_not_remove;
3122c896fe29Sbellard                     }
31239c43b68dSAurelien Jarno                 }
3124152c35aaSRichard Henderson                 goto do_remove;
3125152c35aaSRichard Henderson             }
3126152c35aaSRichard Henderson             goto do_not_remove;
3127152c35aaSRichard Henderson 
31281305c451SRichard Henderson         do_remove:
31290c627cdcSRichard Henderson             tcg_op_remove(s, op);
3130152c35aaSRichard Henderson             break;
3131152c35aaSRichard Henderson 
3132c896fe29Sbellard         do_not_remove:
3133c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
313425f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
313525f49c5fSRichard Henderson 
313625f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
313725f49c5fSRichard Henderson                 op->output_pref[i] = *la_temp_pref(ts);
313825f49c5fSRichard Henderson 
313925f49c5fSRichard Henderson                 /* Output args are dead.  */
314025f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
3141a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
31426b64b624SAurelien Jarno                 }
314325f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
3144a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
31459c43b68dSAurelien Jarno                 }
314625f49c5fSRichard Henderson                 ts->state = TS_DEAD;
314725f49c5fSRichard Henderson                 la_reset_pref(ts);
3148c896fe29Sbellard             }
3149c896fe29Sbellard 
315025f49c5fSRichard Henderson             /* If end of basic block, update.  */
3151ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
3152ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
3153b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_COND_BRANCH) {
3154b4cb76e6SRichard Henderson                 la_bb_sync(s, nb_globals, nb_temps);
3155ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
31562616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
31573d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
3158f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
315925f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
316025f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
316125f49c5fSRichard Henderson                 }
3162c896fe29Sbellard             }
3163c896fe29Sbellard 
316425f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
3165866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
316625f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
316725f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
3168a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
3169c896fe29Sbellard                 }
3170c19f47bfSAurelien Jarno             }
317125f49c5fSRichard Henderson 
317225f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
3173c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
317425f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
317525f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
317625f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
317725f49c5fSRichard Henderson                        all regs for the type.  */
317825f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
317925f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
318025f49c5fSRichard Henderson                 }
318125f49c5fSRichard Henderson             }
318225f49c5fSRichard Henderson 
318325f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
318425f49c5fSRichard Henderson             switch (opc) {
318525f49c5fSRichard Henderson             case INDEX_op_mov_i32:
318625f49c5fSRichard Henderson             case INDEX_op_mov_i64:
318725f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
318825f49c5fSRichard Henderson                    have proper constraints.  That said, special case
318925f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
319025f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
319125f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
319225f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
319325f49c5fSRichard Henderson                 }
319425f49c5fSRichard Henderson                 break;
319525f49c5fSRichard Henderson 
319625f49c5fSRichard Henderson             default:
319725f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
319825f49c5fSRichard Henderson                     const TCGArgConstraint *ct = &def->args_ct[i];
319925f49c5fSRichard Henderson                     TCGRegSet set, *pset;
320025f49c5fSRichard Henderson 
320125f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
320225f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
320325f49c5fSRichard Henderson                     set = *pset;
320425f49c5fSRichard Henderson 
32059be0d080SRichard Henderson                     set &= ct->regs;
3206bc2b17e6SRichard Henderson                     if (ct->ialias) {
320725f49c5fSRichard Henderson                         set &= op->output_pref[ct->alias_index];
320825f49c5fSRichard Henderson                     }
320925f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
321025f49c5fSRichard Henderson                     if (set == 0) {
32119be0d080SRichard Henderson                         set = ct->regs;
321225f49c5fSRichard Henderson                     }
321325f49c5fSRichard Henderson                     *pset = set;
321425f49c5fSRichard Henderson                 }
321525f49c5fSRichard Henderson                 break;
3216c896fe29Sbellard             }
3217c896fe29Sbellard             break;
3218c896fe29Sbellard         }
3219bee158cbSRichard Henderson         op->life = arg_life;
3220c896fe29Sbellard     }
32211ff0a2c5SEvgeny Voevodin }
3222c896fe29Sbellard 
32235a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
3224b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s)
32255a18407fSRichard Henderson {
32265a18407fSRichard Henderson     int nb_globals = s->nb_globals;
322715fa08f8SRichard Henderson     int nb_temps, i;
32285a18407fSRichard Henderson     bool changes = false;
322915fa08f8SRichard Henderson     TCGOp *op, *op_next;
32305a18407fSRichard Henderson 
32315a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
32325a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
32335a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
32345a18407fSRichard Henderson         if (its->indirect_reg) {
32355a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
32365a18407fSRichard Henderson             dts->type = its->type;
32375a18407fSRichard Henderson             dts->base_type = its->base_type;
3238b83eabeaSRichard Henderson             its->state_ptr = dts;
3239b83eabeaSRichard Henderson         } else {
3240b83eabeaSRichard Henderson             its->state_ptr = NULL;
32415a18407fSRichard Henderson         }
3242b83eabeaSRichard Henderson         /* All globals begin dead.  */
3243b83eabeaSRichard Henderson         its->state = TS_DEAD;
32445a18407fSRichard Henderson     }
3245b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
3246b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
3247b83eabeaSRichard Henderson         its->state_ptr = NULL;
3248b83eabeaSRichard Henderson         its->state = TS_DEAD;
3249b83eabeaSRichard Henderson     }
32505a18407fSRichard Henderson 
325115fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
32525a18407fSRichard Henderson         TCGOpcode opc = op->opc;
32535a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
32545a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
32555a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
3256b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
32575a18407fSRichard Henderson 
32585a18407fSRichard Henderson         if (opc == INDEX_op_call) {
3259cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
3260cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
3261efee3746SRichard Henderson             call_flags = op->args[nb_oargs + nb_iargs + 1];
32625a18407fSRichard Henderson         } else {
32635a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
32645a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
32655a18407fSRichard Henderson 
32665a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
3267b4cb76e6SRichard Henderson             if (def->flags & TCG_OPF_COND_BRANCH) {
3268b4cb76e6SRichard Henderson                 /* Like reading globals: sync_globals */
3269b4cb76e6SRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
3270b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
32715a18407fSRichard Henderson                 /* Like writing globals: save_globals */
32725a18407fSRichard Henderson                 call_flags = 0;
32735a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
32745a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
32755a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
32765a18407fSRichard Henderson             } else {
32775a18407fSRichard Henderson                 /* No effect on globals.  */
32785a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
32795a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
32805a18407fSRichard Henderson             }
32815a18407fSRichard Henderson         }
32825a18407fSRichard Henderson 
32835a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
32845a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3285b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3286b83eabeaSRichard Henderson             if (arg_ts) {
3287b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3288b83eabeaSRichard Henderson                 if (dir_ts && arg_ts->state == TS_DEAD) {
3289b83eabeaSRichard Henderson                     TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
32905a18407fSRichard Henderson                                       ? INDEX_op_ld_i32
32915a18407fSRichard Henderson                                       : INDEX_op_ld_i64);
3292ac1043f6SEmilio G. Cota                     TCGOp *lop = tcg_op_insert_before(s, op, lopc);
32935a18407fSRichard Henderson 
3294b83eabeaSRichard Henderson                     lop->args[0] = temp_arg(dir_ts);
3295b83eabeaSRichard Henderson                     lop->args[1] = temp_arg(arg_ts->mem_base);
3296b83eabeaSRichard Henderson                     lop->args[2] = arg_ts->mem_offset;
32975a18407fSRichard Henderson 
32985a18407fSRichard Henderson                     /* Loaded, but synced with memory.  */
3299b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
33005a18407fSRichard Henderson                 }
33015a18407fSRichard Henderson             }
33025a18407fSRichard Henderson         }
33035a18407fSRichard Henderson 
33045a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
33055a18407fSRichard Henderson            No action is required except keeping temp_state up to date
33065a18407fSRichard Henderson            so that we reload when needed.  */
33075a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3308b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3309b83eabeaSRichard Henderson             if (arg_ts) {
3310b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3311b83eabeaSRichard Henderson                 if (dir_ts) {
3312b83eabeaSRichard Henderson                     op->args[i] = temp_arg(dir_ts);
33135a18407fSRichard Henderson                     changes = true;
33145a18407fSRichard Henderson                     if (IS_DEAD_ARG(i)) {
3315b83eabeaSRichard Henderson                         arg_ts->state = TS_DEAD;
33165a18407fSRichard Henderson                     }
33175a18407fSRichard Henderson                 }
33185a18407fSRichard Henderson             }
33195a18407fSRichard Henderson         }
33205a18407fSRichard Henderson 
33215a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
33225a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
33235a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
33245a18407fSRichard Henderson             /* Nothing to do */
33255a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
33265a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
33275a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
33285a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
3329b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3330b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3331b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
33325a18407fSRichard Henderson             }
33335a18407fSRichard Henderson         } else {
33345a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
33355a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
33365a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
3337b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3338b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3339b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
33405a18407fSRichard Henderson             }
33415a18407fSRichard Henderson         }
33425a18407fSRichard Henderson 
33435a18407fSRichard Henderson         /* Outputs become available.  */
334461f15c48SRichard Henderson         if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) {
334561f15c48SRichard Henderson             arg_ts = arg_temp(op->args[0]);
334661f15c48SRichard Henderson             dir_ts = arg_ts->state_ptr;
334761f15c48SRichard Henderson             if (dir_ts) {
334861f15c48SRichard Henderson                 op->args[0] = temp_arg(dir_ts);
334961f15c48SRichard Henderson                 changes = true;
335061f15c48SRichard Henderson 
335161f15c48SRichard Henderson                 /* The output is now live and modified.  */
335261f15c48SRichard Henderson                 arg_ts->state = 0;
335361f15c48SRichard Henderson 
335461f15c48SRichard Henderson                 if (NEED_SYNC_ARG(0)) {
335561f15c48SRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
335661f15c48SRichard Henderson                                       ? INDEX_op_st_i32
335761f15c48SRichard Henderson                                       : INDEX_op_st_i64);
335861f15c48SRichard Henderson                     TCGOp *sop = tcg_op_insert_after(s, op, sopc);
335961f15c48SRichard Henderson                     TCGTemp *out_ts = dir_ts;
336061f15c48SRichard Henderson 
336161f15c48SRichard Henderson                     if (IS_DEAD_ARG(0)) {
336261f15c48SRichard Henderson                         out_ts = arg_temp(op->args[1]);
336361f15c48SRichard Henderson                         arg_ts->state = TS_DEAD;
336461f15c48SRichard Henderson                         tcg_op_remove(s, op);
336561f15c48SRichard Henderson                     } else {
336661f15c48SRichard Henderson                         arg_ts->state = TS_MEM;
336761f15c48SRichard Henderson                     }
336861f15c48SRichard Henderson 
336961f15c48SRichard Henderson                     sop->args[0] = temp_arg(out_ts);
337061f15c48SRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
337161f15c48SRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
337261f15c48SRichard Henderson                 } else {
337361f15c48SRichard Henderson                     tcg_debug_assert(!IS_DEAD_ARG(0));
337461f15c48SRichard Henderson                 }
337561f15c48SRichard Henderson             }
337661f15c48SRichard Henderson         } else {
33775a18407fSRichard Henderson             for (i = 0; i < nb_oargs; i++) {
3378b83eabeaSRichard Henderson                 arg_ts = arg_temp(op->args[i]);
3379b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3380b83eabeaSRichard Henderson                 if (!dir_ts) {
33815a18407fSRichard Henderson                     continue;
33825a18407fSRichard Henderson                 }
3383b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
33845a18407fSRichard Henderson                 changes = true;
33855a18407fSRichard Henderson 
33865a18407fSRichard Henderson                 /* The output is now live and modified.  */
3387b83eabeaSRichard Henderson                 arg_ts->state = 0;
33885a18407fSRichard Henderson 
33895a18407fSRichard Henderson                 /* Sync outputs upon their last write.  */
33905a18407fSRichard Henderson                 if (NEED_SYNC_ARG(i)) {
3391b83eabeaSRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
33925a18407fSRichard Henderson                                       ? INDEX_op_st_i32
33935a18407fSRichard Henderson                                       : INDEX_op_st_i64);
3394ac1043f6SEmilio G. Cota                     TCGOp *sop = tcg_op_insert_after(s, op, sopc);
33955a18407fSRichard Henderson 
3396b83eabeaSRichard Henderson                     sop->args[0] = temp_arg(dir_ts);
3397b83eabeaSRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
3398b83eabeaSRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
33995a18407fSRichard Henderson 
3400b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
34015a18407fSRichard Henderson                 }
34025a18407fSRichard Henderson                 /* Drop outputs that are dead.  */
34035a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3404b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
34055a18407fSRichard Henderson                 }
34065a18407fSRichard Henderson             }
34075a18407fSRichard Henderson         }
340861f15c48SRichard Henderson     }
34095a18407fSRichard Henderson 
34105a18407fSRichard Henderson     return changes;
34115a18407fSRichard Henderson }
34125a18407fSRichard Henderson 
34138d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
3414c896fe29Sbellard static void dump_regs(TCGContext *s)
3415c896fe29Sbellard {
3416c896fe29Sbellard     TCGTemp *ts;
3417c896fe29Sbellard     int i;
3418c896fe29Sbellard     char buf[64];
3419c896fe29Sbellard 
3420c896fe29Sbellard     for(i = 0; i < s->nb_temps; i++) {
3421c896fe29Sbellard         ts = &s->temps[i];
342243439139SRichard Henderson         printf("  %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3423c896fe29Sbellard         switch(ts->val_type) {
3424c896fe29Sbellard         case TEMP_VAL_REG:
3425c896fe29Sbellard             printf("%s", tcg_target_reg_names[ts->reg]);
3426c896fe29Sbellard             break;
3427c896fe29Sbellard         case TEMP_VAL_MEM:
3428b3a62939SRichard Henderson             printf("%d(%s)", (int)ts->mem_offset,
3429b3a62939SRichard Henderson                    tcg_target_reg_names[ts->mem_base->reg]);
3430c896fe29Sbellard             break;
3431c896fe29Sbellard         case TEMP_VAL_CONST:
3432bdb38b95SRichard Henderson             printf("$0x%" PRIx64, ts->val);
3433c896fe29Sbellard             break;
3434c896fe29Sbellard         case TEMP_VAL_DEAD:
3435c896fe29Sbellard             printf("D");
3436c896fe29Sbellard             break;
3437c896fe29Sbellard         default:
3438c896fe29Sbellard             printf("???");
3439c896fe29Sbellard             break;
3440c896fe29Sbellard         }
3441c896fe29Sbellard         printf("\n");
3442c896fe29Sbellard     }
3443c896fe29Sbellard 
3444c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
3445f8b2f202SRichard Henderson         if (s->reg_to_temp[i] != NULL) {
3446c896fe29Sbellard             printf("%s: %s\n",
3447c896fe29Sbellard                    tcg_target_reg_names[i],
3448f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i]));
3449c896fe29Sbellard         }
3450c896fe29Sbellard     }
3451c896fe29Sbellard }
3452c896fe29Sbellard 
3453c896fe29Sbellard static void check_regs(TCGContext *s)
3454c896fe29Sbellard {
3455869938aeSRichard Henderson     int reg;
3456b6638662SRichard Henderson     int k;
3457c896fe29Sbellard     TCGTemp *ts;
3458c896fe29Sbellard     char buf[64];
3459c896fe29Sbellard 
3460c896fe29Sbellard     for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
3461f8b2f202SRichard Henderson         ts = s->reg_to_temp[reg];
3462f8b2f202SRichard Henderson         if (ts != NULL) {
3463f8b2f202SRichard Henderson             if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) {
3464c896fe29Sbellard                 printf("Inconsistency for register %s:\n",
3465c896fe29Sbellard                        tcg_target_reg_names[reg]);
3466b03cce8eSbellard                 goto fail;
3467c896fe29Sbellard             }
3468c896fe29Sbellard         }
3469c896fe29Sbellard     }
3470c896fe29Sbellard     for (k = 0; k < s->nb_temps; k++) {
3471c896fe29Sbellard         ts = &s->temps[k];
3472ee17db83SRichard Henderson         if (ts->val_type == TEMP_VAL_REG
3473ee17db83SRichard Henderson             && ts->kind != TEMP_FIXED
3474f8b2f202SRichard Henderson             && s->reg_to_temp[ts->reg] != ts) {
3475c896fe29Sbellard             printf("Inconsistency for temp %s:\n",
3476f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3477b03cce8eSbellard         fail:
3478c896fe29Sbellard             printf("reg state:\n");
3479c896fe29Sbellard             dump_regs(s);
3480c896fe29Sbellard             tcg_abort();
3481c896fe29Sbellard         }
3482c896fe29Sbellard     }
3483c896fe29Sbellard }
3484c896fe29Sbellard #endif
3485c896fe29Sbellard 
34862272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
3487c896fe29Sbellard {
34889b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64)
34899b9c37c3SRichard Henderson     /* Sparc64 stack is accessed with offset of 2047 */
3490b591dc59SBlue Swirl     s->current_frame_offset = (s->current_frame_offset +
3491b591dc59SBlue Swirl                                (tcg_target_long)sizeof(tcg_target_long) - 1) &
3492b591dc59SBlue Swirl         ~(sizeof(tcg_target_long) - 1);
3493f44c9960SBlue Swirl #endif
3494b591dc59SBlue Swirl     if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
3495b591dc59SBlue Swirl         s->frame_end) {
34965ff9d6a4Sbellard         tcg_abort();
3497b591dc59SBlue Swirl     }
3498c896fe29Sbellard     ts->mem_offset = s->current_frame_offset;
3499b3a62939SRichard Henderson     ts->mem_base = s->frame_temp;
3500c896fe29Sbellard     ts->mem_allocated = 1;
3501e2c6d1b4SRichard Henderson     s->current_frame_offset += sizeof(tcg_target_long);
3502c896fe29Sbellard }
3503c896fe29Sbellard 
3504b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
3505b3915dbbSRichard Henderson 
350659d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
350759d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
350859d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
3509c896fe29Sbellard {
3510c0522136SRichard Henderson     TCGTempVal new_type;
3511c0522136SRichard Henderson 
3512c0522136SRichard Henderson     switch (ts->kind) {
3513c0522136SRichard Henderson     case TEMP_FIXED:
351459d7c14eSRichard Henderson         return;
3515c0522136SRichard Henderson     case TEMP_GLOBAL:
3516c0522136SRichard Henderson     case TEMP_LOCAL:
3517c0522136SRichard Henderson         new_type = TEMP_VAL_MEM;
3518c0522136SRichard Henderson         break;
3519c0522136SRichard Henderson     case TEMP_NORMAL:
3520c0522136SRichard Henderson         new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD;
3521c0522136SRichard Henderson         break;
3522c0522136SRichard Henderson     case TEMP_CONST:
3523c0522136SRichard Henderson         new_type = TEMP_VAL_CONST;
3524c0522136SRichard Henderson         break;
3525c0522136SRichard Henderson     default:
3526c0522136SRichard Henderson         g_assert_not_reached();
352759d7c14eSRichard Henderson     }
352859d7c14eSRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
352959d7c14eSRichard Henderson         s->reg_to_temp[ts->reg] = NULL;
353059d7c14eSRichard Henderson     }
3531c0522136SRichard Henderson     ts->val_type = new_type;
353259d7c14eSRichard Henderson }
3533c896fe29Sbellard 
353459d7c14eSRichard Henderson /* Mark a temporary as dead.  */
353559d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
353659d7c14eSRichard Henderson {
353759d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
353859d7c14eSRichard Henderson }
353959d7c14eSRichard Henderson 
354059d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
354159d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
354259d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
354359d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
354498b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
354598b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
354659d7c14eSRichard Henderson {
3547c0522136SRichard Henderson     if (!temp_readonly(ts) && !ts->mem_coherent) {
35487f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
35492272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
355059d7c14eSRichard Henderson         }
355159d7c14eSRichard Henderson         switch (ts->val_type) {
355259d7c14eSRichard Henderson         case TEMP_VAL_CONST:
355359d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
355459d7c14eSRichard Henderson                require it later in a register, so attempt to store the
355559d7c14eSRichard Henderson                constant to memory directly.  */
355659d7c14eSRichard Henderson             if (free_or_dead
355759d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
355859d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
355959d7c14eSRichard Henderson                 break;
356059d7c14eSRichard Henderson             }
356159d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
356298b4e186SRichard Henderson                       allocated_regs, preferred_regs);
356359d7c14eSRichard Henderson             /* fallthrough */
356459d7c14eSRichard Henderson 
356559d7c14eSRichard Henderson         case TEMP_VAL_REG:
356659d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
356759d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
356859d7c14eSRichard Henderson             break;
356959d7c14eSRichard Henderson 
357059d7c14eSRichard Henderson         case TEMP_VAL_MEM:
357159d7c14eSRichard Henderson             break;
357259d7c14eSRichard Henderson 
357359d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
357459d7c14eSRichard Henderson         default:
357559d7c14eSRichard Henderson             tcg_abort();
3576c896fe29Sbellard         }
35777f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
35787f6ceedfSAurelien Jarno     }
357959d7c14eSRichard Henderson     if (free_or_dead) {
358059d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
358159d7c14eSRichard Henderson     }
358259d7c14eSRichard Henderson }
35837f6ceedfSAurelien Jarno 
35847f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
3585b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
35867f6ceedfSAurelien Jarno {
3587f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
3588f8b2f202SRichard Henderson     if (ts != NULL) {
358998b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
3590c896fe29Sbellard     }
3591c896fe29Sbellard }
3592c896fe29Sbellard 
3593b016486eSRichard Henderson /**
3594b016486eSRichard Henderson  * tcg_reg_alloc:
3595b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
3596b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
3597b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
3598b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
3599b016486eSRichard Henderson  *
3600b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
3601b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
3602b016486eSRichard Henderson  */
3603b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
3604b016486eSRichard Henderson                             TCGRegSet allocated_regs,
3605b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
3606c896fe29Sbellard {
3607b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
3608b016486eSRichard Henderson     TCGRegSet reg_ct[2];
360991478cefSRichard Henderson     const int *order;
3610c896fe29Sbellard 
3611b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
3612b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
3613b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
3614b016486eSRichard Henderson 
3615b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
3616b016486eSRichard Henderson        or if the preference made no difference.  */
3617b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
3618b016486eSRichard Henderson 
361991478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
3620c896fe29Sbellard 
3621b016486eSRichard Henderson     /* Try free registers, preferences first.  */
3622b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3623b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3624b016486eSRichard Henderson 
3625b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3626b016486eSRichard Henderson             /* One register in the set.  */
3627b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3628b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
3629c896fe29Sbellard                 return reg;
3630c896fe29Sbellard             }
3631b016486eSRichard Henderson         } else {
363291478cefSRichard Henderson             for (i = 0; i < n; i++) {
3633b016486eSRichard Henderson                 TCGReg reg = order[i];
3634b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
3635b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
3636b016486eSRichard Henderson                     return reg;
3637b016486eSRichard Henderson                 }
3638b016486eSRichard Henderson             }
3639b016486eSRichard Henderson         }
3640b016486eSRichard Henderson     }
3641b016486eSRichard Henderson 
3642b016486eSRichard Henderson     /* We must spill something.  */
3643b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3644b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3645b016486eSRichard Henderson 
3646b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3647b016486eSRichard Henderson             /* One register in the set.  */
3648b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3649b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
3650c896fe29Sbellard             return reg;
3651b016486eSRichard Henderson         } else {
3652b016486eSRichard Henderson             for (i = 0; i < n; i++) {
3653b016486eSRichard Henderson                 TCGReg reg = order[i];
3654b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
3655b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
3656b016486eSRichard Henderson                     return reg;
3657b016486eSRichard Henderson                 }
3658b016486eSRichard Henderson             }
3659c896fe29Sbellard         }
3660c896fe29Sbellard     }
3661c896fe29Sbellard 
3662c896fe29Sbellard     tcg_abort();
3663c896fe29Sbellard }
3664c896fe29Sbellard 
366540ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
366640ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
366740ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
3668b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
366940ae5c62SRichard Henderson {
367040ae5c62SRichard Henderson     TCGReg reg;
367140ae5c62SRichard Henderson 
367240ae5c62SRichard Henderson     switch (ts->val_type) {
367340ae5c62SRichard Henderson     case TEMP_VAL_REG:
367440ae5c62SRichard Henderson         return;
367540ae5c62SRichard Henderson     case TEMP_VAL_CONST:
3676b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3677b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
36780a6a8bc8SRichard Henderson         if (ts->type <= TCG_TYPE_I64) {
367940ae5c62SRichard Henderson             tcg_out_movi(s, ts->type, reg, ts->val);
36800a6a8bc8SRichard Henderson         } else {
36814e186175SRichard Henderson             uint64_t val = ts->val;
36824e186175SRichard Henderson             MemOp vece = MO_64;
36834e186175SRichard Henderson 
36844e186175SRichard Henderson             /*
36854e186175SRichard Henderson              * Find the minimal vector element that matches the constant.
36864e186175SRichard Henderson              * The targets will, in general, have to do this search anyway,
36874e186175SRichard Henderson              * do this generically.
36884e186175SRichard Henderson              */
36894e186175SRichard Henderson             if (val == dup_const(MO_8, val)) {
36904e186175SRichard Henderson                 vece = MO_8;
36914e186175SRichard Henderson             } else if (val == dup_const(MO_16, val)) {
36924e186175SRichard Henderson                 vece = MO_16;
36930b4286ddSRichard Henderson             } else if (val == dup_const(MO_32, val)) {
36944e186175SRichard Henderson                 vece = MO_32;
36954e186175SRichard Henderson             }
36964e186175SRichard Henderson 
36974e186175SRichard Henderson             tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val);
36980a6a8bc8SRichard Henderson         }
369940ae5c62SRichard Henderson         ts->mem_coherent = 0;
370040ae5c62SRichard Henderson         break;
370140ae5c62SRichard Henderson     case TEMP_VAL_MEM:
3702b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3703b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
370440ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
370540ae5c62SRichard Henderson         ts->mem_coherent = 1;
370640ae5c62SRichard Henderson         break;
370740ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
370840ae5c62SRichard Henderson     default:
370940ae5c62SRichard Henderson         tcg_abort();
371040ae5c62SRichard Henderson     }
371140ae5c62SRichard Henderson     ts->reg = reg;
371240ae5c62SRichard Henderson     ts->val_type = TEMP_VAL_REG;
371340ae5c62SRichard Henderson     s->reg_to_temp[reg] = ts;
371440ae5c62SRichard Henderson }
371540ae5c62SRichard Henderson 
371659d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
3717e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
371859d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
37191ad80729SAurelien Jarno {
37202c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
3721eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
3722e01fa97dSRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts));
37231ad80729SAurelien Jarno }
37241ad80729SAurelien Jarno 
37259814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
3726641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
3727641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
3728641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
3729641d5fbeSbellard {
3730ac3b8891SRichard Henderson     int i, n;
3731641d5fbeSbellard 
3732ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
3733b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
3734641d5fbeSbellard     }
3735e5097dc8Sbellard }
3736e5097dc8Sbellard 
37373d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
37383d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
37393d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
37403d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
37413d5c5f87SAurelien Jarno {
3742ac3b8891SRichard Henderson     int i, n;
37433d5c5f87SAurelien Jarno 
3744ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
374512b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
374612b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
3747ee17db83SRichard Henderson                          || ts->kind == TEMP_FIXED
374812b9b11aSRichard Henderson                          || ts->mem_coherent);
37493d5c5f87SAurelien Jarno     }
37503d5c5f87SAurelien Jarno }
37513d5c5f87SAurelien Jarno 
3752e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
3753e8996ee0Sbellard    all globals are stored at their canonical location. */
3754e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
3755e5097dc8Sbellard {
3756e5097dc8Sbellard     int i;
3757e5097dc8Sbellard 
3758c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
3759b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
3760c0522136SRichard Henderson 
3761c0522136SRichard Henderson         switch (ts->kind) {
3762c0522136SRichard Henderson         case TEMP_LOCAL:
3763b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
3764c0522136SRichard Henderson             break;
3765c0522136SRichard Henderson         case TEMP_NORMAL:
37662c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
3767eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
3768eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3769c0522136SRichard Henderson             break;
3770c0522136SRichard Henderson         case TEMP_CONST:
3771c0522136SRichard Henderson             /* Similarly, we should have freed any allocated register. */
3772c0522136SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_CONST);
3773c0522136SRichard Henderson             break;
3774c0522136SRichard Henderson         default:
3775c0522136SRichard Henderson             g_assert_not_reached();
3776c896fe29Sbellard         }
3777641d5fbeSbellard     }
3778e8996ee0Sbellard 
3779e8996ee0Sbellard     save_globals(s, allocated_regs);
3780c896fe29Sbellard }
3781c896fe29Sbellard 
3782bab1671fSRichard Henderson /*
3783b4cb76e6SRichard Henderson  * At a conditional branch, we assume all temporaries are dead and
3784b4cb76e6SRichard Henderson  * all globals and local temps are synced to their location.
3785b4cb76e6SRichard Henderson  */
3786b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
3787b4cb76e6SRichard Henderson {
3788b4cb76e6SRichard Henderson     sync_globals(s, allocated_regs);
3789b4cb76e6SRichard Henderson 
3790b4cb76e6SRichard Henderson     for (int i = s->nb_globals; i < s->nb_temps; i++) {
3791b4cb76e6SRichard Henderson         TCGTemp *ts = &s->temps[i];
3792b4cb76e6SRichard Henderson         /*
3793b4cb76e6SRichard Henderson          * The liveness analysis already ensures that temps are dead.
3794b4cb76e6SRichard Henderson          * Keep tcg_debug_asserts for safety.
3795b4cb76e6SRichard Henderson          */
3796c0522136SRichard Henderson         switch (ts->kind) {
3797c0522136SRichard Henderson         case TEMP_LOCAL:
3798b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
3799c0522136SRichard Henderson             break;
3800c0522136SRichard Henderson         case TEMP_NORMAL:
3801b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3802c0522136SRichard Henderson             break;
3803c0522136SRichard Henderson         case TEMP_CONST:
3804c0522136SRichard Henderson             break;
3805c0522136SRichard Henderson         default:
3806c0522136SRichard Henderson             g_assert_not_reached();
3807b4cb76e6SRichard Henderson         }
3808b4cb76e6SRichard Henderson     }
3809b4cb76e6SRichard Henderson }
3810b4cb76e6SRichard Henderson 
3811b4cb76e6SRichard Henderson /*
3812c58f4c97SRichard Henderson  * Specialized code generation for INDEX_op_mov_* with a constant.
3813bab1671fSRichard Henderson  */
38140fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
3815ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
3816ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
3817e8996ee0Sbellard {
3818d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3819e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
382059d7c14eSRichard Henderson 
382159d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
3822f8b2f202SRichard Henderson     if (ots->val_type == TEMP_VAL_REG) {
3823f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = NULL;
3824f8b2f202SRichard Henderson     }
3825e8996ee0Sbellard     ots->val_type = TEMP_VAL_CONST;
3826e8996ee0Sbellard     ots->val = val;
382759d7c14eSRichard Henderson     ots->mem_coherent = 0;
3828ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
3829ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
383059d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
3831f8bf00f1SRichard Henderson         temp_dead(s, ots);
38324c4e1ab2SAurelien Jarno     }
3833e8996ee0Sbellard }
3834e8996ee0Sbellard 
3835bab1671fSRichard Henderson /*
3836bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
3837bab1671fSRichard Henderson  */
3838dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
3839c896fe29Sbellard {
3840dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
384169e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
3842c896fe29Sbellard     TCGTemp *ts, *ots;
3843450445d5SRichard Henderson     TCGType otype, itype;
3844c896fe29Sbellard 
3845d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
384669e3706dSRichard Henderson     preferred_regs = op->output_pref[0];
384743439139SRichard Henderson     ots = arg_temp(op->args[0]);
384843439139SRichard Henderson     ts = arg_temp(op->args[1]);
3849450445d5SRichard Henderson 
3850d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3851e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
3852d63e3b6eSRichard Henderson 
3853450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
3854450445d5SRichard Henderson     otype = ots->type;
3855450445d5SRichard Henderson     itype = ts->type;
3856c896fe29Sbellard 
38570fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
38580fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
38590fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
38600fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
38610fe4fca4SPaolo Bonzini             temp_dead(s, ts);
38620fe4fca4SPaolo Bonzini         }
386369e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
38640fe4fca4SPaolo Bonzini         return;
38650fe4fca4SPaolo Bonzini     }
38660fe4fca4SPaolo Bonzini 
38670fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
38680fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
38690fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
38700fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
38710fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
387269e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
387369e3706dSRichard Henderson                   allocated_regs, preferred_regs);
3874c29c1d7eSAurelien Jarno     }
3875c29c1d7eSAurelien Jarno 
38760fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
3877d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
3878c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
3879c29c1d7eSAurelien Jarno            liveness analysis disabled). */
3880eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
3881c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
38822272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
3883c29c1d7eSAurelien Jarno         }
3884b3a62939SRichard Henderson         tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset);
3885c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
3886f8bf00f1SRichard Henderson             temp_dead(s, ts);
3887c29c1d7eSAurelien Jarno         }
3888f8bf00f1SRichard Henderson         temp_dead(s, ots);
3889e8996ee0Sbellard     } else {
3890ee17db83SRichard Henderson         if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) {
3891c29c1d7eSAurelien Jarno             /* the mov can be suppressed */
3892c29c1d7eSAurelien Jarno             if (ots->val_type == TEMP_VAL_REG) {
3893f8b2f202SRichard Henderson                 s->reg_to_temp[ots->reg] = NULL;
3894c896fe29Sbellard             }
3895c29c1d7eSAurelien Jarno             ots->reg = ts->reg;
3896f8bf00f1SRichard Henderson             temp_dead(s, ts);
3897c29c1d7eSAurelien Jarno         } else {
3898c29c1d7eSAurelien Jarno             if (ots->val_type != TEMP_VAL_REG) {
3899c29c1d7eSAurelien Jarno                 /* When allocating a new register, make sure to not spill the
3900c29c1d7eSAurelien Jarno                    input one. */
3901c29c1d7eSAurelien Jarno                 tcg_regset_set_reg(allocated_regs, ts->reg);
3902450445d5SRichard Henderson                 ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
390369e3706dSRichard Henderson                                          allocated_regs, preferred_regs,
3904b016486eSRichard Henderson                                          ots->indirect_base);
3905c29c1d7eSAurelien Jarno             }
390678113e83SRichard Henderson             if (!tcg_out_mov(s, otype, ots->reg, ts->reg)) {
3907240c08d0SRichard Henderson                 /*
3908240c08d0SRichard Henderson                  * Cross register class move not supported.
3909240c08d0SRichard Henderson                  * Store the source register into the destination slot
3910240c08d0SRichard Henderson                  * and leave the destination temp as TEMP_VAL_MEM.
3911240c08d0SRichard Henderson                  */
3912e01fa97dSRichard Henderson                 assert(!temp_readonly(ots));
3913240c08d0SRichard Henderson                 if (!ts->mem_allocated) {
3914240c08d0SRichard Henderson                     temp_allocate_frame(s, ots);
3915240c08d0SRichard Henderson                 }
3916240c08d0SRichard Henderson                 tcg_out_st(s, ts->type, ts->reg,
3917240c08d0SRichard Henderson                            ots->mem_base->reg, ots->mem_offset);
3918240c08d0SRichard Henderson                 ots->mem_coherent = 1;
3919240c08d0SRichard Henderson                 temp_free_or_dead(s, ots, -1);
3920240c08d0SRichard Henderson                 return;
392178113e83SRichard Henderson             }
3922c29c1d7eSAurelien Jarno         }
3923c896fe29Sbellard         ots->val_type = TEMP_VAL_REG;
3924c896fe29Sbellard         ots->mem_coherent = 0;
3925f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3926ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(0)) {
392798b4e186SRichard Henderson             temp_sync(s, ots, allocated_regs, 0, 0);
3928c29c1d7eSAurelien Jarno         }
3929ec7a869dSAurelien Jarno     }
3930c896fe29Sbellard }
3931c896fe29Sbellard 
3932bab1671fSRichard Henderson /*
3933bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
3934bab1671fSRichard Henderson  */
3935bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
3936bab1671fSRichard Henderson {
3937bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
3938bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
3939bab1671fSRichard Henderson     TCGTemp *its, *ots;
3940bab1671fSRichard Henderson     TCGType itype, vtype;
3941d6ecb4a9SRichard Henderson     intptr_t endian_fixup;
3942bab1671fSRichard Henderson     unsigned vece;
3943bab1671fSRichard Henderson     bool ok;
3944bab1671fSRichard Henderson 
3945bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
3946bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
3947bab1671fSRichard Henderson 
3948bab1671fSRichard Henderson     /* ENV should not be modified.  */
3949e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
3950bab1671fSRichard Henderson 
3951bab1671fSRichard Henderson     itype = its->type;
3952bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
3953bab1671fSRichard Henderson     vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
3954bab1671fSRichard Henderson 
3955bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
3956bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
3957bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
3958bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
3959bab1671fSRichard Henderson             temp_dead(s, its);
3960bab1671fSRichard Henderson         }
3961bab1671fSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, op->output_pref[0]);
3962bab1671fSRichard Henderson         return;
3963bab1671fSRichard Henderson     }
3964bab1671fSRichard Henderson 
39659be0d080SRichard Henderson     dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
39669be0d080SRichard Henderson     dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs;
3967bab1671fSRichard Henderson 
3968bab1671fSRichard Henderson     /* Allocate the output register now.  */
3969bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
3970bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
3971bab1671fSRichard Henderson 
3972bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
3973bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
3974bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
3975bab1671fSRichard Henderson         }
3976bab1671fSRichard Henderson         ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
3977bab1671fSRichard Henderson                                  op->output_pref[0], ots->indirect_base);
3978bab1671fSRichard Henderson         ots->val_type = TEMP_VAL_REG;
3979bab1671fSRichard Henderson         ots->mem_coherent = 0;
3980bab1671fSRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3981bab1671fSRichard Henderson     }
3982bab1671fSRichard Henderson 
3983bab1671fSRichard Henderson     switch (its->val_type) {
3984bab1671fSRichard Henderson     case TEMP_VAL_REG:
3985bab1671fSRichard Henderson         /*
3986bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
3987bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
3988bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
3989bab1671fSRichard Henderson          */
3990bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
3991bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
3992bab1671fSRichard Henderson                 goto done;
3993bab1671fSRichard Henderson             }
3994bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
3995bab1671fSRichard Henderson         }
3996bab1671fSRichard Henderson         if (!its->mem_coherent) {
3997bab1671fSRichard Henderson             /*
3998bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
3999bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
4000bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
4001bab1671fSRichard Henderson              */
4002bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
4003bab1671fSRichard Henderson                 break;
4004bab1671fSRichard Henderson             }
4005bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
4006bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
4007bab1671fSRichard Henderson         }
4008bab1671fSRichard Henderson         /* fall through */
4009bab1671fSRichard Henderson 
4010bab1671fSRichard Henderson     case TEMP_VAL_MEM:
4011d6ecb4a9SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
4012d6ecb4a9SRichard Henderson         endian_fixup = itype == TCG_TYPE_I32 ? 4 : 8;
4013d6ecb4a9SRichard Henderson         endian_fixup -= 1 << vece;
4014d6ecb4a9SRichard Henderson #else
4015d6ecb4a9SRichard Henderson         endian_fixup = 0;
4016d6ecb4a9SRichard Henderson #endif
4017d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
4018d6ecb4a9SRichard Henderson                              its->mem_offset + endian_fixup)) {
4019d6ecb4a9SRichard Henderson             goto done;
4020d6ecb4a9SRichard Henderson         }
4021bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
4022bab1671fSRichard Henderson         break;
4023bab1671fSRichard Henderson 
4024bab1671fSRichard Henderson     default:
4025bab1671fSRichard Henderson         g_assert_not_reached();
4026bab1671fSRichard Henderson     }
4027bab1671fSRichard Henderson 
4028bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
4029bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
4030bab1671fSRichard Henderson     tcg_debug_assert(ok);
4031bab1671fSRichard Henderson 
4032bab1671fSRichard Henderson  done:
4033bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
4034bab1671fSRichard Henderson         temp_dead(s, its);
4035bab1671fSRichard Henderson     }
4036bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
4037bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
4038bab1671fSRichard Henderson     }
4039bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
4040bab1671fSRichard Henderson         temp_dead(s, ots);
4041bab1671fSRichard Henderson     }
4042bab1671fSRichard Henderson }
4043bab1671fSRichard Henderson 
4044dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
4045c896fe29Sbellard {
4046dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
4047dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
404882790a87SRichard Henderson     TCGRegSet i_allocated_regs;
404982790a87SRichard Henderson     TCGRegSet o_allocated_regs;
4050b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
4051b6638662SRichard Henderson     TCGReg reg;
4052c896fe29Sbellard     TCGArg arg;
4053c896fe29Sbellard     const TCGArgConstraint *arg_ct;
4054c896fe29Sbellard     TCGTemp *ts;
4055c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
4056c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
4057c896fe29Sbellard 
4058c896fe29Sbellard     nb_oargs = def->nb_oargs;
4059c896fe29Sbellard     nb_iargs = def->nb_iargs;
4060c896fe29Sbellard 
4061c896fe29Sbellard     /* copy constants */
4062c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
4063dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
4064c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
4065c896fe29Sbellard 
4066d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
4067d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
406882790a87SRichard Henderson 
4069c896fe29Sbellard     /* satisfy input constraints */
4070c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
4071d62816f2SRichard Henderson         TCGRegSet i_preferred_regs, o_preferred_regs;
4072d62816f2SRichard Henderson 
407366792f90SRichard Henderson         i = def->args_ct[nb_oargs + k].sort_index;
4074dd186292SRichard Henderson         arg = op->args[i];
4075c896fe29Sbellard         arg_ct = &def->args_ct[i];
407643439139SRichard Henderson         ts = arg_temp(arg);
407740ae5c62SRichard Henderson 
407840ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
407940ae5c62SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct)) {
4080c896fe29Sbellard             /* constant is OK for instruction */
4081c896fe29Sbellard             const_args[i] = 1;
4082c896fe29Sbellard             new_args[i] = ts->val;
4083d62816f2SRichard Henderson             continue;
4084c896fe29Sbellard         }
408540ae5c62SRichard Henderson 
4086d62816f2SRichard Henderson         i_preferred_regs = o_preferred_regs = 0;
4087bc2b17e6SRichard Henderson         if (arg_ct->ialias) {
4088d62816f2SRichard Henderson             o_preferred_regs = op->output_pref[arg_ct->alias_index];
4089c0522136SRichard Henderson 
4090c0522136SRichard Henderson             /*
4091c0522136SRichard Henderson              * If the input is readonly, then it cannot also be an
4092c0522136SRichard Henderson              * output and aliased to itself.  If the input is not
4093c0522136SRichard Henderson              * dead after the instruction, we must allocate a new
4094c0522136SRichard Henderson              * register and move it.
4095c0522136SRichard Henderson              */
4096c0522136SRichard Henderson             if (temp_readonly(ts) || !IS_DEAD_ARG(i)) {
4097c896fe29Sbellard                 goto allocate_in_reg;
4098c896fe29Sbellard             }
4099d62816f2SRichard Henderson 
4100c0522136SRichard Henderson             /*
4101c0522136SRichard Henderson              * Check if the current register has already been allocated
4102c0522136SRichard Henderson              * for another input aliased to an output.
4103c0522136SRichard Henderson              */
4104d62816f2SRichard Henderson             if (ts->val_type == TEMP_VAL_REG) {
4105d62816f2SRichard Henderson                 reg = ts->reg;
4106c0522136SRichard Henderson                 for (int k2 = 0; k2 < k; k2++) {
4107c0522136SRichard Henderson                     int i2 = def->args_ct[nb_oargs + k2].sort_index;
4108bc2b17e6SRichard Henderson                     if (def->args_ct[i2].ialias && reg == new_args[i2]) {
41097e1df267SAurelien Jarno                         goto allocate_in_reg;
41107e1df267SAurelien Jarno                     }
41117e1df267SAurelien Jarno                 }
41125ff9d6a4Sbellard             }
4113d62816f2SRichard Henderson             i_preferred_regs = o_preferred_regs;
4114866cb6cbSAurelien Jarno         }
4115d62816f2SRichard Henderson 
41169be0d080SRichard Henderson         temp_load(s, ts, arg_ct->regs, i_allocated_regs, i_preferred_regs);
4117c896fe29Sbellard         reg = ts->reg;
4118d62816f2SRichard Henderson 
4119c0522136SRichard Henderson         if (!tcg_regset_test_reg(arg_ct->regs, reg)) {
4120c896fe29Sbellard  allocate_in_reg:
4121c0522136SRichard Henderson             /*
4122c0522136SRichard Henderson              * Allocate a new register matching the constraint
4123c0522136SRichard Henderson              * and move the temporary register into it.
4124c0522136SRichard Henderson              */
4125d62816f2SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
4126d62816f2SRichard Henderson                       i_allocated_regs, 0);
41279be0d080SRichard Henderson             reg = tcg_reg_alloc(s, arg_ct->regs, i_allocated_regs,
4128d62816f2SRichard Henderson                                 o_preferred_regs, ts->indirect_base);
412978113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4130240c08d0SRichard Henderson                 /*
4131240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
4132240c08d0SRichard Henderson                  * temp back to its slot and load from there.
4133240c08d0SRichard Henderson                  */
4134240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
4135240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
4136240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
413778113e83SRichard Henderson             }
4138c896fe29Sbellard         }
4139c896fe29Sbellard         new_args[i] = reg;
4140c896fe29Sbellard         const_args[i] = 0;
414182790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
4142c896fe29Sbellard     }
4143c896fe29Sbellard 
4144c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
4145866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
4146866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
414743439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4148c896fe29Sbellard         }
4149c896fe29Sbellard     }
4150c896fe29Sbellard 
4151b4cb76e6SRichard Henderson     if (def->flags & TCG_OPF_COND_BRANCH) {
4152b4cb76e6SRichard Henderson         tcg_reg_alloc_cbranch(s, i_allocated_regs);
4153b4cb76e6SRichard Henderson     } else if (def->flags & TCG_OPF_BB_END) {
415482790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
4155a52ad07eSAurelien Jarno     } else {
4156c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
4157b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
4158c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4159c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
416082790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
4161c896fe29Sbellard                 }
4162c896fe29Sbellard             }
41633d5c5f87SAurelien Jarno         }
41643d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
41653d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
41663d5c5f87SAurelien Jarno                an exception. */
416782790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
4168c896fe29Sbellard         }
4169c896fe29Sbellard 
4170c896fe29Sbellard         /* satisfy the output constraints */
4171c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
417266792f90SRichard Henderson             i = def->args_ct[k].sort_index;
4173dd186292SRichard Henderson             arg = op->args[i];
4174c896fe29Sbellard             arg_ct = &def->args_ct[i];
417543439139SRichard Henderson             ts = arg_temp(arg);
4176d63e3b6eSRichard Henderson 
4177d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
4178e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
4179d63e3b6eSRichard Henderson 
4180bc2b17e6SRichard Henderson             if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
41815ff9d6a4Sbellard                 reg = new_args[arg_ct->alias_index];
4182bc2b17e6SRichard Henderson             } else if (arg_ct->newreg) {
41839be0d080SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->regs,
418482790a87SRichard Henderson                                     i_allocated_regs | o_allocated_regs,
418569e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
4186c896fe29Sbellard             } else {
41879be0d080SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
418869e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
4189c896fe29Sbellard             }
419082790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
4191639368ddSAurelien Jarno             if (ts->val_type == TEMP_VAL_REG) {
4192f8b2f202SRichard Henderson                 s->reg_to_temp[ts->reg] = NULL;
4193639368ddSAurelien Jarno             }
4194c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
4195c896fe29Sbellard             ts->reg = reg;
4196d63e3b6eSRichard Henderson             /*
4197d63e3b6eSRichard Henderson              * Temp value is modified, so the value kept in memory is
4198d63e3b6eSRichard Henderson              * potentially not the same.
4199d63e3b6eSRichard Henderson              */
4200c896fe29Sbellard             ts->mem_coherent = 0;
4201f8b2f202SRichard Henderson             s->reg_to_temp[reg] = ts;
4202c896fe29Sbellard             new_args[i] = reg;
4203c896fe29Sbellard         }
4204e8996ee0Sbellard     }
4205c896fe29Sbellard 
4206c896fe29Sbellard     /* emit instruction */
4207d2fd745fSRichard Henderson     if (def->flags & TCG_OPF_VECTOR) {
4208d2fd745fSRichard Henderson         tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
4209d2fd745fSRichard Henderson                        new_args, const_args);
4210d2fd745fSRichard Henderson     } else {
4211dd186292SRichard Henderson         tcg_out_op(s, op->opc, new_args, const_args);
4212d2fd745fSRichard Henderson     }
4213c896fe29Sbellard 
4214c896fe29Sbellard     /* move the outputs in the correct register if needed */
4215c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
421643439139SRichard Henderson         ts = arg_temp(op->args[i]);
4217d63e3b6eSRichard Henderson 
4218d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
4219e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
4220d63e3b6eSRichard Henderson 
4221ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
422298b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
422359d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4224f8bf00f1SRichard Henderson             temp_dead(s, ts);
4225ec7a869dSAurelien Jarno         }
4226c896fe29Sbellard     }
4227c896fe29Sbellard }
4228c896fe29Sbellard 
4229efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op)
4230efe86b21SRichard Henderson {
4231efe86b21SRichard Henderson     const TCGLifeData arg_life = op->life;
4232efe86b21SRichard Henderson     TCGTemp *ots, *itsl, *itsh;
4233efe86b21SRichard Henderson     TCGType vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
4234efe86b21SRichard Henderson 
4235efe86b21SRichard Henderson     /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */
4236efe86b21SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 32);
4237efe86b21SRichard Henderson     tcg_debug_assert(TCGOP_VECE(op) == MO_64);
4238efe86b21SRichard Henderson 
4239efe86b21SRichard Henderson     ots = arg_temp(op->args[0]);
4240efe86b21SRichard Henderson     itsl = arg_temp(op->args[1]);
4241efe86b21SRichard Henderson     itsh = arg_temp(op->args[2]);
4242efe86b21SRichard Henderson 
4243efe86b21SRichard Henderson     /* ENV should not be modified.  */
4244efe86b21SRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4245efe86b21SRichard Henderson 
4246efe86b21SRichard Henderson     /* Allocate the output register now.  */
4247efe86b21SRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
4248efe86b21SRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
4249efe86b21SRichard Henderson         TCGRegSet dup_out_regs =
4250efe86b21SRichard Henderson             tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
4251efe86b21SRichard Henderson 
4252efe86b21SRichard Henderson         /* Make sure to not spill the input registers. */
4253efe86b21SRichard Henderson         if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) {
4254efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsl->reg);
4255efe86b21SRichard Henderson         }
4256efe86b21SRichard Henderson         if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) {
4257efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsh->reg);
4258efe86b21SRichard Henderson         }
4259efe86b21SRichard Henderson 
4260efe86b21SRichard Henderson         ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
4261efe86b21SRichard Henderson                                  op->output_pref[0], ots->indirect_base);
4262efe86b21SRichard Henderson         ots->val_type = TEMP_VAL_REG;
4263efe86b21SRichard Henderson         ots->mem_coherent = 0;
4264efe86b21SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
4265efe86b21SRichard Henderson     }
4266efe86b21SRichard Henderson 
4267efe86b21SRichard Henderson     /* Promote dup2 of immediates to dupi_vec. */
4268efe86b21SRichard Henderson     if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) {
4269efe86b21SRichard Henderson         uint64_t val = deposit64(itsl->val, 32, 32, itsh->val);
4270efe86b21SRichard Henderson         MemOp vece = MO_64;
4271efe86b21SRichard Henderson 
4272efe86b21SRichard Henderson         if (val == dup_const(MO_8, val)) {
4273efe86b21SRichard Henderson             vece = MO_8;
4274efe86b21SRichard Henderson         } else if (val == dup_const(MO_16, val)) {
4275efe86b21SRichard Henderson             vece = MO_16;
4276efe86b21SRichard Henderson         } else if (val == dup_const(MO_32, val)) {
4277efe86b21SRichard Henderson             vece = MO_32;
4278efe86b21SRichard Henderson         }
4279efe86b21SRichard Henderson 
4280efe86b21SRichard Henderson         tcg_out_dupi_vec(s, vtype, vece, ots->reg, val);
4281efe86b21SRichard Henderson         goto done;
4282efe86b21SRichard Henderson     }
4283efe86b21SRichard Henderson 
4284efe86b21SRichard Henderson     /* If the two inputs form one 64-bit value, try dupm_vec. */
4285efe86b21SRichard Henderson     if (itsl + 1 == itsh && itsl->base_type == TCG_TYPE_I64) {
4286efe86b21SRichard Henderson         if (!itsl->mem_coherent) {
4287efe86b21SRichard Henderson             temp_sync(s, itsl, s->reserved_regs, 0, 0);
4288efe86b21SRichard Henderson         }
4289efe86b21SRichard Henderson         if (!itsh->mem_coherent) {
4290efe86b21SRichard Henderson             temp_sync(s, itsh, s->reserved_regs, 0, 0);
4291efe86b21SRichard Henderson         }
4292efe86b21SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
4293efe86b21SRichard Henderson         TCGTemp *its = itsh;
4294efe86b21SRichard Henderson #else
4295efe86b21SRichard Henderson         TCGTemp *its = itsl;
4296efe86b21SRichard Henderson #endif
4297efe86b21SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg,
4298efe86b21SRichard Henderson                              its->mem_base->reg, its->mem_offset)) {
4299efe86b21SRichard Henderson             goto done;
4300efe86b21SRichard Henderson         }
4301efe86b21SRichard Henderson     }
4302efe86b21SRichard Henderson 
4303efe86b21SRichard Henderson     /* Fall back to generic expansion. */
4304efe86b21SRichard Henderson     return false;
4305efe86b21SRichard Henderson 
4306efe86b21SRichard Henderson  done:
4307efe86b21SRichard Henderson     if (IS_DEAD_ARG(1)) {
4308efe86b21SRichard Henderson         temp_dead(s, itsl);
4309efe86b21SRichard Henderson     }
4310efe86b21SRichard Henderson     if (IS_DEAD_ARG(2)) {
4311efe86b21SRichard Henderson         temp_dead(s, itsh);
4312efe86b21SRichard Henderson     }
4313efe86b21SRichard Henderson     if (NEED_SYNC_ARG(0)) {
4314efe86b21SRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0));
4315efe86b21SRichard Henderson     } else if (IS_DEAD_ARG(0)) {
4316efe86b21SRichard Henderson         temp_dead(s, ots);
4317efe86b21SRichard Henderson     }
4318efe86b21SRichard Henderson     return true;
4319efe86b21SRichard Henderson }
4320efe86b21SRichard Henderson 
4321b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP
4322b03cce8eSbellard #define STACK_DIR(x) (-(x))
4323b03cce8eSbellard #else
4324b03cce8eSbellard #define STACK_DIR(x) (x)
4325b03cce8eSbellard #endif
4326b03cce8eSbellard 
4327dd186292SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
4328c896fe29Sbellard {
4329cd9090aaSRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
4330cd9090aaSRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
4331dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
4332b6638662SRichard Henderson     int flags, nb_regs, i;
4333b6638662SRichard Henderson     TCGReg reg;
4334cf066674SRichard Henderson     TCGArg arg;
4335c896fe29Sbellard     TCGTemp *ts;
4336d3452f1fSRichard Henderson     intptr_t stack_offset;
4337d3452f1fSRichard Henderson     size_t call_stack_size;
4338cf066674SRichard Henderson     tcg_insn_unit *func_addr;
4339cf066674SRichard Henderson     int allocate_args;
4340c896fe29Sbellard     TCGRegSet allocated_regs;
4341c896fe29Sbellard 
4342dd186292SRichard Henderson     func_addr = (tcg_insn_unit *)(intptr_t)op->args[nb_oargs + nb_iargs];
4343dd186292SRichard Henderson     flags = op->args[nb_oargs + nb_iargs + 1];
4344c896fe29Sbellard 
43456e17d0c5SStefan Weil     nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
4346c45cb8bbSRichard Henderson     if (nb_regs > nb_iargs) {
4347c45cb8bbSRichard Henderson         nb_regs = nb_iargs;
4348cf066674SRichard Henderson     }
4349c896fe29Sbellard 
4350c896fe29Sbellard     /* assign stack slots first */
4351c45cb8bbSRichard Henderson     call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long);
4352c896fe29Sbellard     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
4353c896fe29Sbellard         ~(TCG_TARGET_STACK_ALIGN - 1);
4354b03cce8eSbellard     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
4355b03cce8eSbellard     if (allocate_args) {
4356345649c0SBlue Swirl         /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
4357345649c0SBlue Swirl            preallocate call stack */
4358345649c0SBlue Swirl         tcg_abort();
4359b03cce8eSbellard     }
436039cf05d3Sbellard 
436139cf05d3Sbellard     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
4362c45cb8bbSRichard Henderson     for (i = nb_regs; i < nb_iargs; i++) {
4363dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
436439cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP
436539cf05d3Sbellard         stack_offset -= sizeof(tcg_target_long);
436639cf05d3Sbellard #endif
436739cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
436843439139SRichard Henderson             ts = arg_temp(arg);
436940ae5c62SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
4370b722452aSRichard Henderson                       s->reserved_regs, 0);
4371e4d5434cSblueswir1             tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
437239cf05d3Sbellard         }
437339cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP
437439cf05d3Sbellard         stack_offset += sizeof(tcg_target_long);
437539cf05d3Sbellard #endif
4376c896fe29Sbellard     }
4377c896fe29Sbellard 
4378c896fe29Sbellard     /* assign input registers */
4379d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
4380c896fe29Sbellard     for (i = 0; i < nb_regs; i++) {
4381dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
438239cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
438343439139SRichard Henderson             ts = arg_temp(arg);
4384c896fe29Sbellard             reg = tcg_target_call_iarg_regs[i];
438540ae5c62SRichard Henderson 
4386c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
4387c896fe29Sbellard                 if (ts->reg != reg) {
43884250da10SRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
438978113e83SRichard Henderson                     if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4390240c08d0SRichard Henderson                         /*
4391240c08d0SRichard Henderson                          * Cross register class move not supported.  Sync the
4392240c08d0SRichard Henderson                          * temp back to its slot and load from there.
4393240c08d0SRichard Henderson                          */
4394240c08d0SRichard Henderson                         temp_sync(s, ts, allocated_regs, 0, 0);
4395240c08d0SRichard Henderson                         tcg_out_ld(s, ts->type, reg,
4396240c08d0SRichard Henderson                                    ts->mem_base->reg, ts->mem_offset);
439778113e83SRichard Henderson                     }
4398c896fe29Sbellard                 }
4399c896fe29Sbellard             } else {
4400ccb1bb66SRichard Henderson                 TCGRegSet arg_set = 0;
440140ae5c62SRichard Henderson 
44024250da10SRichard Henderson                 tcg_reg_free(s, reg, allocated_regs);
440340ae5c62SRichard Henderson                 tcg_regset_set_reg(arg_set, reg);
4404b722452aSRichard Henderson                 temp_load(s, ts, arg_set, allocated_regs, 0);
4405c896fe29Sbellard             }
440640ae5c62SRichard Henderson 
4407c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
4408c896fe29Sbellard         }
440939cf05d3Sbellard     }
4410c896fe29Sbellard 
4411c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
4412866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4413866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
441443439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4415c896fe29Sbellard         }
4416c896fe29Sbellard     }
4417c896fe29Sbellard 
4418c896fe29Sbellard     /* clobber call registers */
4419c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4420c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
4421b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
4422c896fe29Sbellard         }
4423c896fe29Sbellard     }
4424c896fe29Sbellard 
442578505279SAurelien Jarno     /* Save globals if they might be written by the helper, sync them if
442678505279SAurelien Jarno        they might be read. */
442778505279SAurelien Jarno     if (flags & TCG_CALL_NO_READ_GLOBALS) {
442878505279SAurelien Jarno         /* Nothing to do */
442978505279SAurelien Jarno     } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) {
443078505279SAurelien Jarno         sync_globals(s, allocated_regs);
443178505279SAurelien Jarno     } else {
4432e8996ee0Sbellard         save_globals(s, allocated_regs);
4433b9c18f56Saurel32     }
4434c896fe29Sbellard 
4435cf066674SRichard Henderson     tcg_out_call(s, func_addr);
4436c896fe29Sbellard 
4437c896fe29Sbellard     /* assign output registers and emit moves if needed */
4438c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
4439dd186292SRichard Henderson         arg = op->args[i];
444043439139SRichard Henderson         ts = arg_temp(arg);
4441d63e3b6eSRichard Henderson 
4442d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
4443e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
4444d63e3b6eSRichard Henderson 
4445c896fe29Sbellard         reg = tcg_target_call_oarg_regs[i];
4446eabb7b91SAurelien Jarno         tcg_debug_assert(s->reg_to_temp[reg] == NULL);
4447639368ddSAurelien Jarno         if (ts->val_type == TEMP_VAL_REG) {
4448f8b2f202SRichard Henderson             s->reg_to_temp[ts->reg] = NULL;
4449639368ddSAurelien Jarno         }
4450c896fe29Sbellard         ts->val_type = TEMP_VAL_REG;
4451c896fe29Sbellard         ts->reg = reg;
4452c896fe29Sbellard         ts->mem_coherent = 0;
4453f8b2f202SRichard Henderson         s->reg_to_temp[reg] = ts;
4454ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
445598b4e186SRichard Henderson             temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i));
445659d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4457f8bf00f1SRichard Henderson             temp_dead(s, ts);
4458c896fe29Sbellard         }
4459c896fe29Sbellard     }
44608c11ad25SAurelien Jarno }
4461c896fe29Sbellard 
4462c896fe29Sbellard #ifdef CONFIG_PROFILER
4463c896fe29Sbellard 
4464c3fac113SEmilio G. Cota /* avoid copy/paste errors */
4465c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field)                       \
4466c3fac113SEmilio G. Cota     do {                                                \
4467d73415a3SStefan Hajnoczi         (to)->field += qatomic_read(&((from)->field));  \
4468c3fac113SEmilio G. Cota     } while (0)
4469c896fe29Sbellard 
4470c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field)                                       \
4471c3fac113SEmilio G. Cota     do {                                                                \
4472d73415a3SStefan Hajnoczi         typeof((from)->field) val__ = qatomic_read(&((from)->field));   \
4473c3fac113SEmilio G. Cota         if (val__ > (to)->field) {                                      \
4474c3fac113SEmilio G. Cota             (to)->field = val__;                                        \
4475c3fac113SEmilio G. Cota         }                                                               \
4476c3fac113SEmilio G. Cota     } while (0)
4477c3fac113SEmilio G. Cota 
4478c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */
4479c3fac113SEmilio G. Cota static inline
4480c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
4481c896fe29Sbellard {
4482d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
4483c3fac113SEmilio G. Cota     unsigned int i;
4484c3fac113SEmilio G. Cota 
44853468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4486d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
44873468b59eSEmilio G. Cota         const TCGProfile *orig = &s->prof;
4488c3fac113SEmilio G. Cota 
4489c3fac113SEmilio G. Cota         if (counters) {
449072fd2efbSEmilio G. Cota             PROF_ADD(prof, orig, cpu_exec_time);
4491c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count1);
4492c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count);
4493c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, op_count);
4494c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, op_count_max);
4495c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, temp_count);
4496c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, temp_count_max);
4497c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, del_op_count);
4498c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_in_len);
4499c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_out_len);
4500c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, search_out_len);
4501c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, interm_time);
4502c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_time);
4503c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, la_time);
4504c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, opt_time);
4505c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_count);
4506c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_time);
4507c3fac113SEmilio G. Cota         }
4508c3fac113SEmilio G. Cota         if (table) {
4509c896fe29Sbellard             int i;
4510d70724ceSzhanghailiang 
451115fc7daaSRichard Henderson             for (i = 0; i < NB_OPS; i++) {
4512c3fac113SEmilio G. Cota                 PROF_ADD(prof, orig, table_op_count[i]);
4513c3fac113SEmilio G. Cota             }
4514c3fac113SEmilio G. Cota         }
4515c3fac113SEmilio G. Cota     }
4516c3fac113SEmilio G. Cota }
4517c3fac113SEmilio G. Cota 
4518c3fac113SEmilio G. Cota #undef PROF_ADD
4519c3fac113SEmilio G. Cota #undef PROF_MAX
4520c3fac113SEmilio G. Cota 
4521c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof)
4522c3fac113SEmilio G. Cota {
4523c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, true, false);
4524c3fac113SEmilio G. Cota }
4525c3fac113SEmilio G. Cota 
4526c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof)
4527c3fac113SEmilio G. Cota {
4528c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, false, true);
4529c3fac113SEmilio G. Cota }
4530c3fac113SEmilio G. Cota 
4531d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
4532c3fac113SEmilio G. Cota {
4533c3fac113SEmilio G. Cota     TCGProfile prof = {};
4534c3fac113SEmilio G. Cota     int i;
4535c3fac113SEmilio G. Cota 
4536c3fac113SEmilio G. Cota     tcg_profile_snapshot_table(&prof);
4537c3fac113SEmilio G. Cota     for (i = 0; i < NB_OPS; i++) {
4538d4c51a0aSMarkus Armbruster         qemu_printf("%s %" PRId64 "\n", tcg_op_defs[i].name,
4539c3fac113SEmilio G. Cota                     prof.table_op_count[i]);
4540c896fe29Sbellard     }
4541c896fe29Sbellard }
454272fd2efbSEmilio G. Cota 
454372fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
454472fd2efbSEmilio G. Cota {
4545d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
454672fd2efbSEmilio G. Cota     unsigned int i;
454772fd2efbSEmilio G. Cota     int64_t ret = 0;
454872fd2efbSEmilio G. Cota 
454972fd2efbSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4550d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
455172fd2efbSEmilio G. Cota         const TCGProfile *prof = &s->prof;
455272fd2efbSEmilio G. Cota 
4553d73415a3SStefan Hajnoczi         ret += qatomic_read(&prof->cpu_exec_time);
455472fd2efbSEmilio G. Cota     }
455572fd2efbSEmilio G. Cota     return ret;
455672fd2efbSEmilio G. Cota }
4557246ae24dSMax Filippov #else
4558d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
4559246ae24dSMax Filippov {
4560d4c51a0aSMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4561246ae24dSMax Filippov }
456272fd2efbSEmilio G. Cota 
456372fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
456472fd2efbSEmilio G. Cota {
456572fd2efbSEmilio G. Cota     error_report("%s: TCG profiler not compiled", __func__);
456672fd2efbSEmilio G. Cota     exit(EXIT_FAILURE);
456772fd2efbSEmilio G. Cota }
4568c896fe29Sbellard #endif
4569c896fe29Sbellard 
4570c896fe29Sbellard 
45715bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
4572c896fe29Sbellard {
4573c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER
4574c3fac113SEmilio G. Cota     TCGProfile *prof = &s->prof;
4575c3fac113SEmilio G. Cota #endif
457615fa08f8SRichard Henderson     int i, num_insns;
457715fa08f8SRichard Henderson     TCGOp *op;
4578c896fe29Sbellard 
457904fe6400SRichard Henderson #ifdef CONFIG_PROFILER
458004fe6400SRichard Henderson     {
4581c1f543b7SEmilio G. Cota         int n = 0;
458204fe6400SRichard Henderson 
458315fa08f8SRichard Henderson         QTAILQ_FOREACH(op, &s->ops, link) {
458415fa08f8SRichard Henderson             n++;
458515fa08f8SRichard Henderson         }
4586d73415a3SStefan Hajnoczi         qatomic_set(&prof->op_count, prof->op_count + n);
4587c3fac113SEmilio G. Cota         if (n > prof->op_count_max) {
4588d73415a3SStefan Hajnoczi             qatomic_set(&prof->op_count_max, n);
458904fe6400SRichard Henderson         }
459004fe6400SRichard Henderson 
459104fe6400SRichard Henderson         n = s->nb_temps;
4592d73415a3SStefan Hajnoczi         qatomic_set(&prof->temp_count, prof->temp_count + n);
4593c3fac113SEmilio G. Cota         if (n > prof->temp_count_max) {
4594d73415a3SStefan Hajnoczi             qatomic_set(&prof->temp_count_max, n);
459504fe6400SRichard Henderson         }
459604fe6400SRichard Henderson     }
459704fe6400SRichard Henderson #endif
459804fe6400SRichard Henderson 
4599c896fe29Sbellard #ifdef DEBUG_DISAS
4600d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
4601d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
4602fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
460393fcfe39Saliguori         qemu_log("OP:\n");
46041894f69aSRichard Henderson         tcg_dump_ops(s, false);
460593fcfe39Saliguori         qemu_log("\n");
4606fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
4607c896fe29Sbellard     }
4608c896fe29Sbellard #endif
4609c896fe29Sbellard 
4610bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
4611bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
4612bef16ab4SRichard Henderson     {
4613bef16ab4SRichard Henderson         TCGLabel *l;
4614bef16ab4SRichard Henderson         bool error = false;
4615bef16ab4SRichard Henderson 
4616bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
4617bef16ab4SRichard Henderson             if (unlikely(!l->present) && l->refs) {
4618bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
4619bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
4620bef16ab4SRichard Henderson                 error = true;
4621bef16ab4SRichard Henderson             }
4622bef16ab4SRichard Henderson         }
4623bef16ab4SRichard Henderson         assert(!error);
4624bef16ab4SRichard Henderson     }
4625bef16ab4SRichard Henderson #endif
4626bef16ab4SRichard Henderson 
4627c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
4628d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
4629c5cc28ffSAurelien Jarno #endif
4630c5cc28ffSAurelien Jarno 
46318f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
4632c45cb8bbSRichard Henderson     tcg_optimize(s);
46338f2e8c07SKirill Batuzov #endif
46348f2e8c07SKirill Batuzov 
4635a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4636d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
4637d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time - profile_getclock());
4638a23a9ec6Sbellard #endif
4639c5cc28ffSAurelien Jarno 
4640b4fc67c7SRichard Henderson     reachable_code_pass(s);
4641b83eabeaSRichard Henderson     liveness_pass_1(s);
46425a18407fSRichard Henderson 
46435a18407fSRichard Henderson     if (s->nb_indirects > 0) {
46445a18407fSRichard Henderson #ifdef DEBUG_DISAS
46455a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
46465a18407fSRichard Henderson                      && qemu_log_in_addr_range(tb->pc))) {
4647fc59d2d8SRobert Foley             FILE *logfile = qemu_log_lock();
46485a18407fSRichard Henderson             qemu_log("OP before indirect lowering:\n");
46491894f69aSRichard Henderson             tcg_dump_ops(s, false);
46505a18407fSRichard Henderson             qemu_log("\n");
4651fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
46525a18407fSRichard Henderson         }
46535a18407fSRichard Henderson #endif
46545a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
4655b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
46565a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
4657b83eabeaSRichard Henderson             liveness_pass_1(s);
46585a18407fSRichard Henderson         }
46595a18407fSRichard Henderson     }
4660c5cc28ffSAurelien Jarno 
4661a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4662d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time + profile_getclock());
4663a23a9ec6Sbellard #endif
4664c896fe29Sbellard 
4665c896fe29Sbellard #ifdef DEBUG_DISAS
4666d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
4667d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
4668fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
4669c5cc28ffSAurelien Jarno         qemu_log("OP after optimization and liveness analysis:\n");
46701894f69aSRichard Henderson         tcg_dump_ops(s, true);
467193fcfe39Saliguori         qemu_log("\n");
4672fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
4673c896fe29Sbellard     }
4674c896fe29Sbellard #endif
4675c896fe29Sbellard 
4676c896fe29Sbellard     tcg_reg_alloc_start(s);
4677c896fe29Sbellard 
4678db0c51a3SRichard Henderson     /*
4679db0c51a3SRichard Henderson      * Reset the buffer pointers when restarting after overflow.
4680db0c51a3SRichard Henderson      * TODO: Move this into translate-all.c with the rest of the
4681db0c51a3SRichard Henderson      * buffer management.  Having only this done here is confusing.
4682db0c51a3SRichard Henderson      */
4683db0c51a3SRichard Henderson     s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr);
4684db0c51a3SRichard Henderson     s->code_ptr = s->code_buf;
4685c896fe29Sbellard 
4686659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
46876001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
4688659ef5cbSRichard Henderson #endif
468957a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
469057a26946SRichard Henderson     s->pool_labels = NULL;
469157a26946SRichard Henderson #endif
46929ecefc84SRichard Henderson 
4693fca8a500SRichard Henderson     num_insns = -1;
469415fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
4695c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
4696b3db8758Sblueswir1 
4697c896fe29Sbellard #ifdef CONFIG_PROFILER
4698d73415a3SStefan Hajnoczi         qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
4699c896fe29Sbellard #endif
4700c45cb8bbSRichard Henderson 
4701c896fe29Sbellard         switch (opc) {
4702c896fe29Sbellard         case INDEX_op_mov_i32:
4703c896fe29Sbellard         case INDEX_op_mov_i64:
4704d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
4705dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
4706c896fe29Sbellard             break;
4707bab1671fSRichard Henderson         case INDEX_op_dup_vec:
4708bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
4709bab1671fSRichard Henderson             break;
4710765b842aSRichard Henderson         case INDEX_op_insn_start:
4711fca8a500SRichard Henderson             if (num_insns >= 0) {
47129f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
47139f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
47149f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
47159f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
4716fca8a500SRichard Henderson             }
4717fca8a500SRichard Henderson             num_insns++;
4718bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
4719bad729e2SRichard Henderson                 target_ulong a;
4720bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
4721efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
4722bad729e2SRichard Henderson #else
4723efee3746SRichard Henderson                 a = op->args[i];
4724bad729e2SRichard Henderson #endif
4725fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
4726bad729e2SRichard Henderson             }
4727c896fe29Sbellard             break;
47285ff9d6a4Sbellard         case INDEX_op_discard:
472943439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
47305ff9d6a4Sbellard             break;
4731c896fe29Sbellard         case INDEX_op_set_label:
4732e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
473392ab8e7dSRichard Henderson             tcg_out_label(s, arg_label(op->args[0]));
4734c896fe29Sbellard             break;
4735c896fe29Sbellard         case INDEX_op_call:
4736dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
4737c45cb8bbSRichard Henderson             break;
4738efe86b21SRichard Henderson         case INDEX_op_dup2_vec:
4739efe86b21SRichard Henderson             if (tcg_reg_alloc_dup2(s, op)) {
4740efe86b21SRichard Henderson                 break;
4741efe86b21SRichard Henderson             }
4742efe86b21SRichard Henderson             /* fall through */
4743c896fe29Sbellard         default:
474425c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
4745be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
4746c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
4747c896fe29Sbellard                faster to have specialized register allocator functions for
4748c896fe29Sbellard                some common argument patterns */
4749dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
4750c896fe29Sbellard             break;
4751c896fe29Sbellard         }
47528d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
4753c896fe29Sbellard         check_regs(s);
4754c896fe29Sbellard #endif
4755b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
4756b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
4757b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
4758b125f9dcSRichard Henderson            generating code without having to check during generation.  */
4759644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
4760b125f9dcSRichard Henderson             return -1;
4761b125f9dcSRichard Henderson         }
47626e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
47636e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
47646e6c4efeSRichard Henderson             return -2;
47656e6c4efeSRichard Henderson         }
4766c896fe29Sbellard     }
4767fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
4768fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
4769c45cb8bbSRichard Henderson 
4770b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
4771659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
4772aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
4773aeee05f5SRichard Henderson     if (i < 0) {
4774aeee05f5SRichard Henderson         return i;
477523dceda6SRichard Henderson     }
4776659ef5cbSRichard Henderson #endif
477757a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
47781768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
47791768987bSRichard Henderson     if (i < 0) {
47801768987bSRichard Henderson         return i;
478157a26946SRichard Henderson     }
478257a26946SRichard Henderson #endif
47837ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
47847ecd02a0SRichard Henderson         return -2;
47857ecd02a0SRichard Henderson     }
4786c896fe29Sbellard 
4787df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
4788c896fe29Sbellard     /* flush instruction cache */
4789db0c51a3SRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
4790db0c51a3SRichard Henderson                         (uintptr_t)s->code_buf,
47911da8de39SRichard Henderson                         tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
4792df5d2b16SRichard Henderson #endif
47932aeabc08SStefan Weil 
47941813e175SRichard Henderson     return tcg_current_code_size(s);
4795c896fe29Sbellard }
4796c896fe29Sbellard 
4797a23a9ec6Sbellard #ifdef CONFIG_PROFILER
47983de2faa9SMarkus Armbruster void tcg_dump_info(void)
4799a23a9ec6Sbellard {
4800c3fac113SEmilio G. Cota     TCGProfile prof = {};
4801c3fac113SEmilio G. Cota     const TCGProfile *s;
4802c3fac113SEmilio G. Cota     int64_t tb_count;
4803c3fac113SEmilio G. Cota     int64_t tb_div_count;
4804c3fac113SEmilio G. Cota     int64_t tot;
4805c3fac113SEmilio G. Cota 
4806c3fac113SEmilio G. Cota     tcg_profile_snapshot_counters(&prof);
4807c3fac113SEmilio G. Cota     s = &prof;
4808c3fac113SEmilio G. Cota     tb_count = s->tb_count;
4809c3fac113SEmilio G. Cota     tb_div_count = tb_count ? tb_count : 1;
4810c3fac113SEmilio G. Cota     tot = s->interm_time + s->code_time;
4811a23a9ec6Sbellard 
48123de2faa9SMarkus Armbruster     qemu_printf("JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
4813a23a9ec6Sbellard                 tot, tot / 2.4e9);
48143de2faa9SMarkus Armbruster     qemu_printf("translated TBs      %" PRId64 " (aborted=%" PRId64
48153de2faa9SMarkus Armbruster                 " %0.1f%%)\n",
4816fca8a500SRichard Henderson                 tb_count, s->tb_count1 - tb_count,
4817fca8a500SRichard Henderson                 (double)(s->tb_count1 - s->tb_count)
4818fca8a500SRichard Henderson                 / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
48193de2faa9SMarkus Armbruster     qemu_printf("avg ops/TB          %0.1f max=%d\n",
4820fca8a500SRichard Henderson                 (double)s->op_count / tb_div_count, s->op_count_max);
48213de2faa9SMarkus Armbruster     qemu_printf("deleted ops/TB      %0.2f\n",
4822fca8a500SRichard Henderson                 (double)s->del_op_count / tb_div_count);
48233de2faa9SMarkus Armbruster     qemu_printf("avg temps/TB        %0.2f max=%d\n",
4824fca8a500SRichard Henderson                 (double)s->temp_count / tb_div_count, s->temp_count_max);
48253de2faa9SMarkus Armbruster     qemu_printf("avg host code/TB    %0.1f\n",
4826fca8a500SRichard Henderson                 (double)s->code_out_len / tb_div_count);
48273de2faa9SMarkus Armbruster     qemu_printf("avg search data/TB  %0.1f\n",
4828fca8a500SRichard Henderson                 (double)s->search_out_len / tb_div_count);
4829a23a9ec6Sbellard 
48303de2faa9SMarkus Armbruster     qemu_printf("cycles/op           %0.1f\n",
4831a23a9ec6Sbellard                 s->op_count ? (double)tot / s->op_count : 0);
48323de2faa9SMarkus Armbruster     qemu_printf("cycles/in byte      %0.1f\n",
4833a23a9ec6Sbellard                 s->code_in_len ? (double)tot / s->code_in_len : 0);
48343de2faa9SMarkus Armbruster     qemu_printf("cycles/out byte     %0.1f\n",
4835a23a9ec6Sbellard                 s->code_out_len ? (double)tot / s->code_out_len : 0);
48363de2faa9SMarkus Armbruster     qemu_printf("cycles/search byte     %0.1f\n",
4837fca8a500SRichard Henderson                 s->search_out_len ? (double)tot / s->search_out_len : 0);
4838fca8a500SRichard Henderson     if (tot == 0) {
4839a23a9ec6Sbellard         tot = 1;
4840fca8a500SRichard Henderson     }
48413de2faa9SMarkus Armbruster     qemu_printf("  gen_interm time   %0.1f%%\n",
4842a23a9ec6Sbellard                 (double)s->interm_time / tot * 100.0);
48433de2faa9SMarkus Armbruster     qemu_printf("  gen_code time     %0.1f%%\n",
4844a23a9ec6Sbellard                 (double)s->code_time / tot * 100.0);
48453de2faa9SMarkus Armbruster     qemu_printf("optim./code time    %0.1f%%\n",
4846c5cc28ffSAurelien Jarno                 (double)s->opt_time / (s->code_time ? s->code_time : 1)
4847c5cc28ffSAurelien Jarno                 * 100.0);
48483de2faa9SMarkus Armbruster     qemu_printf("liveness/code time  %0.1f%%\n",
4849a23a9ec6Sbellard                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
48503de2faa9SMarkus Armbruster     qemu_printf("cpu_restore count   %" PRId64 "\n",
4851a23a9ec6Sbellard                 s->restore_count);
48523de2faa9SMarkus Armbruster     qemu_printf("  avg cycles        %0.1f\n",
4853a23a9ec6Sbellard                 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
4854a23a9ec6Sbellard }
4855a23a9ec6Sbellard #else
48563de2faa9SMarkus Armbruster void tcg_dump_info(void)
4857a23a9ec6Sbellard {
48583de2faa9SMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4859a23a9ec6Sbellard }
4860a23a9ec6Sbellard #endif
4861813da627SRichard Henderson 
4862813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
48635872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
48645872bbf2SRichard Henderson 
48655872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
48665872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
48675872bbf2SRichard Henderson 
48685872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
48695872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
48705872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
48715872bbf2SRichard Henderson 
48725872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
48735872bbf2SRichard Henderson */
4874813da627SRichard Henderson 
4875813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
4876813da627SRichard Henderson typedef enum {
4877813da627SRichard Henderson     JIT_NOACTION = 0,
4878813da627SRichard Henderson     JIT_REGISTER_FN,
4879813da627SRichard Henderson     JIT_UNREGISTER_FN
4880813da627SRichard Henderson } jit_actions_t;
4881813da627SRichard Henderson 
4882813da627SRichard Henderson struct jit_code_entry {
4883813da627SRichard Henderson     struct jit_code_entry *next_entry;
4884813da627SRichard Henderson     struct jit_code_entry *prev_entry;
4885813da627SRichard Henderson     const void *symfile_addr;
4886813da627SRichard Henderson     uint64_t symfile_size;
4887813da627SRichard Henderson };
4888813da627SRichard Henderson 
4889813da627SRichard Henderson struct jit_descriptor {
4890813da627SRichard Henderson     uint32_t version;
4891813da627SRichard Henderson     uint32_t action_flag;
4892813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
4893813da627SRichard Henderson     struct jit_code_entry *first_entry;
4894813da627SRichard Henderson };
4895813da627SRichard Henderson 
4896813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
4897813da627SRichard Henderson void __jit_debug_register_code(void)
4898813da627SRichard Henderson {
4899813da627SRichard Henderson     asm("");
4900813da627SRichard Henderson }
4901813da627SRichard Henderson 
4902813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
4903813da627SRichard Henderson    the version before we can set it.  */
4904813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
4905813da627SRichard Henderson 
4906813da627SRichard Henderson /* End GDB interface.  */
4907813da627SRichard Henderson 
4908813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
4909813da627SRichard Henderson {
4910813da627SRichard Henderson     const char *p = strtab + 1;
4911813da627SRichard Henderson 
4912813da627SRichard Henderson     while (1) {
4913813da627SRichard Henderson         if (strcmp(p, str) == 0) {
4914813da627SRichard Henderson             return p - strtab;
4915813da627SRichard Henderson         }
4916813da627SRichard Henderson         p += strlen(p) + 1;
4917813da627SRichard Henderson     }
4918813da627SRichard Henderson }
4919813da627SRichard Henderson 
4920755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size,
49212c90784aSRichard Henderson                                  const void *debug_frame,
49222c90784aSRichard Henderson                                  size_t debug_frame_size)
4923813da627SRichard Henderson {
49245872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
49255872bbf2SRichard Henderson         uint32_t  len;
49265872bbf2SRichard Henderson         uint16_t  version;
49275872bbf2SRichard Henderson         uint32_t  abbrev;
49285872bbf2SRichard Henderson         uint8_t   ptr_size;
49295872bbf2SRichard Henderson         uint8_t   cu_die;
49305872bbf2SRichard Henderson         uint16_t  cu_lang;
49315872bbf2SRichard Henderson         uintptr_t cu_low_pc;
49325872bbf2SRichard Henderson         uintptr_t cu_high_pc;
49335872bbf2SRichard Henderson         uint8_t   fn_die;
49345872bbf2SRichard Henderson         char      fn_name[16];
49355872bbf2SRichard Henderson         uintptr_t fn_low_pc;
49365872bbf2SRichard Henderson         uintptr_t fn_high_pc;
49375872bbf2SRichard Henderson         uint8_t   cu_eoc;
49385872bbf2SRichard Henderson     };
4939813da627SRichard Henderson 
4940813da627SRichard Henderson     struct ElfImage {
4941813da627SRichard Henderson         ElfW(Ehdr) ehdr;
4942813da627SRichard Henderson         ElfW(Phdr) phdr;
49435872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
49445872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
49455872bbf2SRichard Henderson         struct DebugInfo di;
49465872bbf2SRichard Henderson         uint8_t    da[24];
49475872bbf2SRichard Henderson         char       str[80];
49485872bbf2SRichard Henderson     };
49495872bbf2SRichard Henderson 
49505872bbf2SRichard Henderson     struct ElfImage *img;
49515872bbf2SRichard Henderson 
49525872bbf2SRichard Henderson     static const struct ElfImage img_template = {
49535872bbf2SRichard Henderson         .ehdr = {
49545872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
49555872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
49565872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
49575872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
49585872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
49595872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
49605872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
49615872bbf2SRichard Henderson             .e_type = ET_EXEC,
49625872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
49635872bbf2SRichard Henderson             .e_version = EV_CURRENT,
49645872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
49655872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
49665872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
49675872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
49685872bbf2SRichard Henderson             .e_phnum = 1,
49695872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
49705872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
49715872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
4972abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
4973abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
4974abbb3eaeSRichard Henderson #endif
4975abbb3eaeSRichard Henderson #ifdef ELF_OSABI
4976abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
4977abbb3eaeSRichard Henderson #endif
49785872bbf2SRichard Henderson         },
49795872bbf2SRichard Henderson         .phdr = {
49805872bbf2SRichard Henderson             .p_type = PT_LOAD,
49815872bbf2SRichard Henderson             .p_flags = PF_X,
49825872bbf2SRichard Henderson         },
49835872bbf2SRichard Henderson         .shdr = {
49845872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
49855872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
49865872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
49875872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
49885872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
49895872bbf2SRichard Henderson             [1] = { /* .text */
49905872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
49915872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
49925872bbf2SRichard Henderson             },
49935872bbf2SRichard Henderson             [2] = { /* .debug_info */
49945872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
49955872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
49965872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
49975872bbf2SRichard Henderson             },
49985872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
49995872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
50005872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
50015872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
50025872bbf2SRichard Henderson             },
50035872bbf2SRichard Henderson             [4] = { /* .debug_frame */
50045872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
50055872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
50065872bbf2SRichard Henderson             },
50075872bbf2SRichard Henderson             [5] = { /* .symtab */
50085872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
50095872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
50105872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
50115872bbf2SRichard Henderson                 .sh_info = 1,
50125872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
50135872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
50145872bbf2SRichard Henderson             },
50155872bbf2SRichard Henderson             [6] = { /* .strtab */
50165872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
50175872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
50185872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
50195872bbf2SRichard Henderson             }
50205872bbf2SRichard Henderson         },
50215872bbf2SRichard Henderson         .sym = {
50225872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
50235872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
50245872bbf2SRichard Henderson                 .st_shndx = 1,
50255872bbf2SRichard Henderson             }
50265872bbf2SRichard Henderson         },
50275872bbf2SRichard Henderson         .di = {
50285872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
50295872bbf2SRichard Henderson             .version = 2,
50305872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
50315872bbf2SRichard Henderson             .cu_die = 1,
50325872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
50335872bbf2SRichard Henderson             .fn_die = 2,
50345872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
50355872bbf2SRichard Henderson         },
50365872bbf2SRichard Henderson         .da = {
50375872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
50385872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
50395872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
50405872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
50415872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
50425872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
50435872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
50445872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
50455872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
50465872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
50475872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
50485872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
50495872bbf2SRichard Henderson             0           /* no more abbrev */
50505872bbf2SRichard Henderson         },
50515872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
50525872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
5053813da627SRichard Henderson     };
5054813da627SRichard Henderson 
5055813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
5056813da627SRichard Henderson     static struct jit_code_entry one_entry;
5057813da627SRichard Henderson 
50585872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
5059813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
50602c90784aSRichard Henderson     DebugFrameHeader *dfh;
5061813da627SRichard Henderson 
50625872bbf2SRichard Henderson     img = g_malloc(img_size);
50635872bbf2SRichard Henderson     *img = img_template;
5064813da627SRichard Henderson 
50655872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
50665872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
50675872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
5068813da627SRichard Henderson 
50695872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
50705872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
50715872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
5072813da627SRichard Henderson 
50735872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
50745872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
50755872bbf2SRichard Henderson 
50765872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
50775872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
50785872bbf2SRichard Henderson 
50795872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
50805872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
50815872bbf2SRichard Henderson 
50825872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
50835872bbf2SRichard Henderson     img->sym[1].st_value = buf;
50845872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
50855872bbf2SRichard Henderson 
50865872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
508745aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
50885872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
508945aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
5090813da627SRichard Henderson 
50912c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
50922c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
50932c90784aSRichard Henderson     dfh->fde.func_start = buf;
50942c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
50952c90784aSRichard Henderson 
5096813da627SRichard Henderson #ifdef DEBUG_JIT
5097813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
5098813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
5099813da627SRichard Henderson     {
5100813da627SRichard Henderson         FILE *f = fopen("/tmp/qemu.jit", "w+b");
5101813da627SRichard Henderson         if (f) {
51025872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
5103813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
5104813da627SRichard Henderson             }
5105813da627SRichard Henderson             fclose(f);
5106813da627SRichard Henderson         }
5107813da627SRichard Henderson     }
5108813da627SRichard Henderson #endif
5109813da627SRichard Henderson 
5110813da627SRichard Henderson     one_entry.symfile_addr = img;
5111813da627SRichard Henderson     one_entry.symfile_size = img_size;
5112813da627SRichard Henderson 
5113813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
5114813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
5115813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
5116813da627SRichard Henderson     __jit_debug_register_code();
5117813da627SRichard Henderson }
5118813da627SRichard Henderson #else
51195872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
51205872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
5121813da627SRichard Henderson 
5122755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
51232c90784aSRichard Henderson                                  const void *debug_frame,
51242c90784aSRichard Henderson                                  size_t debug_frame_size)
5125813da627SRichard Henderson {
5126813da627SRichard Henderson }
5127813da627SRichard Henderson 
5128755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size)
5129813da627SRichard Henderson {
5130813da627SRichard Henderson }
5131813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
5132db432672SRichard Henderson 
5133db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
5134db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
5135db432672SRichard Henderson {
5136db432672SRichard Henderson     g_assert_not_reached();
5137db432672SRichard Henderson }
5138db432672SRichard Henderson #endif
5139