xref: /qemu/tcg/tcg.c (revision 4c22e840880e935ea07f1c4352bd8c54febff4df)
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);
72*4c22e840SRichard Henderson #ifndef TCG_TARGET_CON_SET_H
73f69d277eSRichard Henderson static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode);
74*4c22e840SRichard Henderson #endif
75e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
766ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
772ba7fae2SRichard Henderson                         intptr_t value, intptr_t addend);
78c896fe29Sbellard 
79497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts.  */
80497a22ebSRichard Henderson typedef struct {
81497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
82497a22ebSRichard Henderson     uint32_t id;
83497a22ebSRichard Henderson     uint8_t version;
84497a22ebSRichard Henderson     char augmentation[1];
85497a22ebSRichard Henderson     uint8_t code_align;
86497a22ebSRichard Henderson     uint8_t data_align;
87497a22ebSRichard Henderson     uint8_t return_column;
88497a22ebSRichard Henderson } DebugFrameCIE;
89497a22ebSRichard Henderson 
90497a22ebSRichard Henderson typedef struct QEMU_PACKED {
91497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
92497a22ebSRichard Henderson     uint32_t cie_offset;
93edee2579SRichard Henderson     uintptr_t func_start;
94edee2579SRichard Henderson     uintptr_t func_len;
95497a22ebSRichard Henderson } DebugFrameFDEHeader;
96497a22ebSRichard Henderson 
972c90784aSRichard Henderson typedef struct QEMU_PACKED {
982c90784aSRichard Henderson     DebugFrameCIE cie;
992c90784aSRichard Henderson     DebugFrameFDEHeader fde;
1002c90784aSRichard Henderson } DebugFrameHeader;
1012c90784aSRichard Henderson 
102755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
1032c90784aSRichard Henderson                                  const void *debug_frame,
1042c90784aSRichard Henderson                                  size_t debug_frame_size)
105813da627SRichard Henderson     __attribute__((unused));
106813da627SRichard Henderson 
107139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */
1082a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
109a05b5b9bSRichard Henderson                        intptr_t arg2);
11078113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
111c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1122a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
113c0ad3001SStefan Weil static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
114c0ad3001SStefan Weil                        const int *const_args);
115d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec
116e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
117e7632cfaSRichard Henderson                             TCGReg dst, TCGReg src);
118d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
119d6ecb4a9SRichard Henderson                              TCGReg dst, TCGReg base, intptr_t offset);
1204e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1214e186175SRichard Henderson                              TCGReg dst, int64_t arg);
122d2fd745fSRichard Henderson static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl,
123d2fd745fSRichard Henderson                            unsigned vece, const TCGArg *args,
124d2fd745fSRichard Henderson                            const int *const_args);
125d2fd745fSRichard Henderson #else
126e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
127e7632cfaSRichard Henderson                                    TCGReg dst, TCGReg src)
128e7632cfaSRichard Henderson {
129e7632cfaSRichard Henderson     g_assert_not_reached();
130e7632cfaSRichard Henderson }
131d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
132d6ecb4a9SRichard Henderson                                     TCGReg dst, TCGReg base, intptr_t offset)
133d6ecb4a9SRichard Henderson {
134d6ecb4a9SRichard Henderson     g_assert_not_reached();
135d6ecb4a9SRichard Henderson }
1364e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1374e186175SRichard Henderson                                     TCGReg dst, int64_t arg)
138e7632cfaSRichard Henderson {
139e7632cfaSRichard Henderson     g_assert_not_reached();
140e7632cfaSRichard Henderson }
141d2fd745fSRichard Henderson static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl,
142d2fd745fSRichard Henderson                                   unsigned vece, const TCGArg *args,
143d2fd745fSRichard Henderson                                   const int *const_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 
352*4c22e840SRichard Henderson #ifdef TCG_TARGET_CON_SET_H
353*4c22e840SRichard Henderson #define C_PFX1(P, A)                    P##A
354*4c22e840SRichard Henderson #define C_PFX2(P, A, B)                 P##A##_##B
355*4c22e840SRichard Henderson #define C_PFX3(P, A, B, C)              P##A##_##B##_##C
356*4c22e840SRichard Henderson #define C_PFX4(P, A, B, C, D)           P##A##_##B##_##C##_##D
357*4c22e840SRichard Henderson #define C_PFX5(P, A, B, C, D, E)        P##A##_##B##_##C##_##D##_##E
358*4c22e840SRichard Henderson #define C_PFX6(P, A, B, C, D, E, F)     P##A##_##B##_##C##_##D##_##E##_##F
359*4c22e840SRichard Henderson 
360*4c22e840SRichard Henderson /* Define an enumeration for the various combinations. */
361*4c22e840SRichard Henderson 
362*4c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1),
363*4c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2),
364*4c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3),
365*4c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4),
366*4c22e840SRichard Henderson 
367*4c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1),
368*4c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2),
369*4c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3),
370*4c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4),
371*4c22e840SRichard Henderson 
372*4c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2),
373*4c22e840SRichard Henderson 
374*4c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1),
375*4c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2),
376*4c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3),
377*4c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4),
378*4c22e840SRichard Henderson 
379*4c22e840SRichard Henderson typedef enum {
380*4c22e840SRichard Henderson #include "tcg-target-con-set.h"
381*4c22e840SRichard Henderson } TCGConstraintSetIndex;
382*4c22e840SRichard Henderson 
383*4c22e840SRichard Henderson static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode);
384*4c22e840SRichard Henderson 
385*4c22e840SRichard Henderson #undef C_O0_I1
386*4c22e840SRichard Henderson #undef C_O0_I2
387*4c22e840SRichard Henderson #undef C_O0_I3
388*4c22e840SRichard Henderson #undef C_O0_I4
389*4c22e840SRichard Henderson #undef C_O1_I1
390*4c22e840SRichard Henderson #undef C_O1_I2
391*4c22e840SRichard Henderson #undef C_O1_I3
392*4c22e840SRichard Henderson #undef C_O1_I4
393*4c22e840SRichard Henderson #undef C_N1_I2
394*4c22e840SRichard Henderson #undef C_O2_I1
395*4c22e840SRichard Henderson #undef C_O2_I2
396*4c22e840SRichard Henderson #undef C_O2_I3
397*4c22e840SRichard Henderson #undef C_O2_I4
398*4c22e840SRichard Henderson 
399*4c22e840SRichard Henderson /* Put all of the constraint sets into an array, indexed by the enum. */
400*4c22e840SRichard Henderson 
401*4c22e840SRichard Henderson #define C_O0_I1(I1)                     { .args_ct_str = { #I1 } },
402*4c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 { .args_ct_str = { #I1, #I2 } },
403*4c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             { .args_ct_str = { #I1, #I2, #I3 } },
404*4c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         { .args_ct_str = { #I1, #I2, #I3, #I4 } },
405*4c22e840SRichard Henderson 
406*4c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 { .args_ct_str = { #O1, #I1 } },
407*4c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             { .args_ct_str = { #O1, #I1, #I2 } },
408*4c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         { .args_ct_str = { #O1, #I1, #I2, #I3 } },
409*4c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     { .args_ct_str = { #O1, #I1, #I2, #I3, #I4 } },
410*4c22e840SRichard Henderson 
411*4c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             { .args_ct_str = { "&" #O1, #I1, #I2 } },
412*4c22e840SRichard Henderson 
413*4c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             { .args_ct_str = { #O1, #O2, #I1 } },
414*4c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         { .args_ct_str = { #O1, #O2, #I1, #I2 } },
415*4c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } },
416*4c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } },
417*4c22e840SRichard Henderson 
418*4c22e840SRichard Henderson static const TCGTargetOpDef constraint_sets[] = {
419*4c22e840SRichard Henderson #include "tcg-target-con-set.h"
420*4c22e840SRichard Henderson };
421*4c22e840SRichard Henderson 
422*4c22e840SRichard Henderson 
423*4c22e840SRichard Henderson #undef C_O0_I1
424*4c22e840SRichard Henderson #undef C_O0_I2
425*4c22e840SRichard Henderson #undef C_O0_I3
426*4c22e840SRichard Henderson #undef C_O0_I4
427*4c22e840SRichard Henderson #undef C_O1_I1
428*4c22e840SRichard Henderson #undef C_O1_I2
429*4c22e840SRichard Henderson #undef C_O1_I3
430*4c22e840SRichard Henderson #undef C_O1_I4
431*4c22e840SRichard Henderson #undef C_N1_I2
432*4c22e840SRichard Henderson #undef C_O2_I1
433*4c22e840SRichard Henderson #undef C_O2_I2
434*4c22e840SRichard Henderson #undef C_O2_I3
435*4c22e840SRichard Henderson #undef C_O2_I4
436*4c22e840SRichard Henderson 
437*4c22e840SRichard Henderson /* Expand the enumerator to be returned from tcg_target_op_def(). */
438*4c22e840SRichard Henderson 
439*4c22e840SRichard Henderson #define C_O0_I1(I1)                     C_PFX1(c_o0_i1_, I1)
440*4c22e840SRichard Henderson #define C_O0_I2(I1, I2)                 C_PFX2(c_o0_i2_, I1, I2)
441*4c22e840SRichard Henderson #define C_O0_I3(I1, I2, I3)             C_PFX3(c_o0_i3_, I1, I2, I3)
442*4c22e840SRichard Henderson #define C_O0_I4(I1, I2, I3, I4)         C_PFX4(c_o0_i4_, I1, I2, I3, I4)
443*4c22e840SRichard Henderson 
444*4c22e840SRichard Henderson #define C_O1_I1(O1, I1)                 C_PFX2(c_o1_i1_, O1, I1)
445*4c22e840SRichard Henderson #define C_O1_I2(O1, I1, I2)             C_PFX3(c_o1_i2_, O1, I1, I2)
446*4c22e840SRichard Henderson #define C_O1_I3(O1, I1, I2, I3)         C_PFX4(c_o1_i3_, O1, I1, I2, I3)
447*4c22e840SRichard Henderson #define C_O1_I4(O1, I1, I2, I3, I4)     C_PFX5(c_o1_i4_, O1, I1, I2, I3, I4)
448*4c22e840SRichard Henderson 
449*4c22e840SRichard Henderson #define C_N1_I2(O1, I1, I2)             C_PFX3(c_n1_i2_, O1, I1, I2)
450*4c22e840SRichard Henderson 
451*4c22e840SRichard Henderson #define C_O2_I1(O1, O2, I1)             C_PFX3(c_o2_i1_, O1, O2, I1)
452*4c22e840SRichard Henderson #define C_O2_I2(O1, O2, I1, I2)         C_PFX4(c_o2_i2_, O1, O2, I1, I2)
453*4c22e840SRichard Henderson #define C_O2_I3(O1, O2, I1, I2, I3)     C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3)
454*4c22e840SRichard Henderson #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4)
455*4c22e840SRichard Henderson 
456*4c22e840SRichard Henderson #endif /* TCG_TARGET_CON_SET_H */
457*4c22e840SRichard Henderson 
458139c1837SPaolo Bonzini #include "tcg-target.c.inc"
459c896fe29Sbellard 
460be2cdc5eSEmilio G. Cota /* compare a pointer @ptr and a tb_tc @s */
461be2cdc5eSEmilio G. Cota static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s)
462be2cdc5eSEmilio G. Cota {
463be2cdc5eSEmilio G. Cota     if (ptr >= s->ptr + s->size) {
464be2cdc5eSEmilio G. Cota         return 1;
465be2cdc5eSEmilio G. Cota     } else if (ptr < s->ptr) {
466be2cdc5eSEmilio G. Cota         return -1;
467be2cdc5eSEmilio G. Cota     }
468be2cdc5eSEmilio G. Cota     return 0;
469be2cdc5eSEmilio G. Cota }
470be2cdc5eSEmilio G. Cota 
471be2cdc5eSEmilio G. Cota static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp)
472be2cdc5eSEmilio G. Cota {
473be2cdc5eSEmilio G. Cota     const struct tb_tc *a = ap;
474be2cdc5eSEmilio G. Cota     const struct tb_tc *b = bp;
475be2cdc5eSEmilio G. Cota 
476be2cdc5eSEmilio G. Cota     /*
477be2cdc5eSEmilio G. Cota      * When both sizes are set, we know this isn't a lookup.
478be2cdc5eSEmilio G. Cota      * This is the most likely case: every TB must be inserted; lookups
479be2cdc5eSEmilio G. Cota      * are a lot less frequent.
480be2cdc5eSEmilio G. Cota      */
481be2cdc5eSEmilio G. Cota     if (likely(a->size && b->size)) {
482be2cdc5eSEmilio G. Cota         if (a->ptr > b->ptr) {
483be2cdc5eSEmilio G. Cota             return 1;
484be2cdc5eSEmilio G. Cota         } else if (a->ptr < b->ptr) {
485be2cdc5eSEmilio G. Cota             return -1;
486be2cdc5eSEmilio G. Cota         }
487be2cdc5eSEmilio G. Cota         /* a->ptr == b->ptr should happen only on deletions */
488be2cdc5eSEmilio G. Cota         g_assert(a->size == b->size);
489be2cdc5eSEmilio G. Cota         return 0;
490be2cdc5eSEmilio G. Cota     }
491be2cdc5eSEmilio G. Cota     /*
492be2cdc5eSEmilio G. Cota      * All lookups have either .size field set to 0.
493be2cdc5eSEmilio G. Cota      * From the glib sources we see that @ap is always the lookup key. However
494be2cdc5eSEmilio G. Cota      * the docs provide no guarantee, so we just mark this case as likely.
495be2cdc5eSEmilio G. Cota      */
496be2cdc5eSEmilio G. Cota     if (likely(a->size == 0)) {
497be2cdc5eSEmilio G. Cota         return ptr_cmp_tb_tc(a->ptr, b);
498be2cdc5eSEmilio G. Cota     }
499be2cdc5eSEmilio G. Cota     return ptr_cmp_tb_tc(b->ptr, a);
500be2cdc5eSEmilio G. Cota }
501be2cdc5eSEmilio G. Cota 
502be2cdc5eSEmilio G. Cota static void tcg_region_trees_init(void)
503be2cdc5eSEmilio G. Cota {
504be2cdc5eSEmilio G. Cota     size_t i;
505be2cdc5eSEmilio G. Cota 
506be2cdc5eSEmilio G. Cota     tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize);
507be2cdc5eSEmilio G. Cota     region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size);
508be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
509be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
510be2cdc5eSEmilio G. Cota 
511be2cdc5eSEmilio G. Cota         qemu_mutex_init(&rt->lock);
512be2cdc5eSEmilio G. Cota         rt->tree = g_tree_new(tb_tc_cmp);
513be2cdc5eSEmilio G. Cota     }
514be2cdc5eSEmilio G. Cota }
515be2cdc5eSEmilio G. Cota 
516db0c51a3SRichard Henderson static struct tcg_region_tree *tc_ptr_to_region_tree(const void *cp)
517be2cdc5eSEmilio G. Cota {
518db0c51a3SRichard Henderson     void *p = tcg_splitwx_to_rw(cp);
519be2cdc5eSEmilio G. Cota     size_t region_idx;
520be2cdc5eSEmilio G. Cota 
521be2cdc5eSEmilio G. Cota     if (p < region.start_aligned) {
522be2cdc5eSEmilio G. Cota         region_idx = 0;
523be2cdc5eSEmilio G. Cota     } else {
524be2cdc5eSEmilio G. Cota         ptrdiff_t offset = p - region.start_aligned;
525be2cdc5eSEmilio G. Cota 
526be2cdc5eSEmilio G. Cota         if (offset > region.stride * (region.n - 1)) {
527be2cdc5eSEmilio G. Cota             region_idx = region.n - 1;
528be2cdc5eSEmilio G. Cota         } else {
529be2cdc5eSEmilio G. Cota             region_idx = offset / region.stride;
530be2cdc5eSEmilio G. Cota         }
531be2cdc5eSEmilio G. Cota     }
532be2cdc5eSEmilio G. Cota     return region_trees + region_idx * tree_size;
533be2cdc5eSEmilio G. Cota }
534be2cdc5eSEmilio G. Cota 
535be2cdc5eSEmilio G. Cota void tcg_tb_insert(TranslationBlock *tb)
536be2cdc5eSEmilio G. Cota {
537be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
538be2cdc5eSEmilio G. Cota 
539be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
540be2cdc5eSEmilio G. Cota     g_tree_insert(rt->tree, &tb->tc, tb);
541be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
542be2cdc5eSEmilio G. Cota }
543be2cdc5eSEmilio G. Cota 
544be2cdc5eSEmilio G. Cota void tcg_tb_remove(TranslationBlock *tb)
545be2cdc5eSEmilio G. Cota {
546be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
547be2cdc5eSEmilio G. Cota 
548be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
549be2cdc5eSEmilio G. Cota     g_tree_remove(rt->tree, &tb->tc);
550be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
551be2cdc5eSEmilio G. Cota }
552be2cdc5eSEmilio G. Cota 
553be2cdc5eSEmilio G. Cota /*
554be2cdc5eSEmilio G. Cota  * Find the TB 'tb' such that
555be2cdc5eSEmilio G. Cota  * tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size
556be2cdc5eSEmilio G. Cota  * Return NULL if not found.
557be2cdc5eSEmilio G. Cota  */
558be2cdc5eSEmilio G. Cota TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr)
559be2cdc5eSEmilio G. Cota {
560be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr);
561be2cdc5eSEmilio G. Cota     TranslationBlock *tb;
562be2cdc5eSEmilio G. Cota     struct tb_tc s = { .ptr = (void *)tc_ptr };
563be2cdc5eSEmilio G. Cota 
564be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
565be2cdc5eSEmilio G. Cota     tb = g_tree_lookup(rt->tree, &s);
566be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
567be2cdc5eSEmilio G. Cota     return tb;
568be2cdc5eSEmilio G. Cota }
569be2cdc5eSEmilio G. Cota 
570be2cdc5eSEmilio G. Cota static void tcg_region_tree_lock_all(void)
571be2cdc5eSEmilio G. Cota {
572be2cdc5eSEmilio G. Cota     size_t i;
573be2cdc5eSEmilio G. Cota 
574be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
575be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
576be2cdc5eSEmilio G. Cota 
577be2cdc5eSEmilio G. Cota         qemu_mutex_lock(&rt->lock);
578be2cdc5eSEmilio G. Cota     }
579be2cdc5eSEmilio G. Cota }
580be2cdc5eSEmilio G. Cota 
581be2cdc5eSEmilio G. Cota static void tcg_region_tree_unlock_all(void)
582be2cdc5eSEmilio G. Cota {
583be2cdc5eSEmilio G. Cota     size_t i;
584be2cdc5eSEmilio G. Cota 
585be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
586be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
587be2cdc5eSEmilio G. Cota 
588be2cdc5eSEmilio G. Cota         qemu_mutex_unlock(&rt->lock);
589be2cdc5eSEmilio G. Cota     }
590be2cdc5eSEmilio G. Cota }
591be2cdc5eSEmilio G. Cota 
592be2cdc5eSEmilio G. Cota void tcg_tb_foreach(GTraverseFunc func, gpointer user_data)
593be2cdc5eSEmilio G. Cota {
594be2cdc5eSEmilio G. Cota     size_t i;
595be2cdc5eSEmilio G. Cota 
596be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
597be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
598be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
599be2cdc5eSEmilio G. Cota 
600be2cdc5eSEmilio G. Cota         g_tree_foreach(rt->tree, func, user_data);
601be2cdc5eSEmilio G. Cota     }
602be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
603be2cdc5eSEmilio G. Cota }
604be2cdc5eSEmilio G. Cota 
605be2cdc5eSEmilio G. Cota size_t tcg_nb_tbs(void)
606be2cdc5eSEmilio G. Cota {
607be2cdc5eSEmilio G. Cota     size_t nb_tbs = 0;
608be2cdc5eSEmilio G. Cota     size_t i;
609be2cdc5eSEmilio G. Cota 
610be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
611be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
612be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
613be2cdc5eSEmilio G. Cota 
614be2cdc5eSEmilio G. Cota         nb_tbs += g_tree_nnodes(rt->tree);
615be2cdc5eSEmilio G. Cota     }
616be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
617be2cdc5eSEmilio G. Cota     return nb_tbs;
618be2cdc5eSEmilio G. Cota }
619be2cdc5eSEmilio G. Cota 
620938e897aSEmilio G. Cota static gboolean tcg_region_tree_traverse(gpointer k, gpointer v, gpointer data)
621938e897aSEmilio G. Cota {
622938e897aSEmilio G. Cota     TranslationBlock *tb = v;
623938e897aSEmilio G. Cota 
624938e897aSEmilio G. Cota     tb_destroy(tb);
625938e897aSEmilio G. Cota     return FALSE;
626938e897aSEmilio G. Cota }
627938e897aSEmilio G. Cota 
628be2cdc5eSEmilio G. Cota static void tcg_region_tree_reset_all(void)
629be2cdc5eSEmilio G. Cota {
630be2cdc5eSEmilio G. Cota     size_t i;
631be2cdc5eSEmilio G. Cota 
632be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
633be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
634be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
635be2cdc5eSEmilio G. Cota 
636938e897aSEmilio G. Cota         g_tree_foreach(rt->tree, tcg_region_tree_traverse, NULL);
637be2cdc5eSEmilio G. Cota         /* Increment the refcount first so that destroy acts as a reset */
638be2cdc5eSEmilio G. Cota         g_tree_ref(rt->tree);
639be2cdc5eSEmilio G. Cota         g_tree_destroy(rt->tree);
640be2cdc5eSEmilio G. Cota     }
641be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
642be2cdc5eSEmilio G. Cota }
643be2cdc5eSEmilio G. Cota 
644e8feb96fSEmilio G. Cota static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend)
645e8feb96fSEmilio G. Cota {
646e8feb96fSEmilio G. Cota     void *start, *end;
647e8feb96fSEmilio G. Cota 
648e8feb96fSEmilio G. Cota     start = region.start_aligned + curr_region * region.stride;
649e8feb96fSEmilio G. Cota     end = start + region.size;
650e8feb96fSEmilio G. Cota 
651e8feb96fSEmilio G. Cota     if (curr_region == 0) {
652e8feb96fSEmilio G. Cota         start = region.start;
653e8feb96fSEmilio G. Cota     }
654e8feb96fSEmilio G. Cota     if (curr_region == region.n - 1) {
655e8feb96fSEmilio G. Cota         end = region.end;
656e8feb96fSEmilio G. Cota     }
657e8feb96fSEmilio G. Cota 
658e8feb96fSEmilio G. Cota     *pstart = start;
659e8feb96fSEmilio G. Cota     *pend = end;
660e8feb96fSEmilio G. Cota }
661e8feb96fSEmilio G. Cota 
662e8feb96fSEmilio G. Cota static void tcg_region_assign(TCGContext *s, size_t curr_region)
663e8feb96fSEmilio G. Cota {
664e8feb96fSEmilio G. Cota     void *start, *end;
665e8feb96fSEmilio G. Cota 
666e8feb96fSEmilio G. Cota     tcg_region_bounds(curr_region, &start, &end);
667e8feb96fSEmilio G. Cota 
668e8feb96fSEmilio G. Cota     s->code_gen_buffer = start;
669e8feb96fSEmilio G. Cota     s->code_gen_ptr = start;
670e8feb96fSEmilio G. Cota     s->code_gen_buffer_size = end - start;
671e8feb96fSEmilio G. Cota     s->code_gen_highwater = end - TCG_HIGHWATER;
672e8feb96fSEmilio G. Cota }
673e8feb96fSEmilio G. Cota 
674e8feb96fSEmilio G. Cota static bool tcg_region_alloc__locked(TCGContext *s)
675e8feb96fSEmilio G. Cota {
676e8feb96fSEmilio G. Cota     if (region.current == region.n) {
677e8feb96fSEmilio G. Cota         return true;
678e8feb96fSEmilio G. Cota     }
679e8feb96fSEmilio G. Cota     tcg_region_assign(s, region.current);
680e8feb96fSEmilio G. Cota     region.current++;
681e8feb96fSEmilio G. Cota     return false;
682e8feb96fSEmilio G. Cota }
683e8feb96fSEmilio G. Cota 
684e8feb96fSEmilio G. Cota /*
685e8feb96fSEmilio G. Cota  * Request a new region once the one in use has filled up.
686e8feb96fSEmilio G. Cota  * Returns true on error.
687e8feb96fSEmilio G. Cota  */
688e8feb96fSEmilio G. Cota static bool tcg_region_alloc(TCGContext *s)
689e8feb96fSEmilio G. Cota {
690e8feb96fSEmilio G. Cota     bool err;
691e8feb96fSEmilio G. Cota     /* read the region size now; alloc__locked will overwrite it on success */
692e8feb96fSEmilio G. Cota     size_t size_full = s->code_gen_buffer_size;
693e8feb96fSEmilio G. Cota 
694e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
695e8feb96fSEmilio G. Cota     err = tcg_region_alloc__locked(s);
696e8feb96fSEmilio G. Cota     if (!err) {
697e8feb96fSEmilio G. Cota         region.agg_size_full += size_full - TCG_HIGHWATER;
698e8feb96fSEmilio G. Cota     }
699e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
700e8feb96fSEmilio G. Cota     return err;
701e8feb96fSEmilio G. Cota }
702e8feb96fSEmilio G. Cota 
703e8feb96fSEmilio G. Cota /*
704e8feb96fSEmilio G. Cota  * Perform a context's first region allocation.
705e8feb96fSEmilio G. Cota  * This function does _not_ increment region.agg_size_full.
706e8feb96fSEmilio G. Cota  */
707e8feb96fSEmilio G. Cota static inline bool tcg_region_initial_alloc__locked(TCGContext *s)
708e8feb96fSEmilio G. Cota {
709e8feb96fSEmilio G. Cota     return tcg_region_alloc__locked(s);
710e8feb96fSEmilio G. Cota }
711e8feb96fSEmilio G. Cota 
712e8feb96fSEmilio G. Cota /* Call from a safe-work context */
713e8feb96fSEmilio G. Cota void tcg_region_reset_all(void)
714e8feb96fSEmilio G. Cota {
715d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
716e8feb96fSEmilio G. Cota     unsigned int i;
717e8feb96fSEmilio G. Cota 
718e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
719e8feb96fSEmilio G. Cota     region.current = 0;
720e8feb96fSEmilio G. Cota     region.agg_size_full = 0;
721e8feb96fSEmilio G. Cota 
7223468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
723d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
7243468b59eSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(s);
725e8feb96fSEmilio G. Cota 
726e8feb96fSEmilio G. Cota         g_assert(!err);
727e8feb96fSEmilio G. Cota     }
728e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
729be2cdc5eSEmilio G. Cota 
730be2cdc5eSEmilio G. Cota     tcg_region_tree_reset_all();
731e8feb96fSEmilio G. Cota }
732e8feb96fSEmilio G. Cota 
7333468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
7343468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
7353468b59eSEmilio G. Cota {
7363468b59eSEmilio G. Cota     return 1;
7373468b59eSEmilio G. Cota }
7383468b59eSEmilio G. Cota #else
7393468b59eSEmilio G. Cota /*
7403468b59eSEmilio G. Cota  * It is likely that some vCPUs will translate more code than others, so we
7413468b59eSEmilio G. Cota  * first try to set more regions than max_cpus, with those regions being of
7423468b59eSEmilio G. Cota  * reasonable size. If that's not possible we make do by evenly dividing
7433468b59eSEmilio G. Cota  * the code_gen_buffer among the vCPUs.
7443468b59eSEmilio G. Cota  */
7453468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
7463468b59eSEmilio G. Cota {
7473468b59eSEmilio G. Cota     size_t i;
7483468b59eSEmilio G. Cota 
7493468b59eSEmilio G. Cota     /* Use a single region if all we have is one vCPU thread */
7505cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY)
7515cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
7525cc8767dSLike Xu     unsigned int max_cpus = ms->smp.max_cpus;
7535cc8767dSLike Xu #endif
7543468b59eSEmilio G. Cota     if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) {
7553468b59eSEmilio G. Cota         return 1;
7563468b59eSEmilio G. Cota     }
7573468b59eSEmilio G. Cota 
7583468b59eSEmilio G. Cota     /* Try to have more regions than max_cpus, with each region being >= 2 MB */
7593468b59eSEmilio G. Cota     for (i = 8; i > 0; i--) {
7603468b59eSEmilio G. Cota         size_t regions_per_thread = i;
7613468b59eSEmilio G. Cota         size_t region_size;
7623468b59eSEmilio G. Cota 
7633468b59eSEmilio G. Cota         region_size = tcg_init_ctx.code_gen_buffer_size;
7643468b59eSEmilio G. Cota         region_size /= max_cpus * regions_per_thread;
7653468b59eSEmilio G. Cota 
7663468b59eSEmilio G. Cota         if (region_size >= 2 * 1024u * 1024) {
7673468b59eSEmilio G. Cota             return max_cpus * regions_per_thread;
7683468b59eSEmilio G. Cota         }
7693468b59eSEmilio G. Cota     }
7703468b59eSEmilio G. Cota     /* If we can't, then just allocate one region per vCPU thread */
7713468b59eSEmilio G. Cota     return max_cpus;
7723468b59eSEmilio G. Cota }
7733468b59eSEmilio G. Cota #endif
7743468b59eSEmilio G. Cota 
775e8feb96fSEmilio G. Cota /*
776e8feb96fSEmilio G. Cota  * Initializes region partitioning.
777e8feb96fSEmilio G. Cota  *
778e8feb96fSEmilio G. Cota  * Called at init time from the parent thread (i.e. the one calling
779e8feb96fSEmilio G. Cota  * tcg_context_init), after the target's TCG globals have been set.
7803468b59eSEmilio G. Cota  *
7813468b59eSEmilio G. Cota  * Region partitioning works by splitting code_gen_buffer into separate regions,
7823468b59eSEmilio G. Cota  * and then assigning regions to TCG threads so that the threads can translate
7833468b59eSEmilio G. Cota  * code in parallel without synchronization.
7843468b59eSEmilio G. Cota  *
7853468b59eSEmilio G. Cota  * In softmmu the number of TCG threads is bounded by max_cpus, so we use at
7863468b59eSEmilio G. Cota  * least max_cpus regions in MTTCG. In !MTTCG we use a single region.
7873468b59eSEmilio G. Cota  * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...])
7883468b59eSEmilio G. Cota  * must have been parsed before calling this function, since it calls
7893468b59eSEmilio G. Cota  * qemu_tcg_mttcg_enabled().
7903468b59eSEmilio G. Cota  *
7913468b59eSEmilio G. Cota  * In user-mode we use a single region.  Having multiple regions in user-mode
7923468b59eSEmilio G. Cota  * is not supported, because the number of vCPU threads (recall that each thread
7933468b59eSEmilio G. Cota  * spawned by the guest corresponds to a vCPU thread) is only bounded by the
7943468b59eSEmilio G. Cota  * OS, and usually this number is huge (tens of thousands is not uncommon).
7953468b59eSEmilio G. Cota  * Thus, given this large bound on the number of vCPU threads and the fact
7963468b59eSEmilio G. Cota  * that code_gen_buffer is allocated at compile-time, we cannot guarantee
7973468b59eSEmilio G. Cota  * that the availability of at least one region per vCPU thread.
7983468b59eSEmilio G. Cota  *
7993468b59eSEmilio G. Cota  * However, this user-mode limitation is unlikely to be a significant problem
8003468b59eSEmilio G. Cota  * in practice. Multi-threaded guests share most if not all of their translated
8013468b59eSEmilio G. Cota  * code, which makes parallel code generation less appealing than in softmmu.
802e8feb96fSEmilio G. Cota  */
803e8feb96fSEmilio G. Cota void tcg_region_init(void)
804e8feb96fSEmilio G. Cota {
805e8feb96fSEmilio G. Cota     void *buf = tcg_init_ctx.code_gen_buffer;
806e8feb96fSEmilio G. Cota     void *aligned;
807e8feb96fSEmilio G. Cota     size_t size = tcg_init_ctx.code_gen_buffer_size;
808e8feb96fSEmilio G. Cota     size_t page_size = qemu_real_host_page_size;
809e8feb96fSEmilio G. Cota     size_t region_size;
810e8feb96fSEmilio G. Cota     size_t n_regions;
811e8feb96fSEmilio G. Cota     size_t i;
812db0c51a3SRichard Henderson     uintptr_t splitwx_diff;
813e8feb96fSEmilio G. Cota 
8143468b59eSEmilio G. Cota     n_regions = tcg_n_regions();
815e8feb96fSEmilio G. Cota 
816e8feb96fSEmilio G. Cota     /* The first region will be 'aligned - buf' bytes larger than the others */
817e8feb96fSEmilio G. Cota     aligned = QEMU_ALIGN_PTR_UP(buf, page_size);
818e8feb96fSEmilio G. Cota     g_assert(aligned < tcg_init_ctx.code_gen_buffer + size);
819e8feb96fSEmilio G. Cota     /*
820e8feb96fSEmilio G. Cota      * Make region_size a multiple of page_size, using aligned as the start.
821e8feb96fSEmilio G. Cota      * As a result of this we might end up with a few extra pages at the end of
822e8feb96fSEmilio G. Cota      * the buffer; we will assign those to the last region.
823e8feb96fSEmilio G. Cota      */
824e8feb96fSEmilio G. Cota     region_size = (size - (aligned - buf)) / n_regions;
825e8feb96fSEmilio G. Cota     region_size = QEMU_ALIGN_DOWN(region_size, page_size);
826e8feb96fSEmilio G. Cota 
827e8feb96fSEmilio G. Cota     /* A region must have at least 2 pages; one code, one guard */
828e8feb96fSEmilio G. Cota     g_assert(region_size >= 2 * page_size);
829e8feb96fSEmilio G. Cota 
830e8feb96fSEmilio G. Cota     /* init the region struct */
831e8feb96fSEmilio G. Cota     qemu_mutex_init(&region.lock);
832e8feb96fSEmilio G. Cota     region.n = n_regions;
833e8feb96fSEmilio G. Cota     region.size = region_size - page_size;
834e8feb96fSEmilio G. Cota     region.stride = region_size;
835e8feb96fSEmilio G. Cota     region.start = buf;
836e8feb96fSEmilio G. Cota     region.start_aligned = aligned;
837e8feb96fSEmilio G. Cota     /* page-align the end, since its last page will be a guard page */
838e8feb96fSEmilio G. Cota     region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size);
839e8feb96fSEmilio G. Cota     /* account for that last guard page */
840e8feb96fSEmilio G. Cota     region.end -= page_size;
841e8feb96fSEmilio G. Cota 
842e8feb96fSEmilio G. Cota     /* set guard pages */
843db0c51a3SRichard Henderson     splitwx_diff = tcg_splitwx_diff;
844e8feb96fSEmilio G. Cota     for (i = 0; i < region.n; i++) {
845e8feb96fSEmilio G. Cota         void *start, *end;
846e8feb96fSEmilio G. Cota         int rc;
847e8feb96fSEmilio G. Cota 
848e8feb96fSEmilio G. Cota         tcg_region_bounds(i, &start, &end);
849e8feb96fSEmilio G. Cota         rc = qemu_mprotect_none(end, page_size);
850e8feb96fSEmilio G. Cota         g_assert(!rc);
851db0c51a3SRichard Henderson         if (splitwx_diff) {
852db0c51a3SRichard Henderson             rc = qemu_mprotect_none(end + splitwx_diff, page_size);
853db0c51a3SRichard Henderson             g_assert(!rc);
854db0c51a3SRichard Henderson         }
855e8feb96fSEmilio G. Cota     }
856e8feb96fSEmilio G. Cota 
857be2cdc5eSEmilio G. Cota     tcg_region_trees_init();
858be2cdc5eSEmilio G. Cota 
8593468b59eSEmilio G. Cota     /* In user-mode we support only one ctx, so do the initial allocation now */
8603468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
861e8feb96fSEmilio G. Cota     {
862e8feb96fSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(tcg_ctx);
863e8feb96fSEmilio G. Cota 
864e8feb96fSEmilio G. Cota         g_assert(!err);
865e8feb96fSEmilio G. Cota     }
8663468b59eSEmilio G. Cota #endif
867e8feb96fSEmilio G. Cota }
868e8feb96fSEmilio G. Cota 
869db0c51a3SRichard Henderson #ifdef CONFIG_DEBUG_TCG
870db0c51a3SRichard Henderson const void *tcg_splitwx_to_rx(void *rw)
871db0c51a3SRichard Henderson {
872db0c51a3SRichard Henderson     /* Pass NULL pointers unchanged. */
873db0c51a3SRichard Henderson     if (rw) {
874db0c51a3SRichard Henderson         g_assert(in_code_gen_buffer(rw));
875db0c51a3SRichard Henderson         rw += tcg_splitwx_diff;
876db0c51a3SRichard Henderson     }
877db0c51a3SRichard Henderson     return rw;
878db0c51a3SRichard Henderson }
879db0c51a3SRichard Henderson 
880db0c51a3SRichard Henderson void *tcg_splitwx_to_rw(const void *rx)
881db0c51a3SRichard Henderson {
882db0c51a3SRichard Henderson     /* Pass NULL pointers unchanged. */
883db0c51a3SRichard Henderson     if (rx) {
884db0c51a3SRichard Henderson         rx -= tcg_splitwx_diff;
885db0c51a3SRichard Henderson         /* Assert that we end with a pointer in the rw region. */
886db0c51a3SRichard Henderson         g_assert(in_code_gen_buffer(rx));
887db0c51a3SRichard Henderson     }
888db0c51a3SRichard Henderson     return (void *)rx;
889db0c51a3SRichard Henderson }
890db0c51a3SRichard Henderson #endif /* CONFIG_DEBUG_TCG */
891db0c51a3SRichard Henderson 
89238b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s)
89338b47b19SEmilio G. Cota {
89438b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
89538b47b19SEmilio G. Cota     s->plugin_tb = g_new0(struct qemu_plugin_tb, 1);
89638b47b19SEmilio G. Cota     s->plugin_tb->insns =
89738b47b19SEmilio G. Cota         g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn);
89838b47b19SEmilio G. Cota #endif
89938b47b19SEmilio G. Cota }
90038b47b19SEmilio G. Cota 
901e8feb96fSEmilio G. Cota /*
9023468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
9033468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
9043468b59eSEmilio G. Cota  * before initiating translation.
9053468b59eSEmilio G. Cota  *
9063468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
9073468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
9083468b59eSEmilio G. Cota  *
9093468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
9103468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
9113468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
9123468b59eSEmilio G. Cota  *
9133468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
9143468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
9153468b59eSEmilio G. Cota  */
9163468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
9173468b59eSEmilio G. Cota void tcg_register_thread(void)
9183468b59eSEmilio G. Cota {
9193468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
9203468b59eSEmilio G. Cota }
9213468b59eSEmilio G. Cota #else
9223468b59eSEmilio G. Cota void tcg_register_thread(void)
9233468b59eSEmilio G. Cota {
9245cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
9253468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
9263468b59eSEmilio G. Cota     unsigned int i, n;
9273468b59eSEmilio G. Cota     bool err;
9283468b59eSEmilio G. Cota 
9293468b59eSEmilio G. Cota     *s = tcg_init_ctx;
9303468b59eSEmilio G. Cota 
9313468b59eSEmilio G. Cota     /* Relink mem_base.  */
9323468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
9333468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
9343468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
9353468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
9363468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
9373468b59eSEmilio G. Cota         }
9383468b59eSEmilio G. Cota     }
9393468b59eSEmilio G. Cota 
9403468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
941d73415a3SStefan Hajnoczi     n = qatomic_fetch_inc(&n_tcg_ctxs);
9425cc8767dSLike Xu     g_assert(n < ms->smp.max_cpus);
943d73415a3SStefan Hajnoczi     qatomic_set(&tcg_ctxs[n], s);
9443468b59eSEmilio G. Cota 
94538b47b19SEmilio G. Cota     if (n > 0) {
94638b47b19SEmilio G. Cota         alloc_tcg_plugin_context(s);
94738b47b19SEmilio G. Cota     }
94838b47b19SEmilio G. Cota 
9493468b59eSEmilio G. Cota     tcg_ctx = s;
9503468b59eSEmilio G. Cota     qemu_mutex_lock(&region.lock);
9513468b59eSEmilio G. Cota     err = tcg_region_initial_alloc__locked(tcg_ctx);
9523468b59eSEmilio G. Cota     g_assert(!err);
9533468b59eSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
9543468b59eSEmilio G. Cota }
9553468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
9563468b59eSEmilio G. Cota 
9573468b59eSEmilio G. Cota /*
958e8feb96fSEmilio G. Cota  * Returns the size (in bytes) of all translated code (i.e. from all regions)
959e8feb96fSEmilio G. Cota  * currently in the cache.
960e8feb96fSEmilio G. Cota  * See also: tcg_code_capacity()
961e8feb96fSEmilio G. Cota  * Do not confuse with tcg_current_code_size(); that one applies to a single
962e8feb96fSEmilio G. Cota  * TCG context.
963e8feb96fSEmilio G. Cota  */
964e8feb96fSEmilio G. Cota size_t tcg_code_size(void)
965e8feb96fSEmilio G. Cota {
966d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
967e8feb96fSEmilio G. Cota     unsigned int i;
968e8feb96fSEmilio G. Cota     size_t total;
969e8feb96fSEmilio G. Cota 
970e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
971e8feb96fSEmilio G. Cota     total = region.agg_size_full;
9723468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
973d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
974e8feb96fSEmilio G. Cota         size_t size;
975e8feb96fSEmilio G. Cota 
976d73415a3SStefan Hajnoczi         size = qatomic_read(&s->code_gen_ptr) - s->code_gen_buffer;
977e8feb96fSEmilio G. Cota         g_assert(size <= s->code_gen_buffer_size);
978e8feb96fSEmilio G. Cota         total += size;
979e8feb96fSEmilio G. Cota     }
980e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
981e8feb96fSEmilio G. Cota     return total;
982e8feb96fSEmilio G. Cota }
983e8feb96fSEmilio G. Cota 
984e8feb96fSEmilio G. Cota /*
985e8feb96fSEmilio G. Cota  * Returns the code capacity (in bytes) of the entire cache, i.e. including all
986e8feb96fSEmilio G. Cota  * regions.
987e8feb96fSEmilio G. Cota  * See also: tcg_code_size()
988e8feb96fSEmilio G. Cota  */
989e8feb96fSEmilio G. Cota size_t tcg_code_capacity(void)
990e8feb96fSEmilio G. Cota {
991e8feb96fSEmilio G. Cota     size_t guard_size, capacity;
992e8feb96fSEmilio G. Cota 
993e8feb96fSEmilio G. Cota     /* no need for synchronization; these variables are set at init time */
994e8feb96fSEmilio G. Cota     guard_size = region.stride - region.size;
995e8feb96fSEmilio G. Cota     capacity = region.end + guard_size - region.start;
996e8feb96fSEmilio G. Cota     capacity -= region.n * (guard_size + TCG_HIGHWATER);
997e8feb96fSEmilio G. Cota     return capacity;
998e8feb96fSEmilio G. Cota }
999e8feb96fSEmilio G. Cota 
1000128ed227SEmilio G. Cota size_t tcg_tb_phys_invalidate_count(void)
1001128ed227SEmilio G. Cota {
1002d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
1003128ed227SEmilio G. Cota     unsigned int i;
1004128ed227SEmilio G. Cota     size_t total = 0;
1005128ed227SEmilio G. Cota 
1006128ed227SEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
1007d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
1008128ed227SEmilio G. Cota 
1009d73415a3SStefan Hajnoczi         total += qatomic_read(&s->tb_phys_invalidate_count);
1010128ed227SEmilio G. Cota     }
1011128ed227SEmilio G. Cota     return total;
1012128ed227SEmilio G. Cota }
1013128ed227SEmilio G. Cota 
1014c896fe29Sbellard /* pool based memory allocation */
1015c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
1016c896fe29Sbellard {
1017c896fe29Sbellard     TCGPool *p;
1018c896fe29Sbellard     int pool_size;
1019c896fe29Sbellard 
1020c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
1021c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
10227267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
1023c896fe29Sbellard         p->size = size;
10244055299eSKirill Batuzov         p->next = s->pool_first_large;
10254055299eSKirill Batuzov         s->pool_first_large = p;
10264055299eSKirill Batuzov         return p->data;
1027c896fe29Sbellard     } else {
1028c896fe29Sbellard         p = s->pool_current;
1029c896fe29Sbellard         if (!p) {
1030c896fe29Sbellard             p = s->pool_first;
1031c896fe29Sbellard             if (!p)
1032c896fe29Sbellard                 goto new_pool;
1033c896fe29Sbellard         } else {
1034c896fe29Sbellard             if (!p->next) {
1035c896fe29Sbellard             new_pool:
1036c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
10377267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
1038c896fe29Sbellard                 p->size = pool_size;
1039c896fe29Sbellard                 p->next = NULL;
1040c896fe29Sbellard                 if (s->pool_current)
1041c896fe29Sbellard                     s->pool_current->next = p;
1042c896fe29Sbellard                 else
1043c896fe29Sbellard                     s->pool_first = p;
1044c896fe29Sbellard             } else {
1045c896fe29Sbellard                 p = p->next;
1046c896fe29Sbellard             }
1047c896fe29Sbellard         }
1048c896fe29Sbellard     }
1049c896fe29Sbellard     s->pool_current = p;
1050c896fe29Sbellard     s->pool_cur = p->data + size;
1051c896fe29Sbellard     s->pool_end = p->data + p->size;
1052c896fe29Sbellard     return p->data;
1053c896fe29Sbellard }
1054c896fe29Sbellard 
1055c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
1056c896fe29Sbellard {
10574055299eSKirill Batuzov     TCGPool *p, *t;
10584055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
10594055299eSKirill Batuzov         t = p->next;
10604055299eSKirill Batuzov         g_free(p);
10614055299eSKirill Batuzov     }
10624055299eSKirill Batuzov     s->pool_first_large = NULL;
1063c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
1064c896fe29Sbellard     s->pool_current = NULL;
1065c896fe29Sbellard }
1066c896fe29Sbellard 
1067100b5e01SRichard Henderson typedef struct TCGHelperInfo {
1068100b5e01SRichard Henderson     void *func;
1069100b5e01SRichard Henderson     const char *name;
1070afb49896SRichard Henderson     unsigned flags;
1071afb49896SRichard Henderson     unsigned sizemask;
1072100b5e01SRichard Henderson } TCGHelperInfo;
1073100b5e01SRichard Henderson 
10742ef6175aSRichard Henderson #include "exec/helper-proto.h"
10752ef6175aSRichard Henderson 
1076100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = {
10772ef6175aSRichard Henderson #include "exec/helper-tcg.h"
1078100b5e01SRichard Henderson };
1079619205fdSEmilio G. Cota static GHashTable *helper_table;
1080100b5e01SRichard Henderson 
108191478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
1082f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
10831c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
10841c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
108591478cefSRichard Henderson 
1086c896fe29Sbellard void tcg_context_init(TCGContext *s)
1087c896fe29Sbellard {
1088100b5e01SRichard Henderson     int op, total_args, n, i;
1089c896fe29Sbellard     TCGOpDef *def;
1090c896fe29Sbellard     TCGArgConstraint *args_ct;
10911c2adb95SRichard Henderson     TCGTemp *ts;
1092c896fe29Sbellard 
1093c896fe29Sbellard     memset(s, 0, sizeof(*s));
1094c896fe29Sbellard     s->nb_globals = 0;
1095c896fe29Sbellard 
1096c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
1097c896fe29Sbellard        space */
1098c896fe29Sbellard     total_args = 0;
1099c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
1100c896fe29Sbellard         def = &tcg_op_defs[op];
1101c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
1102c896fe29Sbellard         total_args += n;
1103c896fe29Sbellard     }
1104c896fe29Sbellard 
1105bc2b17e6SRichard Henderson     args_ct = g_new0(TCGArgConstraint, total_args);
1106c896fe29Sbellard 
1107c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
1108c896fe29Sbellard         def = &tcg_op_defs[op];
1109c896fe29Sbellard         def->args_ct = args_ct;
1110c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
1111c896fe29Sbellard         args_ct += n;
1112c896fe29Sbellard     }
1113c896fe29Sbellard 
11145cd8f621SRichard Henderson     /* Register helpers.  */
111584fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
1116619205fdSEmilio G. Cota     helper_table = g_hash_table_new(NULL, NULL);
111784fd9dd3SRichard Henderson 
1118100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
111984fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
112072866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
1121100b5e01SRichard Henderson     }
11225cd8f621SRichard Henderson 
1123c896fe29Sbellard     tcg_target_init(s);
1124f69d277eSRichard Henderson     process_op_defs(s);
112591478cefSRichard Henderson 
112691478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
112791478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
112891478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
112991478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
113091478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
113191478cefSRichard Henderson             break;
113291478cefSRichard Henderson         }
113391478cefSRichard Henderson     }
113491478cefSRichard Henderson     for (i = 0; i < n; ++i) {
113591478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
113691478cefSRichard Henderson     }
113791478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
113891478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
113991478cefSRichard Henderson     }
1140b1311c4aSEmilio G. Cota 
114138b47b19SEmilio G. Cota     alloc_tcg_plugin_context(s);
114238b47b19SEmilio G. Cota 
1143b1311c4aSEmilio G. Cota     tcg_ctx = s;
11443468b59eSEmilio G. Cota     /*
11453468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
11463468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
11473468b59eSEmilio G. Cota      * reasoning behind this.
11483468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
11493468b59eSEmilio G. Cota      */
11503468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
1151df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
1152df2cce29SEmilio G. Cota     n_tcg_ctxs = 1;
11533468b59eSEmilio G. Cota #else
11545cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
11555cc8767dSLike Xu     unsigned int max_cpus = ms->smp.max_cpus;
11563468b59eSEmilio G. Cota     tcg_ctxs = g_new(TCGContext *, max_cpus);
11573468b59eSEmilio G. Cota #endif
11581c2adb95SRichard Henderson 
11591c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
11601c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
11611c2adb95SRichard Henderson     cpu_env = temp_tcgv_ptr(ts);
11629002ec79SRichard Henderson }
1163b03cce8eSbellard 
11646e3b2bfdSEmilio G. Cota /*
11656e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
11666e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
11676e3b2bfdSEmilio G. Cota  */
11686e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
11696e3b2bfdSEmilio G. Cota {
11706e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
11716e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
11726e3b2bfdSEmilio G. Cota     void *next;
11736e3b2bfdSEmilio G. Cota 
1174e8feb96fSEmilio G. Cota  retry:
11756e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
11766e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
11776e3b2bfdSEmilio G. Cota 
11786e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
1179e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
11806e3b2bfdSEmilio G. Cota             return NULL;
11816e3b2bfdSEmilio G. Cota         }
1182e8feb96fSEmilio G. Cota         goto retry;
1183e8feb96fSEmilio G. Cota     }
1184d73415a3SStefan Hajnoczi     qatomic_set(&s->code_gen_ptr, next);
118557a26946SRichard Henderson     s->data_gen_ptr = NULL;
11866e3b2bfdSEmilio G. Cota     return tb;
11876e3b2bfdSEmilio G. Cota }
11886e3b2bfdSEmilio G. Cota 
11899002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
11909002ec79SRichard Henderson {
11918163b749SRichard Henderson     size_t prologue_size, total_size;
11928163b749SRichard Henderson     void *buf0, *buf1;
11938163b749SRichard Henderson 
11948163b749SRichard Henderson     /* Put the prologue at the beginning of code_gen_buffer.  */
11958163b749SRichard Henderson     buf0 = s->code_gen_buffer;
11965b38ee31SRichard Henderson     total_size = s->code_gen_buffer_size;
11978163b749SRichard Henderson     s->code_ptr = buf0;
11988163b749SRichard Henderson     s->code_buf = buf0;
11995b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
1200b91ccb31SRichard Henderson 
1201db0c51a3SRichard Henderson     /*
1202db0c51a3SRichard Henderson      * The region trees are not yet configured, but tcg_splitwx_to_rx
1203db0c51a3SRichard Henderson      * needs the bounds for an assert.
1204db0c51a3SRichard Henderson      */
1205db0c51a3SRichard Henderson     region.start = buf0;
1206db0c51a3SRichard Henderson     region.end = buf0 + total_size;
1207db0c51a3SRichard Henderson 
1208b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1209db0c51a3SRichard Henderson     tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(buf0);
1210b91ccb31SRichard Henderson #endif
12118163b749SRichard Henderson 
12125b38ee31SRichard Henderson     /* Compute a high-water mark, at which we voluntarily flush the buffer
12135b38ee31SRichard Henderson        and start over.  The size here is arbitrary, significantly larger
12145b38ee31SRichard Henderson        than we expect the code generation for any one opcode to require.  */
12155b38ee31SRichard Henderson     s->code_gen_highwater = s->code_gen_buffer + (total_size - TCG_HIGHWATER);
12165b38ee31SRichard Henderson 
12175b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
12185b38ee31SRichard Henderson     s->pool_labels = NULL;
12195b38ee31SRichard Henderson #endif
12205b38ee31SRichard Henderson 
1221653b87ebSRoman Bolshakov     qemu_thread_jit_write();
12228163b749SRichard Henderson     /* Generate the prologue.  */
1223b03cce8eSbellard     tcg_target_qemu_prologue(s);
12245b38ee31SRichard Henderson 
12255b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
12265b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
12275b38ee31SRichard Henderson     {
12281768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
12291768987bSRichard Henderson         tcg_debug_assert(result == 0);
12305b38ee31SRichard Henderson     }
12315b38ee31SRichard Henderson #endif
12325b38ee31SRichard Henderson 
12338163b749SRichard Henderson     buf1 = s->code_ptr;
1234df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1235db0c51a3SRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(buf0), (uintptr_t)buf0,
12361da8de39SRichard Henderson                         tcg_ptr_byte_diff(buf1, buf0));
1237df5d2b16SRichard Henderson #endif
12388163b749SRichard Henderson 
12398163b749SRichard Henderson     /* Deduct the prologue from the buffer.  */
12408163b749SRichard Henderson     prologue_size = tcg_current_code_size(s);
12418163b749SRichard Henderson     s->code_gen_ptr = buf1;
12428163b749SRichard Henderson     s->code_gen_buffer = buf1;
12438163b749SRichard Henderson     s->code_buf = buf1;
12445b38ee31SRichard Henderson     total_size -= prologue_size;
12458163b749SRichard Henderson     s->code_gen_buffer_size = total_size;
12468163b749SRichard Henderson 
1247755bf9e5SRichard Henderson     tcg_register_jit(tcg_splitwx_to_rx(s->code_gen_buffer), total_size);
1248d6b64b2bSRichard Henderson 
1249d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
1250d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
1251fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
12528163b749SRichard Henderson         qemu_log("PROLOGUE: [size=%zu]\n", prologue_size);
12535b38ee31SRichard Henderson         if (s->data_gen_ptr) {
12545b38ee31SRichard Henderson             size_t code_size = s->data_gen_ptr - buf0;
12555b38ee31SRichard Henderson             size_t data_size = prologue_size - code_size;
12565b38ee31SRichard Henderson             size_t i;
12575b38ee31SRichard Henderson 
12584c389f6eSRichard Henderson             log_disas(buf0, code_size);
12595b38ee31SRichard Henderson 
12605b38ee31SRichard Henderson             for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
12615b38ee31SRichard Henderson                 if (sizeof(tcg_target_ulong) == 8) {
12625b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
12635b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
12645b38ee31SRichard Henderson                              *(uint64_t *)(s->data_gen_ptr + i));
12655b38ee31SRichard Henderson                 } else {
12665b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .long  0x%08x\n",
12675b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
12685b38ee31SRichard Henderson                              *(uint32_t *)(s->data_gen_ptr + i));
12695b38ee31SRichard Henderson                 }
12705b38ee31SRichard Henderson             }
12715b38ee31SRichard Henderson         } else {
12724c389f6eSRichard Henderson             log_disas(buf0, prologue_size);
12735b38ee31SRichard Henderson         }
1274d6b64b2bSRichard Henderson         qemu_log("\n");
1275d6b64b2bSRichard Henderson         qemu_log_flush();
1276fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
1277d6b64b2bSRichard Henderson     }
1278d6b64b2bSRichard Henderson #endif
1279cedbcb01SEmilio G. Cota 
1280cedbcb01SEmilio G. Cota     /* Assert that goto_ptr is implemented completely.  */
1281cedbcb01SEmilio G. Cota     if (TCG_TARGET_HAS_goto_ptr) {
12828b5c2b62SRichard Henderson         tcg_debug_assert(tcg_code_gen_epilogue != NULL);
1283cedbcb01SEmilio G. Cota     }
1284c896fe29Sbellard }
1285c896fe29Sbellard 
1286c896fe29Sbellard void tcg_func_start(TCGContext *s)
1287c896fe29Sbellard {
1288c896fe29Sbellard     tcg_pool_reset(s);
1289c896fe29Sbellard     s->nb_temps = s->nb_globals;
12900ec9eabcSRichard Henderson 
12910ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
12920ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
12930ec9eabcSRichard Henderson 
1294c0522136SRichard Henderson     /* No constant temps have been previously allocated. */
1295c0522136SRichard Henderson     for (int i = 0; i < TCG_TYPE_COUNT; ++i) {
1296c0522136SRichard Henderson         if (s->const_table[i]) {
1297c0522136SRichard Henderson             g_hash_table_remove_all(s->const_table[i]);
1298c0522136SRichard Henderson         }
1299c0522136SRichard Henderson     }
1300c0522136SRichard Henderson 
1301abebf925SRichard Henderson     s->nb_ops = 0;
1302c896fe29Sbellard     s->nb_labels = 0;
1303c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1304c896fe29Sbellard 
13050a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
13060a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
13070a209d4bSRichard Henderson #endif
13080a209d4bSRichard Henderson 
130915fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
131015fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
1311bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
1312c896fe29Sbellard }
1313c896fe29Sbellard 
1314ae30e866SRichard Henderson static TCGTemp *tcg_temp_alloc(TCGContext *s)
13157ca4b752SRichard Henderson {
13167ca4b752SRichard Henderson     int n = s->nb_temps++;
1317ae30e866SRichard Henderson 
1318ae30e866SRichard Henderson     if (n >= TCG_MAX_TEMPS) {
1319ae30e866SRichard Henderson         /* Signal overflow, starting over with fewer guest insns. */
1320ae30e866SRichard Henderson         siglongjmp(s->jmp_trans, -2);
1321ae30e866SRichard Henderson     }
13227ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
13237ca4b752SRichard Henderson }
13247ca4b752SRichard Henderson 
1325ae30e866SRichard Henderson static TCGTemp *tcg_global_alloc(TCGContext *s)
13267ca4b752SRichard Henderson {
1327fa477d25SRichard Henderson     TCGTemp *ts;
1328fa477d25SRichard Henderson 
13297ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
1330ae30e866SRichard Henderson     tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS);
13317ca4b752SRichard Henderson     s->nb_globals++;
1332fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1333ee17db83SRichard Henderson     ts->kind = TEMP_GLOBAL;
1334fa477d25SRichard Henderson 
1335fa477d25SRichard Henderson     return ts;
1336c896fe29Sbellard }
1337c896fe29Sbellard 
1338085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1339b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1340c896fe29Sbellard {
1341c896fe29Sbellard     TCGTemp *ts;
1342c896fe29Sbellard 
1343b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
1344c896fe29Sbellard         tcg_abort();
1345b3a62939SRichard Henderson     }
13467ca4b752SRichard Henderson 
13477ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1348c896fe29Sbellard     ts->base_type = type;
1349c896fe29Sbellard     ts->type = type;
1350ee17db83SRichard Henderson     ts->kind = TEMP_FIXED;
1351c896fe29Sbellard     ts->reg = reg;
1352c896fe29Sbellard     ts->name = name;
1353c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
13547ca4b752SRichard Henderson 
1355085272b3SRichard Henderson     return ts;
1356a7812ae4Spbrook }
1357a7812ae4Spbrook 
1358b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1359a7812ae4Spbrook {
1360b3a62939SRichard Henderson     s->frame_start = start;
1361b3a62939SRichard Henderson     s->frame_end = start + size;
1362085272b3SRichard Henderson     s->frame_temp
1363085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1364b3a62939SRichard Henderson }
1365a7812ae4Spbrook 
1366085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
1367e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
1368c896fe29Sbellard {
1369b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1370dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
13717ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1372b3915dbbSRichard Henderson     int indirect_reg = 0, bigendian = 0;
13737ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
13747ca4b752SRichard Henderson     bigendian = 1;
13757ca4b752SRichard Henderson #endif
1376c896fe29Sbellard 
1377c0522136SRichard Henderson     switch (base_ts->kind) {
1378c0522136SRichard Henderson     case TEMP_FIXED:
1379c0522136SRichard Henderson         break;
1380c0522136SRichard Henderson     case TEMP_GLOBAL:
13815a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
13825a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1383b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
13845a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
13855a18407fSRichard Henderson                             ? 2 : 1);
13865a18407fSRichard Henderson         indirect_reg = 1;
1387c0522136SRichard Henderson         break;
1388c0522136SRichard Henderson     default:
1389c0522136SRichard Henderson         g_assert_not_reached();
1390b3915dbbSRichard Henderson     }
1391b3915dbbSRichard Henderson 
13927ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
13937ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1394c896fe29Sbellard         char buf[64];
13957ca4b752SRichard Henderson 
13967ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1397c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1398b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1399c896fe29Sbellard         ts->mem_allocated = 1;
1400b3a62939SRichard Henderson         ts->mem_base = base_ts;
14017ca4b752SRichard Henderson         ts->mem_offset = offset + bigendian * 4;
1402c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1403c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1404c896fe29Sbellard         ts->name = strdup(buf);
1405c896fe29Sbellard 
14067ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
14077ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
14087ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1409b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
14107ca4b752SRichard Henderson         ts2->mem_allocated = 1;
14117ca4b752SRichard Henderson         ts2->mem_base = base_ts;
14127ca4b752SRichard Henderson         ts2->mem_offset = offset + (1 - bigendian) * 4;
1413c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1414c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1415120c1084SRichard Henderson         ts2->name = strdup(buf);
14167ca4b752SRichard Henderson     } else {
1417c896fe29Sbellard         ts->base_type = type;
1418c896fe29Sbellard         ts->type = type;
1419b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1420c896fe29Sbellard         ts->mem_allocated = 1;
1421b3a62939SRichard Henderson         ts->mem_base = base_ts;
1422c896fe29Sbellard         ts->mem_offset = offset;
1423c896fe29Sbellard         ts->name = name;
1424c896fe29Sbellard     }
1425085272b3SRichard Henderson     return ts;
1426c896fe29Sbellard }
1427c896fe29Sbellard 
14285bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local)
1429c896fe29Sbellard {
1430b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1431ee17db83SRichard Henderson     TCGTempKind kind = temp_local ? TEMP_LOCAL : TEMP_NORMAL;
1432c896fe29Sbellard     TCGTemp *ts;
1433641d5fbeSbellard     int idx, k;
1434c896fe29Sbellard 
14350ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
14360ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
14370ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
14380ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
14390ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
14400ec9eabcSRichard Henderson 
1441e8996ee0Sbellard         ts = &s->temps[idx];
1442e8996ee0Sbellard         ts->temp_allocated = 1;
14437ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
1444ee17db83SRichard Henderson         tcg_debug_assert(ts->kind == kind);
1445e8996ee0Sbellard     } else {
14467ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
14477ca4b752SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
14487ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
14497ca4b752SRichard Henderson 
1450c896fe29Sbellard             ts->base_type = type;
1451c896fe29Sbellard             ts->type = TCG_TYPE_I32;
1452e8996ee0Sbellard             ts->temp_allocated = 1;
1453ee17db83SRichard Henderson             ts->kind = kind;
14547ca4b752SRichard Henderson 
14557ca4b752SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
14567ca4b752SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
14577ca4b752SRichard Henderson             ts2->type = TCG_TYPE_I32;
14587ca4b752SRichard Henderson             ts2->temp_allocated = 1;
1459ee17db83SRichard Henderson             ts2->kind = kind;
14607ca4b752SRichard Henderson         } else {
1461c896fe29Sbellard             ts->base_type = type;
1462c896fe29Sbellard             ts->type = type;
1463e8996ee0Sbellard             ts->temp_allocated = 1;
1464ee17db83SRichard Henderson             ts->kind = kind;
1465c896fe29Sbellard         }
1466e8996ee0Sbellard     }
146727bfd83cSPeter Maydell 
146827bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
146927bfd83cSPeter Maydell     s->temps_in_use++;
147027bfd83cSPeter Maydell #endif
1471085272b3SRichard Henderson     return ts;
1472c896fe29Sbellard }
1473c896fe29Sbellard 
1474d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1475d2fd745fSRichard Henderson {
1476d2fd745fSRichard Henderson     TCGTemp *t;
1477d2fd745fSRichard Henderson 
1478d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1479d2fd745fSRichard Henderson     switch (type) {
1480d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1481d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1482d2fd745fSRichard Henderson         break;
1483d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1484d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1485d2fd745fSRichard Henderson         break;
1486d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1487d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1488d2fd745fSRichard Henderson         break;
1489d2fd745fSRichard Henderson     default:
1490d2fd745fSRichard Henderson         g_assert_not_reached();
1491d2fd745fSRichard Henderson     }
1492d2fd745fSRichard Henderson #endif
1493d2fd745fSRichard Henderson 
1494d2fd745fSRichard Henderson     t = tcg_temp_new_internal(type, 0);
1495d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1496d2fd745fSRichard Henderson }
1497d2fd745fSRichard Henderson 
1498d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1499d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1500d2fd745fSRichard Henderson {
1501d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1502d2fd745fSRichard Henderson 
1503d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1504d2fd745fSRichard Henderson 
1505d2fd745fSRichard Henderson     t = tcg_temp_new_internal(t->base_type, 0);
1506d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1507d2fd745fSRichard Henderson }
1508d2fd745fSRichard Henderson 
15095bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1510c896fe29Sbellard {
1511b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1512085272b3SRichard Henderson     int k, idx;
1513c896fe29Sbellard 
1514c0522136SRichard Henderson     /* In order to simplify users of tcg_constant_*, silently ignore free. */
1515c0522136SRichard Henderson     if (ts->kind == TEMP_CONST) {
1516c0522136SRichard Henderson         return;
1517c0522136SRichard Henderson     }
1518c0522136SRichard Henderson 
151927bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
152027bfd83cSPeter Maydell     s->temps_in_use--;
152127bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
152227bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
152327bfd83cSPeter Maydell     }
152427bfd83cSPeter Maydell #endif
152527bfd83cSPeter Maydell 
1526ee17db83SRichard Henderson     tcg_debug_assert(ts->kind < TEMP_GLOBAL);
1527eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
1528e8996ee0Sbellard     ts->temp_allocated = 0;
15290ec9eabcSRichard Henderson 
1530085272b3SRichard Henderson     idx = temp_idx(ts);
1531ee17db83SRichard Henderson     k = ts->base_type + (ts->kind == TEMP_NORMAL ? 0 : TCG_TYPE_COUNT);
15320ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
1533e8996ee0Sbellard }
1534e8996ee0Sbellard 
1535c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val)
1536c0522136SRichard Henderson {
1537c0522136SRichard Henderson     TCGContext *s = tcg_ctx;
1538c0522136SRichard Henderson     GHashTable *h = s->const_table[type];
1539c0522136SRichard Henderson     TCGTemp *ts;
1540c0522136SRichard Henderson 
1541c0522136SRichard Henderson     if (h == NULL) {
1542c0522136SRichard Henderson         h = g_hash_table_new(g_int64_hash, g_int64_equal);
1543c0522136SRichard Henderson         s->const_table[type] = h;
1544c0522136SRichard Henderson     }
1545c0522136SRichard Henderson 
1546c0522136SRichard Henderson     ts = g_hash_table_lookup(h, &val);
1547c0522136SRichard Henderson     if (ts == NULL) {
1548c0522136SRichard Henderson         ts = tcg_temp_alloc(s);
1549c0522136SRichard Henderson 
1550c0522136SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
1551c0522136SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
1552c0522136SRichard Henderson 
1553c0522136SRichard Henderson             ts->base_type = TCG_TYPE_I64;
1554c0522136SRichard Henderson             ts->type = TCG_TYPE_I32;
1555c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1556c0522136SRichard Henderson             ts->temp_allocated = 1;
1557c0522136SRichard Henderson             /*
1558c0522136SRichard Henderson              * Retain the full value of the 64-bit constant in the low
1559c0522136SRichard Henderson              * part, so that the hash table works.  Actual uses will
1560c0522136SRichard Henderson              * truncate the value to the low part.
1561c0522136SRichard Henderson              */
1562c0522136SRichard Henderson             ts->val = val;
1563c0522136SRichard Henderson 
1564c0522136SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
1565c0522136SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
1566c0522136SRichard Henderson             ts2->type = TCG_TYPE_I32;
1567c0522136SRichard Henderson             ts2->kind = TEMP_CONST;
1568c0522136SRichard Henderson             ts2->temp_allocated = 1;
1569c0522136SRichard Henderson             ts2->val = val >> 32;
1570c0522136SRichard Henderson         } else {
1571c0522136SRichard Henderson             ts->base_type = type;
1572c0522136SRichard Henderson             ts->type = type;
1573c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1574c0522136SRichard Henderson             ts->temp_allocated = 1;
1575c0522136SRichard Henderson             ts->val = val;
1576c0522136SRichard Henderson         }
1577c0522136SRichard Henderson         g_hash_table_insert(h, &ts->val, ts);
1578c0522136SRichard Henderson     }
1579c0522136SRichard Henderson 
1580c0522136SRichard Henderson     return ts;
1581c0522136SRichard Henderson }
1582c0522136SRichard Henderson 
1583c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val)
1584c0522136SRichard Henderson {
1585c0522136SRichard Henderson     val = dup_const(vece, val);
1586c0522136SRichard Henderson     return temp_tcgv_vec(tcg_constant_internal(type, val));
1587c0522136SRichard Henderson }
1588c0522136SRichard Henderson 
158988d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val)
159088d4005bSRichard Henderson {
159188d4005bSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
159288d4005bSRichard Henderson 
159388d4005bSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
159488d4005bSRichard Henderson     return tcg_constant_vec(t->base_type, vece, val);
159588d4005bSRichard Henderson }
159688d4005bSRichard Henderson 
1597a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
1598a7812ae4Spbrook {
1599a7812ae4Spbrook     TCGv_i32 t0;
1600a7812ae4Spbrook     t0 = tcg_temp_new_i32();
1601e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
1602e8996ee0Sbellard     return t0;
1603c896fe29Sbellard }
1604c896fe29Sbellard 
1605a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
1606c896fe29Sbellard {
1607a7812ae4Spbrook     TCGv_i64 t0;
1608a7812ae4Spbrook     t0 = tcg_temp_new_i64();
1609e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
1610e8996ee0Sbellard     return t0;
1611c896fe29Sbellard }
1612c896fe29Sbellard 
1613a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
1614bdffd4a9Saurel32 {
1615a7812ae4Spbrook     TCGv_i32 t0;
1616a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
1617bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
1618bdffd4a9Saurel32     return t0;
1619bdffd4a9Saurel32 }
1620bdffd4a9Saurel32 
1621a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
1622bdffd4a9Saurel32 {
1623a7812ae4Spbrook     TCGv_i64 t0;
1624a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
1625bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
1626bdffd4a9Saurel32     return t0;
1627bdffd4a9Saurel32 }
1628bdffd4a9Saurel32 
162927bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
163027bfd83cSPeter Maydell void tcg_clear_temp_count(void)
163127bfd83cSPeter Maydell {
1632b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
163327bfd83cSPeter Maydell     s->temps_in_use = 0;
163427bfd83cSPeter Maydell }
163527bfd83cSPeter Maydell 
163627bfd83cSPeter Maydell int tcg_check_temp_count(void)
163727bfd83cSPeter Maydell {
1638b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
163927bfd83cSPeter Maydell     if (s->temps_in_use) {
164027bfd83cSPeter Maydell         /* Clear the count so that we don't give another
164127bfd83cSPeter Maydell          * warning immediately next time around.
164227bfd83cSPeter Maydell          */
164327bfd83cSPeter Maydell         s->temps_in_use = 0;
164427bfd83cSPeter Maydell         return 1;
164527bfd83cSPeter Maydell     }
164627bfd83cSPeter Maydell     return 0;
164727bfd83cSPeter Maydell }
164827bfd83cSPeter Maydell #endif
164927bfd83cSPeter Maydell 
1650be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1651be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1652be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1653be0f34b5SRichard Henderson {
1654d2fd745fSRichard Henderson     const bool have_vec
1655d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1656d2fd745fSRichard Henderson 
1657be0f34b5SRichard Henderson     switch (op) {
1658be0f34b5SRichard Henderson     case INDEX_op_discard:
1659be0f34b5SRichard Henderson     case INDEX_op_set_label:
1660be0f34b5SRichard Henderson     case INDEX_op_call:
1661be0f34b5SRichard Henderson     case INDEX_op_br:
1662be0f34b5SRichard Henderson     case INDEX_op_mb:
1663be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1664be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1665be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1666be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i32:
1667be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i32:
1668be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i64:
1669be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i64:
1670be0f34b5SRichard Henderson         return true;
1671be0f34b5SRichard Henderson 
167207ce0b05SRichard Henderson     case INDEX_op_qemu_st8_i32:
167307ce0b05SRichard Henderson         return TCG_TARGET_HAS_qemu_st8_i32;
167407ce0b05SRichard Henderson 
1675be0f34b5SRichard Henderson     case INDEX_op_goto_ptr:
1676be0f34b5SRichard Henderson         return TCG_TARGET_HAS_goto_ptr;
1677be0f34b5SRichard Henderson 
1678be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1679be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1680be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1681be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1682be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1683be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1684be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1685be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1686be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1687be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1688be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1689be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1690be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1691be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1692be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1693be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1694be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1695be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1696be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1697be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1698be0f34b5SRichard Henderson         return true;
1699be0f34b5SRichard Henderson 
1700be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1701be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1702be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1703be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1704be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1705be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1706be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1707be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1708be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1709be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1710be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1711be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1712be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1713be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1714be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1715be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1716be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1717be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1718be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1719be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1720fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
1721fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
1722be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1723be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1724be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1725be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1726be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1727be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1728be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1729be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1730be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1731be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1732be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1733be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1734be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1735be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1736be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1737be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1738be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1739be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1740be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1741be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1742be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1743be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1744be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1745be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1746be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1747be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1748be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1749be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1750be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1751be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1752be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1753be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1754be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1755be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1756be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1757be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1758be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1759be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1760be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1761be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1762be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1763be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1764be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1765be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1766be0f34b5SRichard Henderson 
1767be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1768be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1769be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1770be0f34b5SRichard Henderson 
1771be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1772be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1773be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1774be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1775be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1776be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1777be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1778be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1779be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1780be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1781be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1782be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1783be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1784be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1785be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1786be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1787be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1788be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1789be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1790be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1791be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1792be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1793be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1794be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1795be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1796be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1797be0f34b5SRichard Henderson 
1798be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1799be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1800be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1801be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1802be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1803be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1804be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1805be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1806be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1807be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
1808be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
1809be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
1810be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
1811be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
1812be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
1813be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
1814be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
1815be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
1816be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
1817be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
1818fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
1819fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
1820be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
1821be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrl_i64_i32;
1822be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
1823be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrh_i64_i32;
1824be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
1825be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
1826be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
1827be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
1828be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
1829be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
1830be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
1831be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
1832be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
1833be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
1834be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
1835be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
1836be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
1837be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
1838be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
1839be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
1840be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
1841be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
1842be0f34b5SRichard Henderson     case INDEX_op_not_i64:
1843be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
1844be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
1845be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
1846be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
1847be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
1848be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
1849be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
1850be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
1851be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
1852be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
1853be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
1854be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
1855be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
1856be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
1857be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
1858be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
1859be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
1860be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
1861be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
1862be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
1863be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
1864be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
1865be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
1866be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
1867be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
1868be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
1869be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
1870be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
1871be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
1872be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
1873be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
1874be0f34b5SRichard Henderson 
1875d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
1876d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
187737ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
1878d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
1879d2fd745fSRichard Henderson     case INDEX_op_st_vec:
1880d2fd745fSRichard Henderson     case INDEX_op_add_vec:
1881d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
1882d2fd745fSRichard Henderson     case INDEX_op_and_vec:
1883d2fd745fSRichard Henderson     case INDEX_op_or_vec:
1884d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
1885212be173SRichard Henderson     case INDEX_op_cmp_vec:
1886d2fd745fSRichard Henderson         return have_vec;
1887d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
1888d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
1889d2fd745fSRichard Henderson     case INDEX_op_not_vec:
1890d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
1891d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
1892d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
1893bcefc902SRichard Henderson     case INDEX_op_abs_vec:
1894bcefc902SRichard Henderson         return have_vec && TCG_TARGET_HAS_abs_vec;
1895d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
1896d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
1897d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
1898d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
18993774030aSRichard Henderson     case INDEX_op_mul_vec:
19003774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
1901d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
1902d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
1903d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
1904d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
1905d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
1906d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
1907d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
1908d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
1909d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
1910d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
1911d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
1912d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
1913b0f7e744SRichard Henderson     case INDEX_op_rotli_vec:
1914b0f7e744SRichard Henderson         return have_vec && TCG_TARGET_HAS_roti_vec;
191523850a74SRichard Henderson     case INDEX_op_rotls_vec:
191623850a74SRichard Henderson         return have_vec && TCG_TARGET_HAS_rots_vec;
19175d0ceda9SRichard Henderson     case INDEX_op_rotlv_vec:
19185d0ceda9SRichard Henderson     case INDEX_op_rotrv_vec:
19195d0ceda9SRichard Henderson         return have_vec && TCG_TARGET_HAS_rotv_vec;
19208afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
19218afaf050SRichard Henderson     case INDEX_op_usadd_vec:
19228afaf050SRichard Henderson     case INDEX_op_sssub_vec:
19238afaf050SRichard Henderson     case INDEX_op_ussub_vec:
19248afaf050SRichard Henderson         return have_vec && TCG_TARGET_HAS_sat_vec;
1925dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
1926dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
1927dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
1928dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
1929dd0a0fcdSRichard Henderson         return have_vec && TCG_TARGET_HAS_minmax_vec;
193038dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
193138dc1294SRichard Henderson         return have_vec && TCG_TARGET_HAS_bitsel_vec;
1932f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
1933f75da298SRichard Henderson         return have_vec && TCG_TARGET_HAS_cmpsel_vec;
1934d2fd745fSRichard Henderson 
1935db432672SRichard Henderson     default:
1936db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
1937db432672SRichard Henderson         return true;
1938be0f34b5SRichard Henderson     }
1939be0f34b5SRichard Henderson }
1940be0f34b5SRichard Henderson 
194139cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment
194239cf05d3Sbellard    and endian swap. Maybe it would be better to do the alignment
194339cf05d3Sbellard    and endian swap in tcg_reg_alloc_call(). */
1944ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
1945c896fe29Sbellard {
194675e8b9b7SRichard Henderson     int i, real_args, nb_rets, pi;
1947bbb8a1b4SRichard Henderson     unsigned sizemask, flags;
1948afb49896SRichard Henderson     TCGHelperInfo *info;
194975e8b9b7SRichard Henderson     TCGOp *op;
1950afb49896SRichard Henderson 
1951619205fdSEmilio G. Cota     info = g_hash_table_lookup(helper_table, (gpointer)func);
1952bbb8a1b4SRichard Henderson     flags = info->flags;
1953bbb8a1b4SRichard Henderson     sizemask = info->sizemask;
19542bece2c8SRichard Henderson 
195538b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
195638b47b19SEmilio G. Cota     /* detect non-plugin helpers */
195738b47b19SEmilio G. Cota     if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) {
195838b47b19SEmilio G. Cota         tcg_ctx->plugin_insn->calls_helpers = true;
195938b47b19SEmilio G. Cota     }
196038b47b19SEmilio G. Cota #endif
196138b47b19SEmilio G. Cota 
196234b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
196334b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
196434b1a49cSRichard Henderson     /* We have 64-bit values in one register, but need to pass as two
196534b1a49cSRichard Henderson        separate parameters.  Split them.  */
196634b1a49cSRichard Henderson     int orig_sizemask = sizemask;
196734b1a49cSRichard Henderson     int orig_nargs = nargs;
196834b1a49cSRichard Henderson     TCGv_i64 retl, reth;
1969ae8b75dcSRichard Henderson     TCGTemp *split_args[MAX_OPC_PARAM];
197034b1a49cSRichard Henderson 
1971f764718dSRichard Henderson     retl = NULL;
1972f764718dSRichard Henderson     reth = NULL;
197334b1a49cSRichard Henderson     if (sizemask != 0) {
197434b1a49cSRichard Henderson         for (i = real_args = 0; i < nargs; ++i) {
197534b1a49cSRichard Henderson             int is_64bit = sizemask & (1 << (i+1)*2);
197634b1a49cSRichard Henderson             if (is_64bit) {
1977085272b3SRichard Henderson                 TCGv_i64 orig = temp_tcgv_i64(args[i]);
197834b1a49cSRichard Henderson                 TCGv_i32 h = tcg_temp_new_i32();
197934b1a49cSRichard Henderson                 TCGv_i32 l = tcg_temp_new_i32();
198034b1a49cSRichard Henderson                 tcg_gen_extr_i64_i32(l, h, orig);
1981ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(h);
1982ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(l);
198334b1a49cSRichard Henderson             } else {
198434b1a49cSRichard Henderson                 split_args[real_args++] = args[i];
198534b1a49cSRichard Henderson             }
198634b1a49cSRichard Henderson         }
198734b1a49cSRichard Henderson         nargs = real_args;
198834b1a49cSRichard Henderson         args = split_args;
198934b1a49cSRichard Henderson         sizemask = 0;
199034b1a49cSRichard Henderson     }
199134b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
19922bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
19932bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
19942bece2c8SRichard Henderson         int is_signed = sizemask & (2 << (i+1)*2);
19952bece2c8SRichard Henderson         if (!is_64bit) {
19962bece2c8SRichard Henderson             TCGv_i64 temp = tcg_temp_new_i64();
1997085272b3SRichard Henderson             TCGv_i64 orig = temp_tcgv_i64(args[i]);
19982bece2c8SRichard Henderson             if (is_signed) {
19992bece2c8SRichard Henderson                 tcg_gen_ext32s_i64(temp, orig);
20002bece2c8SRichard Henderson             } else {
20012bece2c8SRichard Henderson                 tcg_gen_ext32u_i64(temp, orig);
20022bece2c8SRichard Henderson             }
2003ae8b75dcSRichard Henderson             args[i] = tcgv_i64_temp(temp);
20042bece2c8SRichard Henderson         }
20052bece2c8SRichard Henderson     }
20062bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
20072bece2c8SRichard Henderson 
200815fa08f8SRichard Henderson     op = tcg_emit_op(INDEX_op_call);
200975e8b9b7SRichard Henderson 
201075e8b9b7SRichard Henderson     pi = 0;
2011ae8b75dcSRichard Henderson     if (ret != NULL) {
201234b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
201334b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
201434b1a49cSRichard Henderson         if (orig_sizemask & 1) {
201534b1a49cSRichard Henderson             /* The 32-bit ABI is going to return the 64-bit value in
201634b1a49cSRichard Henderson                the %o0/%o1 register pair.  Prepare for this by using
201734b1a49cSRichard Henderson                two return temporaries, and reassemble below.  */
201834b1a49cSRichard Henderson             retl = tcg_temp_new_i64();
201934b1a49cSRichard Henderson             reth = tcg_temp_new_i64();
2020ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(reth);
2021ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(retl);
202234b1a49cSRichard Henderson             nb_rets = 2;
202334b1a49cSRichard Henderson         } else {
2024ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
202534b1a49cSRichard Henderson             nb_rets = 1;
202634b1a49cSRichard Henderson         }
202734b1a49cSRichard Henderson #else
202834b1a49cSRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) {
202902eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
2030ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
2031ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
2032a7812ae4Spbrook #else
2033ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
2034ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
2035a7812ae4Spbrook #endif
2036a7812ae4Spbrook             nb_rets = 2;
203734b1a49cSRichard Henderson         } else {
2038ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
2039a7812ae4Spbrook             nb_rets = 1;
2040a7812ae4Spbrook         }
204134b1a49cSRichard Henderson #endif
2042a7812ae4Spbrook     } else {
2043a7812ae4Spbrook         nb_rets = 0;
2044a7812ae4Spbrook     }
2045cd9090aaSRichard Henderson     TCGOP_CALLO(op) = nb_rets;
204675e8b9b7SRichard Henderson 
2047a7812ae4Spbrook     real_args = 0;
2048a7812ae4Spbrook     for (i = 0; i < nargs; i++) {
20492bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
2050bbb8a1b4SRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
205139cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS
205239cf05d3Sbellard             /* some targets want aligned 64 bit args */
2053ebd486d5Smalc             if (real_args & 1) {
205475e8b9b7SRichard Henderson                 op->args[pi++] = TCG_CALL_DUMMY_ARG;
2055ebd486d5Smalc                 real_args++;
205639cf05d3Sbellard             }
205739cf05d3Sbellard #endif
20583f90f252SRichard Henderson            /* If stack grows up, then we will be placing successive
20593f90f252SRichard Henderson               arguments at lower addresses, which means we need to
20603f90f252SRichard Henderson               reverse the order compared to how we would normally
20613f90f252SRichard Henderson               treat either big or little-endian.  For those arguments
20623f90f252SRichard Henderson               that will wind up in registers, this still works for
20633f90f252SRichard Henderson               HPPA (the only current STACK_GROWSUP target) since the
20643f90f252SRichard Henderson               argument registers are *also* allocated in decreasing
20653f90f252SRichard Henderson               order.  If another such target is added, this logic may
20663f90f252SRichard Henderson               have to get more complicated to differentiate between
20673f90f252SRichard Henderson               stack arguments and register arguments.  */
206802eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
2069ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
2070ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
2071c896fe29Sbellard #else
2072ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
2073ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
2074c896fe29Sbellard #endif
2075a7812ae4Spbrook             real_args += 2;
20762bece2c8SRichard Henderson             continue;
20772bece2c8SRichard Henderson         }
20782bece2c8SRichard Henderson 
2079ae8b75dcSRichard Henderson         op->args[pi++] = temp_arg(args[i]);
2080a7812ae4Spbrook         real_args++;
2081c896fe29Sbellard     }
208275e8b9b7SRichard Henderson     op->args[pi++] = (uintptr_t)func;
208375e8b9b7SRichard Henderson     op->args[pi++] = flags;
2084cd9090aaSRichard Henderson     TCGOP_CALLI(op) = real_args;
2085a7812ae4Spbrook 
208675e8b9b7SRichard Henderson     /* Make sure the fields didn't overflow.  */
2087cd9090aaSRichard Henderson     tcg_debug_assert(TCGOP_CALLI(op) == real_args);
208875e8b9b7SRichard Henderson     tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
20892bece2c8SRichard Henderson 
209034b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
209134b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
209234b1a49cSRichard Henderson     /* Free all of the parts we allocated above.  */
209334b1a49cSRichard Henderson     for (i = real_args = 0; i < orig_nargs; ++i) {
209434b1a49cSRichard Henderson         int is_64bit = orig_sizemask & (1 << (i+1)*2);
209534b1a49cSRichard Henderson         if (is_64bit) {
2096085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
2097085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
209834b1a49cSRichard Henderson         } else {
209934b1a49cSRichard Henderson             real_args++;
210034b1a49cSRichard Henderson         }
210134b1a49cSRichard Henderson     }
210234b1a49cSRichard Henderson     if (orig_sizemask & 1) {
210334b1a49cSRichard Henderson         /* The 32-bit ABI returned two 32-bit pieces.  Re-assemble them.
210434b1a49cSRichard Henderson            Note that describing these as TCGv_i64 eliminates an unnecessary
210534b1a49cSRichard Henderson            zero-extension that tcg_gen_concat_i32_i64 would create.  */
2106085272b3SRichard Henderson         tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth);
210734b1a49cSRichard Henderson         tcg_temp_free_i64(retl);
210834b1a49cSRichard Henderson         tcg_temp_free_i64(reth);
210934b1a49cSRichard Henderson     }
211034b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
21112bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
21122bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
21132bece2c8SRichard Henderson         if (!is_64bit) {
2114085272b3SRichard Henderson             tcg_temp_free_internal(args[i]);
21152bece2c8SRichard Henderson         }
21162bece2c8SRichard Henderson     }
21172bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
2118a7812ae4Spbrook }
2119c896fe29Sbellard 
21208fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
2121c896fe29Sbellard {
2122ac3b8891SRichard Henderson     int i, n;
2123ac3b8891SRichard Henderson 
2124ee17db83SRichard Henderson     for (i = 0, n = s->nb_temps; i < n; i++) {
2125ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2126ee17db83SRichard Henderson         TCGTempVal val = TEMP_VAL_MEM;
2127ee17db83SRichard Henderson 
2128ee17db83SRichard Henderson         switch (ts->kind) {
2129c0522136SRichard Henderson         case TEMP_CONST:
2130c0522136SRichard Henderson             val = TEMP_VAL_CONST;
2131c0522136SRichard Henderson             break;
2132ee17db83SRichard Henderson         case TEMP_FIXED:
2133ee17db83SRichard Henderson             val = TEMP_VAL_REG;
2134ee17db83SRichard Henderson             break;
2135ee17db83SRichard Henderson         case TEMP_GLOBAL:
2136ee17db83SRichard Henderson             break;
2137ee17db83SRichard Henderson         case TEMP_NORMAL:
2138ee17db83SRichard Henderson             val = TEMP_VAL_DEAD;
2139ee17db83SRichard Henderson             /* fall through */
2140ee17db83SRichard Henderson         case TEMP_LOCAL:
2141e8996ee0Sbellard             ts->mem_allocated = 0;
2142ee17db83SRichard Henderson             break;
2143ee17db83SRichard Henderson         default:
2144ee17db83SRichard Henderson             g_assert_not_reached();
2145ee17db83SRichard Henderson         }
2146ee17db83SRichard Henderson         ts->val_type = val;
2147e8996ee0Sbellard     }
2148f8b2f202SRichard Henderson 
2149f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
2150c896fe29Sbellard }
2151c896fe29Sbellard 
2152f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
2153f8b2f202SRichard Henderson                                  TCGTemp *ts)
2154c896fe29Sbellard {
21551807f4c4SRichard Henderson     int idx = temp_idx(ts);
2156ac56dd48Spbrook 
2157ee17db83SRichard Henderson     switch (ts->kind) {
2158ee17db83SRichard Henderson     case TEMP_FIXED:
2159ee17db83SRichard Henderson     case TEMP_GLOBAL:
2160ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
2161ee17db83SRichard Henderson         break;
2162ee17db83SRichard Henderson     case TEMP_LOCAL:
2163641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
2164ee17db83SRichard Henderson         break;
2165ee17db83SRichard Henderson     case TEMP_NORMAL:
2166ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
2167ee17db83SRichard Henderson         break;
2168c0522136SRichard Henderson     case TEMP_CONST:
2169c0522136SRichard Henderson         switch (ts->type) {
2170c0522136SRichard Henderson         case TCG_TYPE_I32:
2171c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val);
2172c0522136SRichard Henderson             break;
2173c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32
2174c0522136SRichard Henderson         case TCG_TYPE_I64:
2175c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%" PRIx64, ts->val);
2176c0522136SRichard Henderson             break;
2177c0522136SRichard Henderson #endif
2178c0522136SRichard Henderson         case TCG_TYPE_V64:
2179c0522136SRichard Henderson         case TCG_TYPE_V128:
2180c0522136SRichard Henderson         case TCG_TYPE_V256:
2181c0522136SRichard Henderson             snprintf(buf, buf_size, "v%d$0x%" PRIx64,
2182c0522136SRichard Henderson                      64 << (ts->type - TCG_TYPE_V64), ts->val);
2183c0522136SRichard Henderson             break;
2184c0522136SRichard Henderson         default:
2185c0522136SRichard Henderson             g_assert_not_reached();
2186c0522136SRichard Henderson         }
2187c0522136SRichard Henderson         break;
2188c896fe29Sbellard     }
2189c896fe29Sbellard     return buf;
2190c896fe29Sbellard }
2191c896fe29Sbellard 
219243439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
219343439139SRichard Henderson                              int buf_size, TCGArg arg)
2194f8b2f202SRichard Henderson {
219543439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
2196f8b2f202SRichard Henderson }
2197f8b2f202SRichard Henderson 
21986e085f72SRichard Henderson /* Find helper name.  */
21996e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val)
2200e8996ee0Sbellard {
22016e085f72SRichard Henderson     const char *ret = NULL;
2202619205fdSEmilio G. Cota     if (helper_table) {
2203619205fdSEmilio G. Cota         TCGHelperInfo *info = g_hash_table_lookup(helper_table, (gpointer)val);
220472866e82SRichard Henderson         if (info) {
220572866e82SRichard Henderson             ret = info->name;
220672866e82SRichard Henderson         }
2207e8996ee0Sbellard     }
22086e085f72SRichard Henderson     return ret;
22094dc81f28Sbellard }
22104dc81f28Sbellard 
2211f48f3edeSblueswir1 static const char * const cond_name[] =
2212f48f3edeSblueswir1 {
22130aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
22140aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
2215f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
2216f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
2217f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
2218f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
2219f48f3edeSblueswir1     [TCG_COND_LE] = "le",
2220f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
2221f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
2222f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
2223f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
2224f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
2225f48f3edeSblueswir1 };
2226f48f3edeSblueswir1 
2227f713d6adSRichard Henderson static const char * const ldst_name[] =
2228f713d6adSRichard Henderson {
2229f713d6adSRichard Henderson     [MO_UB]   = "ub",
2230f713d6adSRichard Henderson     [MO_SB]   = "sb",
2231f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
2232f713d6adSRichard Henderson     [MO_LESW] = "lesw",
2233f713d6adSRichard Henderson     [MO_LEUL] = "leul",
2234f713d6adSRichard Henderson     [MO_LESL] = "lesl",
2235f713d6adSRichard Henderson     [MO_LEQ]  = "leq",
2236f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
2237f713d6adSRichard Henderson     [MO_BESW] = "besw",
2238f713d6adSRichard Henderson     [MO_BEUL] = "beul",
2239f713d6adSRichard Henderson     [MO_BESL] = "besl",
2240f713d6adSRichard Henderson     [MO_BEQ]  = "beq",
2241f713d6adSRichard Henderson };
2242f713d6adSRichard Henderson 
22431f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
224452bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY
22451f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
22461f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
22471f00b27fSSergey Sorokin #else
22481f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
22491f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
22501f00b27fSSergey Sorokin #endif
22511f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
22521f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
22531f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
22541f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
22551f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
22561f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
22571f00b27fSSergey Sorokin };
22581f00b27fSSergey Sorokin 
2259b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
2260b016486eSRichard Henderson {
2261b016486eSRichard Henderson     return (d & (d - 1)) == 0;
2262b016486eSRichard Henderson }
2263b016486eSRichard Henderson 
2264b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
2265b016486eSRichard Henderson {
2266b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
2267b016486eSRichard Henderson         return ctz32(d);
2268b016486eSRichard Henderson     } else {
2269b016486eSRichard Henderson         return ctz64(d);
2270b016486eSRichard Henderson     }
2271b016486eSRichard Henderson }
2272b016486eSRichard Henderson 
22731894f69aSRichard Henderson static void tcg_dump_ops(TCGContext *s, bool have_prefs)
2274c896fe29Sbellard {
2275c896fe29Sbellard     char buf[128];
2276c45cb8bbSRichard Henderson     TCGOp *op;
2277c896fe29Sbellard 
227815fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
2279c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
2280c45cb8bbSRichard Henderson         const TCGOpDef *def;
2281c45cb8bbSRichard Henderson         TCGOpcode c;
2282bdfb460eSRichard Henderson         int col = 0;
2283c45cb8bbSRichard Henderson 
2284c45cb8bbSRichard Henderson         c = op->opc;
2285c896fe29Sbellard         def = &tcg_op_defs[c];
2286c45cb8bbSRichard Henderson 
2287765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
2288b016486eSRichard Henderson             nb_oargs = 0;
228915fa08f8SRichard Henderson             col += qemu_log("\n ----");
22909aef40edSRichard Henderson 
22919aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
22929aef40edSRichard Henderson                 target_ulong a;
22937e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
2294efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
22957e4597d7Sbellard #else
2296efee3746SRichard Henderson                 a = op->args[i];
22977e4597d7Sbellard #endif
2298bdfb460eSRichard Henderson                 col += qemu_log(" " TARGET_FMT_lx, a);
2299eeacee4dSBlue Swirl             }
23007e4597d7Sbellard         } else if (c == INDEX_op_call) {
2301c896fe29Sbellard             /* variable number of arguments */
2302cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2303cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2304c896fe29Sbellard             nb_cargs = def->nb_cargs;
2305b03cce8eSbellard 
2306cf066674SRichard Henderson             /* function name, flags, out args */
2307bdfb460eSRichard Henderson             col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name,
2308efee3746SRichard Henderson                             tcg_find_helper(s, op->args[nb_oargs + nb_iargs]),
2309efee3746SRichard Henderson                             op->args[nb_oargs + nb_iargs + 1], nb_oargs);
2310b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
231143439139SRichard Henderson                 col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf),
2312efee3746SRichard Henderson                                                        op->args[i]));
2313b03cce8eSbellard             }
2314cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
2315efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
2316cf066674SRichard Henderson                 const char *t = "<dummy>";
2317cf066674SRichard Henderson                 if (arg != TCG_CALL_DUMMY_ARG) {
231843439139SRichard Henderson                     t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
2319b03cce8eSbellard                 }
2320bdfb460eSRichard Henderson                 col += qemu_log(",%s", t);
2321e8996ee0Sbellard             }
2322b03cce8eSbellard         } else {
2323bdfb460eSRichard Henderson             col += qemu_log(" %s ", def->name);
2324c45cb8bbSRichard Henderson 
2325c896fe29Sbellard             nb_oargs = def->nb_oargs;
2326c896fe29Sbellard             nb_iargs = def->nb_iargs;
2327c896fe29Sbellard             nb_cargs = def->nb_cargs;
2328c896fe29Sbellard 
2329d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
2330d2fd745fSRichard Henderson                 col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op),
2331d2fd745fSRichard Henderson                                 8 << TCGOP_VECE(op));
2332d2fd745fSRichard Henderson             }
2333d2fd745fSRichard Henderson 
2334c896fe29Sbellard             k = 0;
2335c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
2336eeacee4dSBlue Swirl                 if (k != 0) {
2337bdfb460eSRichard Henderson                     col += qemu_log(",");
2338eeacee4dSBlue Swirl                 }
233943439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2340efee3746SRichard Henderson                                                       op->args[k++]));
2341c896fe29Sbellard             }
2342c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
2343eeacee4dSBlue Swirl                 if (k != 0) {
2344bdfb460eSRichard Henderson                     col += qemu_log(",");
2345eeacee4dSBlue Swirl                 }
234643439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2347efee3746SRichard Henderson                                                       op->args[k++]));
2348c896fe29Sbellard             }
2349be210acbSRichard Henderson             switch (c) {
2350be210acbSRichard Henderson             case INDEX_op_brcond_i32:
2351ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
2352ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
2353be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
2354be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
2355ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
2356be210acbSRichard Henderson             case INDEX_op_setcond_i64:
2357ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
2358212be173SRichard Henderson             case INDEX_op_cmp_vec:
2359f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
2360efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
2361efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
2362efee3746SRichard Henderson                     col += qemu_log(",%s", cond_name[op->args[k++]]);
2363eeacee4dSBlue Swirl                 } else {
2364efee3746SRichard Henderson                     col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]);
2365eeacee4dSBlue Swirl                 }
2366f48f3edeSblueswir1                 i = 1;
2367be210acbSRichard Henderson                 break;
2368f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
2369f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
237007ce0b05SRichard Henderson             case INDEX_op_qemu_st8_i32:
2371f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
2372f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
237359227d5dSRichard Henderson                 {
2374efee3746SRichard Henderson                     TCGMemOpIdx oi = op->args[k++];
237514776ab5STony Nguyen                     MemOp op = get_memop(oi);
237659227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
237759227d5dSRichard Henderson 
237859c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
2379bdfb460eSRichard Henderson                         col += qemu_log(",$0x%x,%u", op, ix);
238059c4b7e8SRichard Henderson                     } else {
23811f00b27fSSergey Sorokin                         const char *s_al, *s_op;
23821f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
238359c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
2384bdfb460eSRichard Henderson                         col += qemu_log(",%s%s,%u", s_al, s_op, ix);
2385f713d6adSRichard Henderson                     }
2386f713d6adSRichard Henderson                     i = 1;
238759227d5dSRichard Henderson                 }
2388f713d6adSRichard Henderson                 break;
2389be210acbSRichard Henderson             default:
2390f48f3edeSblueswir1                 i = 0;
2391be210acbSRichard Henderson                 break;
2392be210acbSRichard Henderson             }
239351e3972cSRichard Henderson             switch (c) {
239451e3972cSRichard Henderson             case INDEX_op_set_label:
239551e3972cSRichard Henderson             case INDEX_op_br:
239651e3972cSRichard Henderson             case INDEX_op_brcond_i32:
239751e3972cSRichard Henderson             case INDEX_op_brcond_i64:
239851e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2399efee3746SRichard Henderson                 col += qemu_log("%s$L%d", k ? "," : "",
2400efee3746SRichard Henderson                                 arg_label(op->args[k])->id);
240151e3972cSRichard Henderson                 i++, k++;
240251e3972cSRichard Henderson                 break;
240351e3972cSRichard Henderson             default:
240451e3972cSRichard Henderson                 break;
2405eeacee4dSBlue Swirl             }
240651e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
2407efee3746SRichard Henderson                 col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]);
2408bdfb460eSRichard Henderson             }
2409bdfb460eSRichard Henderson         }
2410bdfb460eSRichard Henderson 
24111894f69aSRichard Henderson         if (have_prefs || op->life) {
24127606488cSRobert Foley 
24137606488cSRobert Foley             QemuLogFile *logfile;
24147606488cSRobert Foley 
24157606488cSRobert Foley             rcu_read_lock();
2416d73415a3SStefan Hajnoczi             logfile = qatomic_rcu_read(&qemu_logfile);
24177606488cSRobert Foley             if (logfile) {
24181894f69aSRichard Henderson                 for (; col < 40; ++col) {
24197606488cSRobert Foley                     putc(' ', logfile->fd);
2420bdfb460eSRichard Henderson                 }
24211894f69aSRichard Henderson             }
24227606488cSRobert Foley             rcu_read_unlock();
24237606488cSRobert Foley         }
24241894f69aSRichard Henderson 
24251894f69aSRichard Henderson         if (op->life) {
24261894f69aSRichard Henderson             unsigned life = op->life;
2427bdfb460eSRichard Henderson 
2428bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
2429bdfb460eSRichard Henderson                 qemu_log("  sync:");
2430bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
2431bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
2432bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2433bdfb460eSRichard Henderson                     }
2434bdfb460eSRichard Henderson                 }
2435bdfb460eSRichard Henderson             }
2436bdfb460eSRichard Henderson             life /= DEAD_ARG;
2437bdfb460eSRichard Henderson             if (life) {
2438bdfb460eSRichard Henderson                 qemu_log("  dead:");
2439bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
2440bdfb460eSRichard Henderson                     if (life & 1) {
2441bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2442bdfb460eSRichard Henderson                     }
2443bdfb460eSRichard Henderson                 }
2444c896fe29Sbellard             }
2445b03cce8eSbellard         }
24461894f69aSRichard Henderson 
24471894f69aSRichard Henderson         if (have_prefs) {
24481894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
24491894f69aSRichard Henderson                 TCGRegSet set = op->output_pref[i];
24501894f69aSRichard Henderson 
24511894f69aSRichard Henderson                 if (i == 0) {
24521894f69aSRichard Henderson                     qemu_log("  pref=");
24531894f69aSRichard Henderson                 } else {
24541894f69aSRichard Henderson                     qemu_log(",");
24551894f69aSRichard Henderson                 }
24561894f69aSRichard Henderson                 if (set == 0) {
24571894f69aSRichard Henderson                     qemu_log("none");
24581894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
24591894f69aSRichard Henderson                     qemu_log("all");
24601894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
24611894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
24621894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
24631894f69aSRichard Henderson                     qemu_log("%s", tcg_target_reg_names[reg]);
24641894f69aSRichard Henderson #endif
24651894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
24661894f69aSRichard Henderson                     qemu_log("%#x", (uint32_t)set);
24671894f69aSRichard Henderson                 } else {
24681894f69aSRichard Henderson                     qemu_log("%#" PRIx64, (uint64_t)set);
24691894f69aSRichard Henderson                 }
24701894f69aSRichard Henderson             }
24711894f69aSRichard Henderson         }
24721894f69aSRichard Henderson 
2473eeacee4dSBlue Swirl         qemu_log("\n");
2474c896fe29Sbellard     }
2475c896fe29Sbellard }
2476c896fe29Sbellard 
2477c896fe29Sbellard /* we give more priority to constraints with less registers */
2478c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2479c896fe29Sbellard {
248074a11790SRichard Henderson     const TCGArgConstraint *arg_ct = &def->args_ct[k];
248174a11790SRichard Henderson     int n;
2482c896fe29Sbellard 
2483bc2b17e6SRichard Henderson     if (arg_ct->oalias) {
2484c896fe29Sbellard         /* an alias is equivalent to a single register */
2485c896fe29Sbellard         n = 1;
2486c896fe29Sbellard     } else {
248774a11790SRichard Henderson         n = ctpop64(arg_ct->regs);
2488c896fe29Sbellard     }
2489c896fe29Sbellard     return TCG_TARGET_NB_REGS - n + 1;
2490c896fe29Sbellard }
2491c896fe29Sbellard 
2492c896fe29Sbellard /* sort from highest priority to lowest */
2493c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2494c896fe29Sbellard {
249566792f90SRichard Henderson     int i, j;
249666792f90SRichard Henderson     TCGArgConstraint *a = def->args_ct;
2497c896fe29Sbellard 
249866792f90SRichard Henderson     for (i = 0; i < n; i++) {
249966792f90SRichard Henderson         a[start + i].sort_index = start + i;
250066792f90SRichard Henderson     }
250166792f90SRichard Henderson     if (n <= 1) {
2502c896fe29Sbellard         return;
250366792f90SRichard Henderson     }
2504c896fe29Sbellard     for (i = 0; i < n - 1; i++) {
2505c896fe29Sbellard         for (j = i + 1; j < n; j++) {
250666792f90SRichard Henderson             int p1 = get_constraint_priority(def, a[start + i].sort_index);
250766792f90SRichard Henderson             int p2 = get_constraint_priority(def, a[start + j].sort_index);
2508c896fe29Sbellard             if (p1 < p2) {
250966792f90SRichard Henderson                 int tmp = a[start + i].sort_index;
251066792f90SRichard Henderson                 a[start + i].sort_index = a[start + j].sort_index;
251166792f90SRichard Henderson                 a[start + j].sort_index = tmp;
2512c896fe29Sbellard             }
2513c896fe29Sbellard         }
2514c896fe29Sbellard     }
2515c896fe29Sbellard }
2516c896fe29Sbellard 
2517f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2518c896fe29Sbellard {
2519a9751609SRichard Henderson     TCGOpcode op;
2520c896fe29Sbellard 
2521f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
2522f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
2523f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
2524069ea736SRichard Henderson         int i, nb_args;
2525f69d277eSRichard Henderson 
2526f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
2527f69d277eSRichard Henderson             continue;
2528f69d277eSRichard Henderson         }
2529f69d277eSRichard Henderson 
2530c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
2531f69d277eSRichard Henderson         if (nb_args == 0) {
2532f69d277eSRichard Henderson             continue;
2533f69d277eSRichard Henderson         }
2534f69d277eSRichard Henderson 
2535*4c22e840SRichard Henderson #ifdef TCG_TARGET_CON_SET_H
2536*4c22e840SRichard Henderson         /*
2537*4c22e840SRichard Henderson          * Macro magic should make it impossible, but double-check that
2538*4c22e840SRichard Henderson          * the array index is in range.  Since the signness of an enum
2539*4c22e840SRichard Henderson          * is implementation defined, force the result to unsigned.
2540*4c22e840SRichard Henderson          */
2541*4c22e840SRichard Henderson         unsigned con_set = tcg_target_op_def(op);
2542*4c22e840SRichard Henderson         tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets));
2543*4c22e840SRichard Henderson         tdefs = &constraint_sets[con_set];
2544*4c22e840SRichard Henderson #else
2545f69d277eSRichard Henderson         tdefs = tcg_target_op_def(op);
2546f69d277eSRichard Henderson         /* Missing TCGTargetOpDef entry. */
2547f69d277eSRichard Henderson         tcg_debug_assert(tdefs != NULL);
2548*4c22e840SRichard Henderson #endif
2549f69d277eSRichard Henderson 
2550c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2551f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
2552f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2553eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2554f69d277eSRichard Henderson 
255517280ff4SRichard Henderson             while (*ct_str != '\0') {
255617280ff4SRichard Henderson                 switch(*ct_str) {
255717280ff4SRichard Henderson                 case '0' ... '9':
255817280ff4SRichard Henderson                     {
255917280ff4SRichard Henderson                         int oarg = *ct_str - '0';
256017280ff4SRichard Henderson                         tcg_debug_assert(ct_str == tdefs->args_ct_str[i]);
2561eabb7b91SAurelien Jarno                         tcg_debug_assert(oarg < def->nb_oargs);
256274a11790SRichard Henderson                         tcg_debug_assert(def->args_ct[oarg].regs != 0);
2563c896fe29Sbellard                         def->args_ct[i] = def->args_ct[oarg];
2564bc2b17e6SRichard Henderson                         /* The output sets oalias.  */
2565bc2b17e6SRichard Henderson                         def->args_ct[oarg].oalias = true;
25665ff9d6a4Sbellard                         def->args_ct[oarg].alias_index = i;
2567bc2b17e6SRichard Henderson                         /* The input sets ialias. */
2568bc2b17e6SRichard Henderson                         def->args_ct[i].ialias = true;
25695ff9d6a4Sbellard                         def->args_ct[i].alias_index = oarg;
257017280ff4SRichard Henderson                     }
257117280ff4SRichard Henderson                     ct_str++;
2572c896fe29Sbellard                     break;
257382790a87SRichard Henderson                 case '&':
2574bc2b17e6SRichard Henderson                     def->args_ct[i].newreg = true;
257582790a87SRichard Henderson                     ct_str++;
257682790a87SRichard Henderson                     break;
2577c896fe29Sbellard                 case 'i':
2578c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2579c896fe29Sbellard                     ct_str++;
2580c896fe29Sbellard                     break;
2581358b4923SRichard Henderson 
2582358b4923SRichard Henderson                 /* Include all of the target-specific constraints. */
2583358b4923SRichard Henderson 
2584358b4923SRichard Henderson #undef CONST
2585358b4923SRichard Henderson #define CONST(CASE, MASK) \
2586358b4923SRichard Henderson     case CASE: def->args_ct[i].ct |= MASK; ct_str++; break;
2587358b4923SRichard Henderson #define REGS(CASE, MASK) \
2588358b4923SRichard Henderson     case CASE: def->args_ct[i].regs |= MASK; ct_str++; break;
2589358b4923SRichard Henderson 
2590358b4923SRichard Henderson #include "tcg-target-con-str.h"
2591358b4923SRichard Henderson 
2592358b4923SRichard Henderson #undef REGS
2593358b4923SRichard Henderson #undef CONST
2594c896fe29Sbellard                 default:
2595358b4923SRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2596358b4923SRichard Henderson                     g_assert_not_reached();
2597358b4923SRichard Henderson                 }
2598c896fe29Sbellard             }
2599c896fe29Sbellard         }
2600c896fe29Sbellard 
2601c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2602eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2603c68aaa18SStefan Weil 
2604c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
2605c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
2606c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
2607c896fe29Sbellard     }
2608c896fe29Sbellard }
2609c896fe29Sbellard 
26100c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
26110c627cdcSRichard Henderson {
2612d88a117eSRichard Henderson     TCGLabel *label;
2613d88a117eSRichard Henderson 
2614d88a117eSRichard Henderson     switch (op->opc) {
2615d88a117eSRichard Henderson     case INDEX_op_br:
2616d88a117eSRichard Henderson         label = arg_label(op->args[0]);
2617d88a117eSRichard Henderson         label->refs--;
2618d88a117eSRichard Henderson         break;
2619d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
2620d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
2621d88a117eSRichard Henderson         label = arg_label(op->args[3]);
2622d88a117eSRichard Henderson         label->refs--;
2623d88a117eSRichard Henderson         break;
2624d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
2625d88a117eSRichard Henderson         label = arg_label(op->args[5]);
2626d88a117eSRichard Henderson         label->refs--;
2627d88a117eSRichard Henderson         break;
2628d88a117eSRichard Henderson     default:
2629d88a117eSRichard Henderson         break;
2630d88a117eSRichard Henderson     }
2631d88a117eSRichard Henderson 
263215fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
263315fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
2634abebf925SRichard Henderson     s->nb_ops--;
26350c627cdcSRichard Henderson 
26360c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
2637d73415a3SStefan Hajnoczi     qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
26380c627cdcSRichard Henderson #endif
26390c627cdcSRichard Henderson }
26400c627cdcSRichard Henderson 
264115fa08f8SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc)
264215fa08f8SRichard Henderson {
264315fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
264415fa08f8SRichard Henderson     TCGOp *op;
264515fa08f8SRichard Henderson 
264615fa08f8SRichard Henderson     if (likely(QTAILQ_EMPTY(&s->free_ops))) {
264715fa08f8SRichard Henderson         op = tcg_malloc(sizeof(TCGOp));
264815fa08f8SRichard Henderson     } else {
264915fa08f8SRichard Henderson         op = QTAILQ_FIRST(&s->free_ops);
265015fa08f8SRichard Henderson         QTAILQ_REMOVE(&s->free_ops, op, link);
265115fa08f8SRichard Henderson     }
265215fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
265315fa08f8SRichard Henderson     op->opc = opc;
2654abebf925SRichard Henderson     s->nb_ops++;
265515fa08f8SRichard Henderson 
265615fa08f8SRichard Henderson     return op;
265715fa08f8SRichard Henderson }
265815fa08f8SRichard Henderson 
265915fa08f8SRichard Henderson TCGOp *tcg_emit_op(TCGOpcode opc)
266015fa08f8SRichard Henderson {
266115fa08f8SRichard Henderson     TCGOp *op = tcg_op_alloc(opc);
266215fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
266315fa08f8SRichard Henderson     return op;
266415fa08f8SRichard Henderson }
266515fa08f8SRichard Henderson 
2666ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
26675a18407fSRichard Henderson {
266815fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
266915fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
26705a18407fSRichard Henderson     return new_op;
26715a18407fSRichard Henderson }
26725a18407fSRichard Henderson 
2673ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
26745a18407fSRichard Henderson {
267515fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
267615fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
26775a18407fSRichard Henderson     return new_op;
26785a18407fSRichard Henderson }
26795a18407fSRichard Henderson 
2680b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
2681b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s)
2682b4fc67c7SRichard Henderson {
2683b4fc67c7SRichard Henderson     TCGOp *op, *op_next;
2684b4fc67c7SRichard Henderson     bool dead = false;
2685b4fc67c7SRichard Henderson 
2686b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
2687b4fc67c7SRichard Henderson         bool remove = dead;
2688b4fc67c7SRichard Henderson         TCGLabel *label;
2689b4fc67c7SRichard Henderson         int call_flags;
2690b4fc67c7SRichard Henderson 
2691b4fc67c7SRichard Henderson         switch (op->opc) {
2692b4fc67c7SRichard Henderson         case INDEX_op_set_label:
2693b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
2694b4fc67c7SRichard Henderson             if (label->refs == 0) {
2695b4fc67c7SRichard Henderson                 /*
2696b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
2697b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
2698b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
2699b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
2700b4fc67c7SRichard Henderson                  * little to be gained by iterating.
2701b4fc67c7SRichard Henderson                  */
2702b4fc67c7SRichard Henderson                 remove = true;
2703b4fc67c7SRichard Henderson             } else {
2704b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
2705b4fc67c7SRichard Henderson                 dead = false;
2706b4fc67c7SRichard Henderson                 remove = false;
2707b4fc67c7SRichard Henderson 
2708b4fc67c7SRichard Henderson                 /*
2709b4fc67c7SRichard Henderson                  * Optimization can fold conditional branches to unconditional.
2710b4fc67c7SRichard Henderson                  * If we find a label with one reference which is preceded by
2711b4fc67c7SRichard Henderson                  * an unconditional branch to it, remove both.  This needed to
2712b4fc67c7SRichard Henderson                  * wait until the dead code in between them was removed.
2713b4fc67c7SRichard Henderson                  */
2714b4fc67c7SRichard Henderson                 if (label->refs == 1) {
2715eae3eb3eSPaolo Bonzini                     TCGOp *op_prev = QTAILQ_PREV(op, link);
2716b4fc67c7SRichard Henderson                     if (op_prev->opc == INDEX_op_br &&
2717b4fc67c7SRichard Henderson                         label == arg_label(op_prev->args[0])) {
2718b4fc67c7SRichard Henderson                         tcg_op_remove(s, op_prev);
2719b4fc67c7SRichard Henderson                         remove = true;
2720b4fc67c7SRichard Henderson                     }
2721b4fc67c7SRichard Henderson                 }
2722b4fc67c7SRichard Henderson             }
2723b4fc67c7SRichard Henderson             break;
2724b4fc67c7SRichard Henderson 
2725b4fc67c7SRichard Henderson         case INDEX_op_br:
2726b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
2727b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
2728b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
2729b4fc67c7SRichard Henderson             dead = true;
2730b4fc67c7SRichard Henderson             break;
2731b4fc67c7SRichard Henderson 
2732b4fc67c7SRichard Henderson         case INDEX_op_call:
2733b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
2734b4fc67c7SRichard Henderson             call_flags = op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1];
2735b4fc67c7SRichard Henderson             if (call_flags & TCG_CALL_NO_RETURN) {
2736b4fc67c7SRichard Henderson                 dead = true;
2737b4fc67c7SRichard Henderson             }
2738b4fc67c7SRichard Henderson             break;
2739b4fc67c7SRichard Henderson 
2740b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
2741b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
2742b4fc67c7SRichard Henderson             remove = false;
2743b4fc67c7SRichard Henderson             break;
2744b4fc67c7SRichard Henderson 
2745b4fc67c7SRichard Henderson         default:
2746b4fc67c7SRichard Henderson             break;
2747b4fc67c7SRichard Henderson         }
2748b4fc67c7SRichard Henderson 
2749b4fc67c7SRichard Henderson         if (remove) {
2750b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
2751b4fc67c7SRichard Henderson         }
2752b4fc67c7SRichard Henderson     }
2753b4fc67c7SRichard Henderson }
2754b4fc67c7SRichard Henderson 
2755c70fbf0aSRichard Henderson #define TS_DEAD  1
2756c70fbf0aSRichard Henderson #define TS_MEM   2
2757c70fbf0aSRichard Henderson 
27585a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
27595a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
27605a18407fSRichard Henderson 
276125f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
276225f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
276325f49c5fSRichard Henderson {
276425f49c5fSRichard Henderson     return ts->state_ptr;
276525f49c5fSRichard Henderson }
276625f49c5fSRichard Henderson 
276725f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
276825f49c5fSRichard Henderson  * maximal regset for its type.
276925f49c5fSRichard Henderson  */
277025f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
277125f49c5fSRichard Henderson {
277225f49c5fSRichard Henderson     *la_temp_pref(ts)
277325f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
277425f49c5fSRichard Henderson }
277525f49c5fSRichard Henderson 
27769c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
27779c43b68dSAurelien Jarno    should be in memory. */
27782616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
2779c896fe29Sbellard {
2780b83eabeaSRichard Henderson     int i;
2781b83eabeaSRichard Henderson 
2782b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2783b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
278425f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2785b83eabeaSRichard Henderson     }
2786b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2787b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
278825f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2789b83eabeaSRichard Henderson     }
2790c896fe29Sbellard }
2791c896fe29Sbellard 
27929c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
27939c43b68dSAurelien Jarno    and local temps should be in memory. */
27942616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
2795641d5fbeSbellard {
2796b83eabeaSRichard Henderson     int i;
2797641d5fbeSbellard 
2798ee17db83SRichard Henderson     for (i = 0; i < nt; ++i) {
2799ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2800ee17db83SRichard Henderson         int state;
2801ee17db83SRichard Henderson 
2802ee17db83SRichard Henderson         switch (ts->kind) {
2803ee17db83SRichard Henderson         case TEMP_FIXED:
2804ee17db83SRichard Henderson         case TEMP_GLOBAL:
2805ee17db83SRichard Henderson         case TEMP_LOCAL:
2806ee17db83SRichard Henderson             state = TS_DEAD | TS_MEM;
2807ee17db83SRichard Henderson             break;
2808ee17db83SRichard Henderson         case TEMP_NORMAL:
2809c0522136SRichard Henderson         case TEMP_CONST:
2810ee17db83SRichard Henderson             state = TS_DEAD;
2811ee17db83SRichard Henderson             break;
2812ee17db83SRichard Henderson         default:
2813ee17db83SRichard Henderson             g_assert_not_reached();
2814c70fbf0aSRichard Henderson         }
2815ee17db83SRichard Henderson         ts->state = state;
2816ee17db83SRichard Henderson         la_reset_pref(ts);
2817641d5fbeSbellard     }
2818641d5fbeSbellard }
2819641d5fbeSbellard 
2820f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
2821f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
2822f65a061cSRichard Henderson {
2823f65a061cSRichard Henderson     int i;
2824f65a061cSRichard Henderson 
2825f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
282625f49c5fSRichard Henderson         int state = s->temps[i].state;
282725f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
282825f49c5fSRichard Henderson         if (state == TS_DEAD) {
282925f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
283025f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
283125f49c5fSRichard Henderson         }
2832f65a061cSRichard Henderson     }
2833f65a061cSRichard Henderson }
2834f65a061cSRichard Henderson 
2835b4cb76e6SRichard Henderson /*
2836b4cb76e6SRichard Henderson  * liveness analysis: conditional branch: all temps are dead,
2837b4cb76e6SRichard Henderson  * globals and local temps should be synced.
2838b4cb76e6SRichard Henderson  */
2839b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
2840b4cb76e6SRichard Henderson {
2841b4cb76e6SRichard Henderson     la_global_sync(s, ng);
2842b4cb76e6SRichard Henderson 
2843b4cb76e6SRichard Henderson     for (int i = ng; i < nt; ++i) {
2844c0522136SRichard Henderson         TCGTemp *ts = &s->temps[i];
2845c0522136SRichard Henderson         int state;
2846c0522136SRichard Henderson 
2847c0522136SRichard Henderson         switch (ts->kind) {
2848c0522136SRichard Henderson         case TEMP_LOCAL:
2849c0522136SRichard Henderson             state = ts->state;
2850c0522136SRichard Henderson             ts->state = state | TS_MEM;
2851b4cb76e6SRichard Henderson             if (state != TS_DEAD) {
2852b4cb76e6SRichard Henderson                 continue;
2853b4cb76e6SRichard Henderson             }
2854c0522136SRichard Henderson             break;
2855c0522136SRichard Henderson         case TEMP_NORMAL:
2856b4cb76e6SRichard Henderson             s->temps[i].state = TS_DEAD;
2857c0522136SRichard Henderson             break;
2858c0522136SRichard Henderson         case TEMP_CONST:
2859c0522136SRichard Henderson             continue;
2860c0522136SRichard Henderson         default:
2861c0522136SRichard Henderson             g_assert_not_reached();
2862b4cb76e6SRichard Henderson         }
2863b4cb76e6SRichard Henderson         la_reset_pref(&s->temps[i]);
2864b4cb76e6SRichard Henderson     }
2865b4cb76e6SRichard Henderson }
2866b4cb76e6SRichard Henderson 
2867f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
2868f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
2869f65a061cSRichard Henderson {
2870f65a061cSRichard Henderson     int i;
2871f65a061cSRichard Henderson 
2872f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
2873f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
287425f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
287525f49c5fSRichard Henderson     }
287625f49c5fSRichard Henderson }
287725f49c5fSRichard Henderson 
287825f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
287925f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
288025f49c5fSRichard Henderson {
288125f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
288225f49c5fSRichard Henderson     int i;
288325f49c5fSRichard Henderson 
288425f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
288525f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
288625f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
288725f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
288825f49c5fSRichard Henderson             TCGRegSet set = *pset;
288925f49c5fSRichard Henderson 
289025f49c5fSRichard Henderson             set &= mask;
289125f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
289225f49c5fSRichard Henderson             if (set == 0) {
289325f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
289425f49c5fSRichard Henderson             }
289525f49c5fSRichard Henderson             *pset = set;
289625f49c5fSRichard Henderson         }
2897f65a061cSRichard Henderson     }
2898f65a061cSRichard Henderson }
2899f65a061cSRichard Henderson 
2900a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
2901c896fe29Sbellard    given input arguments is dead. Instructions updating dead
2902c896fe29Sbellard    temporaries are removed. */
2903b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s)
2904c896fe29Sbellard {
2905c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
29062616c808SRichard Henderson     int nb_temps = s->nb_temps;
290715fa08f8SRichard Henderson     TCGOp *op, *op_prev;
290825f49c5fSRichard Henderson     TCGRegSet *prefs;
290925f49c5fSRichard Henderson     int i;
291025f49c5fSRichard Henderson 
291125f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
291225f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
291325f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
291425f49c5fSRichard Henderson     }
2915c896fe29Sbellard 
2916ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
29172616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
2918c896fe29Sbellard 
2919eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
292025f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
2921c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
2922c45cb8bbSRichard Henderson         bool have_opc_new2;
2923a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
292425f49c5fSRichard Henderson         TCGTemp *ts;
2925c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2926c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2927c45cb8bbSRichard Henderson 
2928c45cb8bbSRichard Henderson         switch (opc) {
2929c896fe29Sbellard         case INDEX_op_call:
2930c6e113f5Sbellard             {
2931c6e113f5Sbellard                 int call_flags;
293225f49c5fSRichard Henderson                 int nb_call_regs;
2933c6e113f5Sbellard 
2934cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
2935cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
2936efee3746SRichard Henderson                 call_flags = op->args[nb_oargs + nb_iargs + 1];
2937c6e113f5Sbellard 
2938c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
293978505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
2940c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
294125f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
294225f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
2943c6e113f5Sbellard                             goto do_not_remove_call;
2944c6e113f5Sbellard                         }
29459c43b68dSAurelien Jarno                     }
2946c45cb8bbSRichard Henderson                     goto do_remove;
2947152c35aaSRichard Henderson                 }
2948c6e113f5Sbellard             do_not_remove_call:
2949c896fe29Sbellard 
295025f49c5fSRichard Henderson                 /* Output args are dead.  */
2951c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
295225f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
295325f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
2954a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
29556b64b624SAurelien Jarno                     }
295625f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
2957a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
29589c43b68dSAurelien Jarno                     }
295925f49c5fSRichard Henderson                     ts->state = TS_DEAD;
296025f49c5fSRichard Henderson                     la_reset_pref(ts);
296125f49c5fSRichard Henderson 
296225f49c5fSRichard Henderson                     /* Not used -- it will be tcg_target_call_oarg_regs[i].  */
296325f49c5fSRichard Henderson                     op->output_pref[i] = 0;
2964c896fe29Sbellard                 }
2965c896fe29Sbellard 
296678505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
296778505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
2968f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
2969c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
2970f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
2971b9c18f56Saurel32                 }
2972c896fe29Sbellard 
297325f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
2974866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
297525f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
297625f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
2977a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
2978c896fe29Sbellard                     }
2979c896fe29Sbellard                 }
298025f49c5fSRichard Henderson 
298125f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
298225f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
298325f49c5fSRichard Henderson 
298425f49c5fSRichard Henderson                 nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
298525f49c5fSRichard Henderson 
298625f49c5fSRichard Henderson                 /* Input arguments are live for preceding opcodes.  */
298725f49c5fSRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
298825f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
298925f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
299025f49c5fSRichard Henderson                         /* For those arguments that die, and will be allocated
299125f49c5fSRichard Henderson                          * in registers, clear the register set for that arg,
299225f49c5fSRichard Henderson                          * to be filled in below.  For args that will be on
299325f49c5fSRichard Henderson                          * the stack, reset to any available reg.
299425f49c5fSRichard Henderson                          */
299525f49c5fSRichard Henderson                         *la_temp_pref(ts)
299625f49c5fSRichard Henderson                             = (i < nb_call_regs ? 0 :
299725f49c5fSRichard Henderson                                tcg_target_available_regs[ts->type]);
299825f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
299925f49c5fSRichard Henderson                     }
300025f49c5fSRichard Henderson                 }
300125f49c5fSRichard Henderson 
300225f49c5fSRichard Henderson                 /* For each input argument, add its input register to prefs.
300325f49c5fSRichard Henderson                    If a temp is used once, this produces a single set bit.  */
300425f49c5fSRichard Henderson                 for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) {
300525f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
300625f49c5fSRichard Henderson                     if (ts) {
300725f49c5fSRichard Henderson                         tcg_regset_set_reg(*la_temp_pref(ts),
300825f49c5fSRichard Henderson                                            tcg_target_call_iarg_regs[i]);
3009c70fbf0aSRichard Henderson                     }
3010c19f47bfSAurelien Jarno                 }
3011c6e113f5Sbellard             }
3012c896fe29Sbellard             break;
3013765b842aSRichard Henderson         case INDEX_op_insn_start:
3014c896fe29Sbellard             break;
30155ff9d6a4Sbellard         case INDEX_op_discard:
30165ff9d6a4Sbellard             /* mark the temporary as dead */
301725f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
301825f49c5fSRichard Henderson             ts->state = TS_DEAD;
301925f49c5fSRichard Henderson             la_reset_pref(ts);
30205ff9d6a4Sbellard             break;
30211305c451SRichard Henderson 
30221305c451SRichard Henderson         case INDEX_op_add2_i32:
3023c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
3024f1fae40cSRichard Henderson             goto do_addsub2;
30251305c451SRichard Henderson         case INDEX_op_sub2_i32:
3026c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
3027f1fae40cSRichard Henderson             goto do_addsub2;
3028f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
3029c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
3030f1fae40cSRichard Henderson             goto do_addsub2;
3031f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
3032c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
3033f1fae40cSRichard Henderson         do_addsub2:
30341305c451SRichard Henderson             nb_iargs = 4;
30351305c451SRichard Henderson             nb_oargs = 2;
30361305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
30371305c451SRichard Henderson                the low part.  The result can be optimized to a simple
30381305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
30391305c451SRichard Henderson                cpu mode is set to 32 bit.  */
3040b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
3041b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
30421305c451SRichard Henderson                     goto do_remove;
30431305c451SRichard Henderson                 }
3044c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
3045c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
3046c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
3047efee3746SRichard Henderson                 op->args[1] = op->args[2];
3048efee3746SRichard Henderson                 op->args[2] = op->args[4];
30491305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
30501305c451SRichard Henderson                 nb_iargs = 2;
30511305c451SRichard Henderson                 nb_oargs = 1;
30521305c451SRichard Henderson             }
30531305c451SRichard Henderson             goto do_not_remove;
30541305c451SRichard Henderson 
30551414968aSRichard Henderson         case INDEX_op_mulu2_i32:
3056c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
3057c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
3058c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
305903271524SRichard Henderson             goto do_mul2;
3060f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
3061c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
3062c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
3063c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
3064f1fae40cSRichard Henderson             goto do_mul2;
3065f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
3066c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
3067c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
3068c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
306903271524SRichard Henderson             goto do_mul2;
3070f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
3071c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
3072c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
3073c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
307403271524SRichard Henderson             goto do_mul2;
3075f1fae40cSRichard Henderson         do_mul2:
30761414968aSRichard Henderson             nb_iargs = 2;
30771414968aSRichard Henderson             nb_oargs = 2;
3078b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
3079b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
308003271524SRichard Henderson                     /* Both parts of the operation are dead.  */
30811414968aSRichard Henderson                     goto do_remove;
30821414968aSRichard Henderson                 }
308303271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
3084c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
3085efee3746SRichard Henderson                 op->args[1] = op->args[2];
3086efee3746SRichard Henderson                 op->args[2] = op->args[3];
3087b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
308803271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
3089c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
3090efee3746SRichard Henderson                 op->args[0] = op->args[1];
3091efee3746SRichard Henderson                 op->args[1] = op->args[2];
3092efee3746SRichard Henderson                 op->args[2] = op->args[3];
309303271524SRichard Henderson             } else {
309403271524SRichard Henderson                 goto do_not_remove;
309503271524SRichard Henderson             }
309603271524SRichard Henderson             /* Mark the single-word operation live.  */
30971414968aSRichard Henderson             nb_oargs = 1;
30981414968aSRichard Henderson             goto do_not_remove;
30991414968aSRichard Henderson 
3100c896fe29Sbellard         default:
31011305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
3102c896fe29Sbellard             nb_iargs = def->nb_iargs;
3103c896fe29Sbellard             nb_oargs = def->nb_oargs;
3104c896fe29Sbellard 
3105c896fe29Sbellard             /* Test if the operation can be removed because all
31065ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
31075ff9d6a4Sbellard                implies side effects */
31085ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
3109c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
3110b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
3111c896fe29Sbellard                         goto do_not_remove;
3112c896fe29Sbellard                     }
31139c43b68dSAurelien Jarno                 }
3114152c35aaSRichard Henderson                 goto do_remove;
3115152c35aaSRichard Henderson             }
3116152c35aaSRichard Henderson             goto do_not_remove;
3117152c35aaSRichard Henderson 
31181305c451SRichard Henderson         do_remove:
31190c627cdcSRichard Henderson             tcg_op_remove(s, op);
3120152c35aaSRichard Henderson             break;
3121152c35aaSRichard Henderson 
3122c896fe29Sbellard         do_not_remove:
3123c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
312425f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
312525f49c5fSRichard Henderson 
312625f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
312725f49c5fSRichard Henderson                 op->output_pref[i] = *la_temp_pref(ts);
312825f49c5fSRichard Henderson 
312925f49c5fSRichard Henderson                 /* Output args are dead.  */
313025f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
3131a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
31326b64b624SAurelien Jarno                 }
313325f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
3134a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
31359c43b68dSAurelien Jarno                 }
313625f49c5fSRichard Henderson                 ts->state = TS_DEAD;
313725f49c5fSRichard Henderson                 la_reset_pref(ts);
3138c896fe29Sbellard             }
3139c896fe29Sbellard 
314025f49c5fSRichard Henderson             /* If end of basic block, update.  */
3141ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
3142ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
3143b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_COND_BRANCH) {
3144b4cb76e6SRichard Henderson                 la_bb_sync(s, nb_globals, nb_temps);
3145ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
31462616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
31473d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
3148f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
314925f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
315025f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
315125f49c5fSRichard Henderson                 }
3152c896fe29Sbellard             }
3153c896fe29Sbellard 
315425f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
3155866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
315625f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
315725f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
3158a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
3159c896fe29Sbellard                 }
3160c19f47bfSAurelien Jarno             }
316125f49c5fSRichard Henderson 
316225f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
3163c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
316425f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
316525f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
316625f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
316725f49c5fSRichard Henderson                        all regs for the type.  */
316825f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
316925f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
317025f49c5fSRichard Henderson                 }
317125f49c5fSRichard Henderson             }
317225f49c5fSRichard Henderson 
317325f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
317425f49c5fSRichard Henderson             switch (opc) {
317525f49c5fSRichard Henderson             case INDEX_op_mov_i32:
317625f49c5fSRichard Henderson             case INDEX_op_mov_i64:
317725f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
317825f49c5fSRichard Henderson                    have proper constraints.  That said, special case
317925f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
318025f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
318125f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
318225f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
318325f49c5fSRichard Henderson                 }
318425f49c5fSRichard Henderson                 break;
318525f49c5fSRichard Henderson 
318625f49c5fSRichard Henderson             default:
318725f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
318825f49c5fSRichard Henderson                     const TCGArgConstraint *ct = &def->args_ct[i];
318925f49c5fSRichard Henderson                     TCGRegSet set, *pset;
319025f49c5fSRichard Henderson 
319125f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
319225f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
319325f49c5fSRichard Henderson                     set = *pset;
319425f49c5fSRichard Henderson 
31959be0d080SRichard Henderson                     set &= ct->regs;
3196bc2b17e6SRichard Henderson                     if (ct->ialias) {
319725f49c5fSRichard Henderson                         set &= op->output_pref[ct->alias_index];
319825f49c5fSRichard Henderson                     }
319925f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
320025f49c5fSRichard Henderson                     if (set == 0) {
32019be0d080SRichard Henderson                         set = ct->regs;
320225f49c5fSRichard Henderson                     }
320325f49c5fSRichard Henderson                     *pset = set;
320425f49c5fSRichard Henderson                 }
320525f49c5fSRichard Henderson                 break;
3206c896fe29Sbellard             }
3207c896fe29Sbellard             break;
3208c896fe29Sbellard         }
3209bee158cbSRichard Henderson         op->life = arg_life;
3210c896fe29Sbellard     }
32111ff0a2c5SEvgeny Voevodin }
3212c896fe29Sbellard 
32135a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
3214b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s)
32155a18407fSRichard Henderson {
32165a18407fSRichard Henderson     int nb_globals = s->nb_globals;
321715fa08f8SRichard Henderson     int nb_temps, i;
32185a18407fSRichard Henderson     bool changes = false;
321915fa08f8SRichard Henderson     TCGOp *op, *op_next;
32205a18407fSRichard Henderson 
32215a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
32225a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
32235a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
32245a18407fSRichard Henderson         if (its->indirect_reg) {
32255a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
32265a18407fSRichard Henderson             dts->type = its->type;
32275a18407fSRichard Henderson             dts->base_type = its->base_type;
3228b83eabeaSRichard Henderson             its->state_ptr = dts;
3229b83eabeaSRichard Henderson         } else {
3230b83eabeaSRichard Henderson             its->state_ptr = NULL;
32315a18407fSRichard Henderson         }
3232b83eabeaSRichard Henderson         /* All globals begin dead.  */
3233b83eabeaSRichard Henderson         its->state = TS_DEAD;
32345a18407fSRichard Henderson     }
3235b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
3236b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
3237b83eabeaSRichard Henderson         its->state_ptr = NULL;
3238b83eabeaSRichard Henderson         its->state = TS_DEAD;
3239b83eabeaSRichard Henderson     }
32405a18407fSRichard Henderson 
324115fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
32425a18407fSRichard Henderson         TCGOpcode opc = op->opc;
32435a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
32445a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
32455a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
3246b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
32475a18407fSRichard Henderson 
32485a18407fSRichard Henderson         if (opc == INDEX_op_call) {
3249cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
3250cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
3251efee3746SRichard Henderson             call_flags = op->args[nb_oargs + nb_iargs + 1];
32525a18407fSRichard Henderson         } else {
32535a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
32545a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
32555a18407fSRichard Henderson 
32565a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
3257b4cb76e6SRichard Henderson             if (def->flags & TCG_OPF_COND_BRANCH) {
3258b4cb76e6SRichard Henderson                 /* Like reading globals: sync_globals */
3259b4cb76e6SRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
3260b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
32615a18407fSRichard Henderson                 /* Like writing globals: save_globals */
32625a18407fSRichard Henderson                 call_flags = 0;
32635a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
32645a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
32655a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
32665a18407fSRichard Henderson             } else {
32675a18407fSRichard Henderson                 /* No effect on globals.  */
32685a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
32695a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
32705a18407fSRichard Henderson             }
32715a18407fSRichard Henderson         }
32725a18407fSRichard Henderson 
32735a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
32745a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3275b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3276b83eabeaSRichard Henderson             if (arg_ts) {
3277b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3278b83eabeaSRichard Henderson                 if (dir_ts && arg_ts->state == TS_DEAD) {
3279b83eabeaSRichard Henderson                     TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
32805a18407fSRichard Henderson                                       ? INDEX_op_ld_i32
32815a18407fSRichard Henderson                                       : INDEX_op_ld_i64);
3282ac1043f6SEmilio G. Cota                     TCGOp *lop = tcg_op_insert_before(s, op, lopc);
32835a18407fSRichard Henderson 
3284b83eabeaSRichard Henderson                     lop->args[0] = temp_arg(dir_ts);
3285b83eabeaSRichard Henderson                     lop->args[1] = temp_arg(arg_ts->mem_base);
3286b83eabeaSRichard Henderson                     lop->args[2] = arg_ts->mem_offset;
32875a18407fSRichard Henderson 
32885a18407fSRichard Henderson                     /* Loaded, but synced with memory.  */
3289b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
32905a18407fSRichard Henderson                 }
32915a18407fSRichard Henderson             }
32925a18407fSRichard Henderson         }
32935a18407fSRichard Henderson 
32945a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
32955a18407fSRichard Henderson            No action is required except keeping temp_state up to date
32965a18407fSRichard Henderson            so that we reload when needed.  */
32975a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3298b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3299b83eabeaSRichard Henderson             if (arg_ts) {
3300b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3301b83eabeaSRichard Henderson                 if (dir_ts) {
3302b83eabeaSRichard Henderson                     op->args[i] = temp_arg(dir_ts);
33035a18407fSRichard Henderson                     changes = true;
33045a18407fSRichard Henderson                     if (IS_DEAD_ARG(i)) {
3305b83eabeaSRichard Henderson                         arg_ts->state = TS_DEAD;
33065a18407fSRichard Henderson                     }
33075a18407fSRichard Henderson                 }
33085a18407fSRichard Henderson             }
33095a18407fSRichard Henderson         }
33105a18407fSRichard Henderson 
33115a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
33125a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
33135a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
33145a18407fSRichard Henderson             /* Nothing to do */
33155a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
33165a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
33175a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
33185a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
3319b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3320b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3321b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
33225a18407fSRichard Henderson             }
33235a18407fSRichard Henderson         } else {
33245a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
33255a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
33265a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
3327b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3328b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3329b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
33305a18407fSRichard Henderson             }
33315a18407fSRichard Henderson         }
33325a18407fSRichard Henderson 
33335a18407fSRichard Henderson         /* Outputs become available.  */
333461f15c48SRichard Henderson         if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) {
333561f15c48SRichard Henderson             arg_ts = arg_temp(op->args[0]);
333661f15c48SRichard Henderson             dir_ts = arg_ts->state_ptr;
333761f15c48SRichard Henderson             if (dir_ts) {
333861f15c48SRichard Henderson                 op->args[0] = temp_arg(dir_ts);
333961f15c48SRichard Henderson                 changes = true;
334061f15c48SRichard Henderson 
334161f15c48SRichard Henderson                 /* The output is now live and modified.  */
334261f15c48SRichard Henderson                 arg_ts->state = 0;
334361f15c48SRichard Henderson 
334461f15c48SRichard Henderson                 if (NEED_SYNC_ARG(0)) {
334561f15c48SRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
334661f15c48SRichard Henderson                                       ? INDEX_op_st_i32
334761f15c48SRichard Henderson                                       : INDEX_op_st_i64);
334861f15c48SRichard Henderson                     TCGOp *sop = tcg_op_insert_after(s, op, sopc);
334961f15c48SRichard Henderson                     TCGTemp *out_ts = dir_ts;
335061f15c48SRichard Henderson 
335161f15c48SRichard Henderson                     if (IS_DEAD_ARG(0)) {
335261f15c48SRichard Henderson                         out_ts = arg_temp(op->args[1]);
335361f15c48SRichard Henderson                         arg_ts->state = TS_DEAD;
335461f15c48SRichard Henderson                         tcg_op_remove(s, op);
335561f15c48SRichard Henderson                     } else {
335661f15c48SRichard Henderson                         arg_ts->state = TS_MEM;
335761f15c48SRichard Henderson                     }
335861f15c48SRichard Henderson 
335961f15c48SRichard Henderson                     sop->args[0] = temp_arg(out_ts);
336061f15c48SRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
336161f15c48SRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
336261f15c48SRichard Henderson                 } else {
336361f15c48SRichard Henderson                     tcg_debug_assert(!IS_DEAD_ARG(0));
336461f15c48SRichard Henderson                 }
336561f15c48SRichard Henderson             }
336661f15c48SRichard Henderson         } else {
33675a18407fSRichard Henderson             for (i = 0; i < nb_oargs; i++) {
3368b83eabeaSRichard Henderson                 arg_ts = arg_temp(op->args[i]);
3369b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3370b83eabeaSRichard Henderson                 if (!dir_ts) {
33715a18407fSRichard Henderson                     continue;
33725a18407fSRichard Henderson                 }
3373b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
33745a18407fSRichard Henderson                 changes = true;
33755a18407fSRichard Henderson 
33765a18407fSRichard Henderson                 /* The output is now live and modified.  */
3377b83eabeaSRichard Henderson                 arg_ts->state = 0;
33785a18407fSRichard Henderson 
33795a18407fSRichard Henderson                 /* Sync outputs upon their last write.  */
33805a18407fSRichard Henderson                 if (NEED_SYNC_ARG(i)) {
3381b83eabeaSRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
33825a18407fSRichard Henderson                                       ? INDEX_op_st_i32
33835a18407fSRichard Henderson                                       : INDEX_op_st_i64);
3384ac1043f6SEmilio G. Cota                     TCGOp *sop = tcg_op_insert_after(s, op, sopc);
33855a18407fSRichard Henderson 
3386b83eabeaSRichard Henderson                     sop->args[0] = temp_arg(dir_ts);
3387b83eabeaSRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
3388b83eabeaSRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
33895a18407fSRichard Henderson 
3390b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
33915a18407fSRichard Henderson                 }
33925a18407fSRichard Henderson                 /* Drop outputs that are dead.  */
33935a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3394b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
33955a18407fSRichard Henderson                 }
33965a18407fSRichard Henderson             }
33975a18407fSRichard Henderson         }
339861f15c48SRichard Henderson     }
33995a18407fSRichard Henderson 
34005a18407fSRichard Henderson     return changes;
34015a18407fSRichard Henderson }
34025a18407fSRichard Henderson 
34038d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
3404c896fe29Sbellard static void dump_regs(TCGContext *s)
3405c896fe29Sbellard {
3406c896fe29Sbellard     TCGTemp *ts;
3407c896fe29Sbellard     int i;
3408c896fe29Sbellard     char buf[64];
3409c896fe29Sbellard 
3410c896fe29Sbellard     for(i = 0; i < s->nb_temps; i++) {
3411c896fe29Sbellard         ts = &s->temps[i];
341243439139SRichard Henderson         printf("  %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3413c896fe29Sbellard         switch(ts->val_type) {
3414c896fe29Sbellard         case TEMP_VAL_REG:
3415c896fe29Sbellard             printf("%s", tcg_target_reg_names[ts->reg]);
3416c896fe29Sbellard             break;
3417c896fe29Sbellard         case TEMP_VAL_MEM:
3418b3a62939SRichard Henderson             printf("%d(%s)", (int)ts->mem_offset,
3419b3a62939SRichard Henderson                    tcg_target_reg_names[ts->mem_base->reg]);
3420c896fe29Sbellard             break;
3421c896fe29Sbellard         case TEMP_VAL_CONST:
3422bdb38b95SRichard Henderson             printf("$0x%" PRIx64, ts->val);
3423c896fe29Sbellard             break;
3424c896fe29Sbellard         case TEMP_VAL_DEAD:
3425c896fe29Sbellard             printf("D");
3426c896fe29Sbellard             break;
3427c896fe29Sbellard         default:
3428c896fe29Sbellard             printf("???");
3429c896fe29Sbellard             break;
3430c896fe29Sbellard         }
3431c896fe29Sbellard         printf("\n");
3432c896fe29Sbellard     }
3433c896fe29Sbellard 
3434c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
3435f8b2f202SRichard Henderson         if (s->reg_to_temp[i] != NULL) {
3436c896fe29Sbellard             printf("%s: %s\n",
3437c896fe29Sbellard                    tcg_target_reg_names[i],
3438f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i]));
3439c896fe29Sbellard         }
3440c896fe29Sbellard     }
3441c896fe29Sbellard }
3442c896fe29Sbellard 
3443c896fe29Sbellard static void check_regs(TCGContext *s)
3444c896fe29Sbellard {
3445869938aeSRichard Henderson     int reg;
3446b6638662SRichard Henderson     int k;
3447c896fe29Sbellard     TCGTemp *ts;
3448c896fe29Sbellard     char buf[64];
3449c896fe29Sbellard 
3450c896fe29Sbellard     for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
3451f8b2f202SRichard Henderson         ts = s->reg_to_temp[reg];
3452f8b2f202SRichard Henderson         if (ts != NULL) {
3453f8b2f202SRichard Henderson             if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) {
3454c896fe29Sbellard                 printf("Inconsistency for register %s:\n",
3455c896fe29Sbellard                        tcg_target_reg_names[reg]);
3456b03cce8eSbellard                 goto fail;
3457c896fe29Sbellard             }
3458c896fe29Sbellard         }
3459c896fe29Sbellard     }
3460c896fe29Sbellard     for (k = 0; k < s->nb_temps; k++) {
3461c896fe29Sbellard         ts = &s->temps[k];
3462ee17db83SRichard Henderson         if (ts->val_type == TEMP_VAL_REG
3463ee17db83SRichard Henderson             && ts->kind != TEMP_FIXED
3464f8b2f202SRichard Henderson             && s->reg_to_temp[ts->reg] != ts) {
3465c896fe29Sbellard             printf("Inconsistency for temp %s:\n",
3466f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3467b03cce8eSbellard         fail:
3468c896fe29Sbellard             printf("reg state:\n");
3469c896fe29Sbellard             dump_regs(s);
3470c896fe29Sbellard             tcg_abort();
3471c896fe29Sbellard         }
3472c896fe29Sbellard     }
3473c896fe29Sbellard }
3474c896fe29Sbellard #endif
3475c896fe29Sbellard 
34762272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
3477c896fe29Sbellard {
34789b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64)
34799b9c37c3SRichard Henderson     /* Sparc64 stack is accessed with offset of 2047 */
3480b591dc59SBlue Swirl     s->current_frame_offset = (s->current_frame_offset +
3481b591dc59SBlue Swirl                                (tcg_target_long)sizeof(tcg_target_long) - 1) &
3482b591dc59SBlue Swirl         ~(sizeof(tcg_target_long) - 1);
3483f44c9960SBlue Swirl #endif
3484b591dc59SBlue Swirl     if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
3485b591dc59SBlue Swirl         s->frame_end) {
34865ff9d6a4Sbellard         tcg_abort();
3487b591dc59SBlue Swirl     }
3488c896fe29Sbellard     ts->mem_offset = s->current_frame_offset;
3489b3a62939SRichard Henderson     ts->mem_base = s->frame_temp;
3490c896fe29Sbellard     ts->mem_allocated = 1;
3491e2c6d1b4SRichard Henderson     s->current_frame_offset += sizeof(tcg_target_long);
3492c896fe29Sbellard }
3493c896fe29Sbellard 
3494b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
3495b3915dbbSRichard Henderson 
349659d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
349759d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
349859d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
3499c896fe29Sbellard {
3500c0522136SRichard Henderson     TCGTempVal new_type;
3501c0522136SRichard Henderson 
3502c0522136SRichard Henderson     switch (ts->kind) {
3503c0522136SRichard Henderson     case TEMP_FIXED:
350459d7c14eSRichard Henderson         return;
3505c0522136SRichard Henderson     case TEMP_GLOBAL:
3506c0522136SRichard Henderson     case TEMP_LOCAL:
3507c0522136SRichard Henderson         new_type = TEMP_VAL_MEM;
3508c0522136SRichard Henderson         break;
3509c0522136SRichard Henderson     case TEMP_NORMAL:
3510c0522136SRichard Henderson         new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD;
3511c0522136SRichard Henderson         break;
3512c0522136SRichard Henderson     case TEMP_CONST:
3513c0522136SRichard Henderson         new_type = TEMP_VAL_CONST;
3514c0522136SRichard Henderson         break;
3515c0522136SRichard Henderson     default:
3516c0522136SRichard Henderson         g_assert_not_reached();
351759d7c14eSRichard Henderson     }
351859d7c14eSRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
351959d7c14eSRichard Henderson         s->reg_to_temp[ts->reg] = NULL;
352059d7c14eSRichard Henderson     }
3521c0522136SRichard Henderson     ts->val_type = new_type;
352259d7c14eSRichard Henderson }
3523c896fe29Sbellard 
352459d7c14eSRichard Henderson /* Mark a temporary as dead.  */
352559d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
352659d7c14eSRichard Henderson {
352759d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
352859d7c14eSRichard Henderson }
352959d7c14eSRichard Henderson 
353059d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
353159d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
353259d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
353359d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
353498b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
353598b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
353659d7c14eSRichard Henderson {
3537c0522136SRichard Henderson     if (!temp_readonly(ts) && !ts->mem_coherent) {
35387f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
35392272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
354059d7c14eSRichard Henderson         }
354159d7c14eSRichard Henderson         switch (ts->val_type) {
354259d7c14eSRichard Henderson         case TEMP_VAL_CONST:
354359d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
354459d7c14eSRichard Henderson                require it later in a register, so attempt to store the
354559d7c14eSRichard Henderson                constant to memory directly.  */
354659d7c14eSRichard Henderson             if (free_or_dead
354759d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
354859d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
354959d7c14eSRichard Henderson                 break;
355059d7c14eSRichard Henderson             }
355159d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
355298b4e186SRichard Henderson                       allocated_regs, preferred_regs);
355359d7c14eSRichard Henderson             /* fallthrough */
355459d7c14eSRichard Henderson 
355559d7c14eSRichard Henderson         case TEMP_VAL_REG:
355659d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
355759d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
355859d7c14eSRichard Henderson             break;
355959d7c14eSRichard Henderson 
356059d7c14eSRichard Henderson         case TEMP_VAL_MEM:
356159d7c14eSRichard Henderson             break;
356259d7c14eSRichard Henderson 
356359d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
356459d7c14eSRichard Henderson         default:
356559d7c14eSRichard Henderson             tcg_abort();
3566c896fe29Sbellard         }
35677f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
35687f6ceedfSAurelien Jarno     }
356959d7c14eSRichard Henderson     if (free_or_dead) {
357059d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
357159d7c14eSRichard Henderson     }
357259d7c14eSRichard Henderson }
35737f6ceedfSAurelien Jarno 
35747f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
3575b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
35767f6ceedfSAurelien Jarno {
3577f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
3578f8b2f202SRichard Henderson     if (ts != NULL) {
357998b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
3580c896fe29Sbellard     }
3581c896fe29Sbellard }
3582c896fe29Sbellard 
3583b016486eSRichard Henderson /**
3584b016486eSRichard Henderson  * tcg_reg_alloc:
3585b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
3586b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
3587b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
3588b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
3589b016486eSRichard Henderson  *
3590b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
3591b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
3592b016486eSRichard Henderson  */
3593b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
3594b016486eSRichard Henderson                             TCGRegSet allocated_regs,
3595b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
3596c896fe29Sbellard {
3597b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
3598b016486eSRichard Henderson     TCGRegSet reg_ct[2];
359991478cefSRichard Henderson     const int *order;
3600c896fe29Sbellard 
3601b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
3602b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
3603b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
3604b016486eSRichard Henderson 
3605b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
3606b016486eSRichard Henderson        or if the preference made no difference.  */
3607b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
3608b016486eSRichard Henderson 
360991478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
3610c896fe29Sbellard 
3611b016486eSRichard Henderson     /* Try free registers, preferences first.  */
3612b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3613b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3614b016486eSRichard Henderson 
3615b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3616b016486eSRichard Henderson             /* One register in the set.  */
3617b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3618b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
3619c896fe29Sbellard                 return reg;
3620c896fe29Sbellard             }
3621b016486eSRichard Henderson         } else {
362291478cefSRichard Henderson             for (i = 0; i < n; i++) {
3623b016486eSRichard Henderson                 TCGReg reg = order[i];
3624b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
3625b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
3626b016486eSRichard Henderson                     return reg;
3627b016486eSRichard Henderson                 }
3628b016486eSRichard Henderson             }
3629b016486eSRichard Henderson         }
3630b016486eSRichard Henderson     }
3631b016486eSRichard Henderson 
3632b016486eSRichard Henderson     /* We must spill something.  */
3633b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3634b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3635b016486eSRichard Henderson 
3636b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3637b016486eSRichard Henderson             /* One register in the set.  */
3638b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3639b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
3640c896fe29Sbellard             return reg;
3641b016486eSRichard Henderson         } else {
3642b016486eSRichard Henderson             for (i = 0; i < n; i++) {
3643b016486eSRichard Henderson                 TCGReg reg = order[i];
3644b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
3645b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
3646b016486eSRichard Henderson                     return reg;
3647b016486eSRichard Henderson                 }
3648b016486eSRichard Henderson             }
3649c896fe29Sbellard         }
3650c896fe29Sbellard     }
3651c896fe29Sbellard 
3652c896fe29Sbellard     tcg_abort();
3653c896fe29Sbellard }
3654c896fe29Sbellard 
365540ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
365640ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
365740ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
3658b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
365940ae5c62SRichard Henderson {
366040ae5c62SRichard Henderson     TCGReg reg;
366140ae5c62SRichard Henderson 
366240ae5c62SRichard Henderson     switch (ts->val_type) {
366340ae5c62SRichard Henderson     case TEMP_VAL_REG:
366440ae5c62SRichard Henderson         return;
366540ae5c62SRichard Henderson     case TEMP_VAL_CONST:
3666b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3667b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
36680a6a8bc8SRichard Henderson         if (ts->type <= TCG_TYPE_I64) {
366940ae5c62SRichard Henderson             tcg_out_movi(s, ts->type, reg, ts->val);
36700a6a8bc8SRichard Henderson         } else {
36714e186175SRichard Henderson             uint64_t val = ts->val;
36724e186175SRichard Henderson             MemOp vece = MO_64;
36734e186175SRichard Henderson 
36744e186175SRichard Henderson             /*
36754e186175SRichard Henderson              * Find the minimal vector element that matches the constant.
36764e186175SRichard Henderson              * The targets will, in general, have to do this search anyway,
36774e186175SRichard Henderson              * do this generically.
36784e186175SRichard Henderson              */
36794e186175SRichard Henderson             if (val == dup_const(MO_8, val)) {
36804e186175SRichard Henderson                 vece = MO_8;
36814e186175SRichard Henderson             } else if (val == dup_const(MO_16, val)) {
36824e186175SRichard Henderson                 vece = MO_16;
36830b4286ddSRichard Henderson             } else if (val == dup_const(MO_32, val)) {
36844e186175SRichard Henderson                 vece = MO_32;
36854e186175SRichard Henderson             }
36864e186175SRichard Henderson 
36874e186175SRichard Henderson             tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val);
36880a6a8bc8SRichard Henderson         }
368940ae5c62SRichard Henderson         ts->mem_coherent = 0;
369040ae5c62SRichard Henderson         break;
369140ae5c62SRichard Henderson     case TEMP_VAL_MEM:
3692b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3693b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
369440ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
369540ae5c62SRichard Henderson         ts->mem_coherent = 1;
369640ae5c62SRichard Henderson         break;
369740ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
369840ae5c62SRichard Henderson     default:
369940ae5c62SRichard Henderson         tcg_abort();
370040ae5c62SRichard Henderson     }
370140ae5c62SRichard Henderson     ts->reg = reg;
370240ae5c62SRichard Henderson     ts->val_type = TEMP_VAL_REG;
370340ae5c62SRichard Henderson     s->reg_to_temp[reg] = ts;
370440ae5c62SRichard Henderson }
370540ae5c62SRichard Henderson 
370659d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
3707e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
370859d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
37091ad80729SAurelien Jarno {
37102c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
3711eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
3712e01fa97dSRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts));
37131ad80729SAurelien Jarno }
37141ad80729SAurelien Jarno 
37159814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
3716641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
3717641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
3718641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
3719641d5fbeSbellard {
3720ac3b8891SRichard Henderson     int i, n;
3721641d5fbeSbellard 
3722ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
3723b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
3724641d5fbeSbellard     }
3725e5097dc8Sbellard }
3726e5097dc8Sbellard 
37273d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
37283d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
37293d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
37303d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
37313d5c5f87SAurelien Jarno {
3732ac3b8891SRichard Henderson     int i, n;
37333d5c5f87SAurelien Jarno 
3734ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
373512b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
373612b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
3737ee17db83SRichard Henderson                          || ts->kind == TEMP_FIXED
373812b9b11aSRichard Henderson                          || ts->mem_coherent);
37393d5c5f87SAurelien Jarno     }
37403d5c5f87SAurelien Jarno }
37413d5c5f87SAurelien Jarno 
3742e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
3743e8996ee0Sbellard    all globals are stored at their canonical location. */
3744e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
3745e5097dc8Sbellard {
3746e5097dc8Sbellard     int i;
3747e5097dc8Sbellard 
3748c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
3749b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
3750c0522136SRichard Henderson 
3751c0522136SRichard Henderson         switch (ts->kind) {
3752c0522136SRichard Henderson         case TEMP_LOCAL:
3753b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
3754c0522136SRichard Henderson             break;
3755c0522136SRichard Henderson         case TEMP_NORMAL:
37562c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
3757eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
3758eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3759c0522136SRichard Henderson             break;
3760c0522136SRichard Henderson         case TEMP_CONST:
3761c0522136SRichard Henderson             /* Similarly, we should have freed any allocated register. */
3762c0522136SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_CONST);
3763c0522136SRichard Henderson             break;
3764c0522136SRichard Henderson         default:
3765c0522136SRichard Henderson             g_assert_not_reached();
3766c896fe29Sbellard         }
3767641d5fbeSbellard     }
3768e8996ee0Sbellard 
3769e8996ee0Sbellard     save_globals(s, allocated_regs);
3770c896fe29Sbellard }
3771c896fe29Sbellard 
3772bab1671fSRichard Henderson /*
3773b4cb76e6SRichard Henderson  * At a conditional branch, we assume all temporaries are dead and
3774b4cb76e6SRichard Henderson  * all globals and local temps are synced to their location.
3775b4cb76e6SRichard Henderson  */
3776b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
3777b4cb76e6SRichard Henderson {
3778b4cb76e6SRichard Henderson     sync_globals(s, allocated_regs);
3779b4cb76e6SRichard Henderson 
3780b4cb76e6SRichard Henderson     for (int i = s->nb_globals; i < s->nb_temps; i++) {
3781b4cb76e6SRichard Henderson         TCGTemp *ts = &s->temps[i];
3782b4cb76e6SRichard Henderson         /*
3783b4cb76e6SRichard Henderson          * The liveness analysis already ensures that temps are dead.
3784b4cb76e6SRichard Henderson          * Keep tcg_debug_asserts for safety.
3785b4cb76e6SRichard Henderson          */
3786c0522136SRichard Henderson         switch (ts->kind) {
3787c0522136SRichard Henderson         case TEMP_LOCAL:
3788b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
3789c0522136SRichard Henderson             break;
3790c0522136SRichard Henderson         case TEMP_NORMAL:
3791b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3792c0522136SRichard Henderson             break;
3793c0522136SRichard Henderson         case TEMP_CONST:
3794c0522136SRichard Henderson             break;
3795c0522136SRichard Henderson         default:
3796c0522136SRichard Henderson             g_assert_not_reached();
3797b4cb76e6SRichard Henderson         }
3798b4cb76e6SRichard Henderson     }
3799b4cb76e6SRichard Henderson }
3800b4cb76e6SRichard Henderson 
3801b4cb76e6SRichard Henderson /*
3802c58f4c97SRichard Henderson  * Specialized code generation for INDEX_op_mov_* with a constant.
3803bab1671fSRichard Henderson  */
38040fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
3805ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
3806ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
3807e8996ee0Sbellard {
3808d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3809e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
381059d7c14eSRichard Henderson 
381159d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
3812f8b2f202SRichard Henderson     if (ots->val_type == TEMP_VAL_REG) {
3813f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = NULL;
3814f8b2f202SRichard Henderson     }
3815e8996ee0Sbellard     ots->val_type = TEMP_VAL_CONST;
3816e8996ee0Sbellard     ots->val = val;
381759d7c14eSRichard Henderson     ots->mem_coherent = 0;
3818ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
3819ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
382059d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
3821f8bf00f1SRichard Henderson         temp_dead(s, ots);
38224c4e1ab2SAurelien Jarno     }
3823e8996ee0Sbellard }
3824e8996ee0Sbellard 
3825bab1671fSRichard Henderson /*
3826bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
3827bab1671fSRichard Henderson  */
3828dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
3829c896fe29Sbellard {
3830dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
383169e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
3832c896fe29Sbellard     TCGTemp *ts, *ots;
3833450445d5SRichard Henderson     TCGType otype, itype;
3834c896fe29Sbellard 
3835d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
383669e3706dSRichard Henderson     preferred_regs = op->output_pref[0];
383743439139SRichard Henderson     ots = arg_temp(op->args[0]);
383843439139SRichard Henderson     ts = arg_temp(op->args[1]);
3839450445d5SRichard Henderson 
3840d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3841e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
3842d63e3b6eSRichard Henderson 
3843450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
3844450445d5SRichard Henderson     otype = ots->type;
3845450445d5SRichard Henderson     itype = ts->type;
3846c896fe29Sbellard 
38470fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
38480fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
38490fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
38500fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
38510fe4fca4SPaolo Bonzini             temp_dead(s, ts);
38520fe4fca4SPaolo Bonzini         }
385369e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
38540fe4fca4SPaolo Bonzini         return;
38550fe4fca4SPaolo Bonzini     }
38560fe4fca4SPaolo Bonzini 
38570fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
38580fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
38590fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
38600fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
38610fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
386269e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
386369e3706dSRichard Henderson                   allocated_regs, preferred_regs);
3864c29c1d7eSAurelien Jarno     }
3865c29c1d7eSAurelien Jarno 
38660fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
3867d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
3868c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
3869c29c1d7eSAurelien Jarno            liveness analysis disabled). */
3870eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
3871c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
38722272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
3873c29c1d7eSAurelien Jarno         }
3874b3a62939SRichard Henderson         tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset);
3875c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
3876f8bf00f1SRichard Henderson             temp_dead(s, ts);
3877c29c1d7eSAurelien Jarno         }
3878f8bf00f1SRichard Henderson         temp_dead(s, ots);
3879e8996ee0Sbellard     } else {
3880ee17db83SRichard Henderson         if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) {
3881c29c1d7eSAurelien Jarno             /* the mov can be suppressed */
3882c29c1d7eSAurelien Jarno             if (ots->val_type == TEMP_VAL_REG) {
3883f8b2f202SRichard Henderson                 s->reg_to_temp[ots->reg] = NULL;
3884c896fe29Sbellard             }
3885c29c1d7eSAurelien Jarno             ots->reg = ts->reg;
3886f8bf00f1SRichard Henderson             temp_dead(s, ts);
3887c29c1d7eSAurelien Jarno         } else {
3888c29c1d7eSAurelien Jarno             if (ots->val_type != TEMP_VAL_REG) {
3889c29c1d7eSAurelien Jarno                 /* When allocating a new register, make sure to not spill the
3890c29c1d7eSAurelien Jarno                    input one. */
3891c29c1d7eSAurelien Jarno                 tcg_regset_set_reg(allocated_regs, ts->reg);
3892450445d5SRichard Henderson                 ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
389369e3706dSRichard Henderson                                          allocated_regs, preferred_regs,
3894b016486eSRichard Henderson                                          ots->indirect_base);
3895c29c1d7eSAurelien Jarno             }
389678113e83SRichard Henderson             if (!tcg_out_mov(s, otype, ots->reg, ts->reg)) {
3897240c08d0SRichard Henderson                 /*
3898240c08d0SRichard Henderson                  * Cross register class move not supported.
3899240c08d0SRichard Henderson                  * Store the source register into the destination slot
3900240c08d0SRichard Henderson                  * and leave the destination temp as TEMP_VAL_MEM.
3901240c08d0SRichard Henderson                  */
3902e01fa97dSRichard Henderson                 assert(!temp_readonly(ots));
3903240c08d0SRichard Henderson                 if (!ts->mem_allocated) {
3904240c08d0SRichard Henderson                     temp_allocate_frame(s, ots);
3905240c08d0SRichard Henderson                 }
3906240c08d0SRichard Henderson                 tcg_out_st(s, ts->type, ts->reg,
3907240c08d0SRichard Henderson                            ots->mem_base->reg, ots->mem_offset);
3908240c08d0SRichard Henderson                 ots->mem_coherent = 1;
3909240c08d0SRichard Henderson                 temp_free_or_dead(s, ots, -1);
3910240c08d0SRichard Henderson                 return;
391178113e83SRichard Henderson             }
3912c29c1d7eSAurelien Jarno         }
3913c896fe29Sbellard         ots->val_type = TEMP_VAL_REG;
3914c896fe29Sbellard         ots->mem_coherent = 0;
3915f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3916ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(0)) {
391798b4e186SRichard Henderson             temp_sync(s, ots, allocated_regs, 0, 0);
3918c29c1d7eSAurelien Jarno         }
3919ec7a869dSAurelien Jarno     }
3920c896fe29Sbellard }
3921c896fe29Sbellard 
3922bab1671fSRichard Henderson /*
3923bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
3924bab1671fSRichard Henderson  */
3925bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
3926bab1671fSRichard Henderson {
3927bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
3928bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
3929bab1671fSRichard Henderson     TCGTemp *its, *ots;
3930bab1671fSRichard Henderson     TCGType itype, vtype;
3931d6ecb4a9SRichard Henderson     intptr_t endian_fixup;
3932bab1671fSRichard Henderson     unsigned vece;
3933bab1671fSRichard Henderson     bool ok;
3934bab1671fSRichard Henderson 
3935bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
3936bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
3937bab1671fSRichard Henderson 
3938bab1671fSRichard Henderson     /* ENV should not be modified.  */
3939e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
3940bab1671fSRichard Henderson 
3941bab1671fSRichard Henderson     itype = its->type;
3942bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
3943bab1671fSRichard Henderson     vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
3944bab1671fSRichard Henderson 
3945bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
3946bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
3947bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
3948bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
3949bab1671fSRichard Henderson             temp_dead(s, its);
3950bab1671fSRichard Henderson         }
3951bab1671fSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, op->output_pref[0]);
3952bab1671fSRichard Henderson         return;
3953bab1671fSRichard Henderson     }
3954bab1671fSRichard Henderson 
39559be0d080SRichard Henderson     dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
39569be0d080SRichard Henderson     dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs;
3957bab1671fSRichard Henderson 
3958bab1671fSRichard Henderson     /* Allocate the output register now.  */
3959bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
3960bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
3961bab1671fSRichard Henderson 
3962bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
3963bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
3964bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
3965bab1671fSRichard Henderson         }
3966bab1671fSRichard Henderson         ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
3967bab1671fSRichard Henderson                                  op->output_pref[0], ots->indirect_base);
3968bab1671fSRichard Henderson         ots->val_type = TEMP_VAL_REG;
3969bab1671fSRichard Henderson         ots->mem_coherent = 0;
3970bab1671fSRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3971bab1671fSRichard Henderson     }
3972bab1671fSRichard Henderson 
3973bab1671fSRichard Henderson     switch (its->val_type) {
3974bab1671fSRichard Henderson     case TEMP_VAL_REG:
3975bab1671fSRichard Henderson         /*
3976bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
3977bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
3978bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
3979bab1671fSRichard Henderson          */
3980bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
3981bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
3982bab1671fSRichard Henderson                 goto done;
3983bab1671fSRichard Henderson             }
3984bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
3985bab1671fSRichard Henderson         }
3986bab1671fSRichard Henderson         if (!its->mem_coherent) {
3987bab1671fSRichard Henderson             /*
3988bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
3989bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
3990bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
3991bab1671fSRichard Henderson              */
3992bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
3993bab1671fSRichard Henderson                 break;
3994bab1671fSRichard Henderson             }
3995bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
3996bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
3997bab1671fSRichard Henderson         }
3998bab1671fSRichard Henderson         /* fall through */
3999bab1671fSRichard Henderson 
4000bab1671fSRichard Henderson     case TEMP_VAL_MEM:
4001d6ecb4a9SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
4002d6ecb4a9SRichard Henderson         endian_fixup = itype == TCG_TYPE_I32 ? 4 : 8;
4003d6ecb4a9SRichard Henderson         endian_fixup -= 1 << vece;
4004d6ecb4a9SRichard Henderson #else
4005d6ecb4a9SRichard Henderson         endian_fixup = 0;
4006d6ecb4a9SRichard Henderson #endif
4007d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
4008d6ecb4a9SRichard Henderson                              its->mem_offset + endian_fixup)) {
4009d6ecb4a9SRichard Henderson             goto done;
4010d6ecb4a9SRichard Henderson         }
4011bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
4012bab1671fSRichard Henderson         break;
4013bab1671fSRichard Henderson 
4014bab1671fSRichard Henderson     default:
4015bab1671fSRichard Henderson         g_assert_not_reached();
4016bab1671fSRichard Henderson     }
4017bab1671fSRichard Henderson 
4018bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
4019bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
4020bab1671fSRichard Henderson     tcg_debug_assert(ok);
4021bab1671fSRichard Henderson 
4022bab1671fSRichard Henderson  done:
4023bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
4024bab1671fSRichard Henderson         temp_dead(s, its);
4025bab1671fSRichard Henderson     }
4026bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
4027bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
4028bab1671fSRichard Henderson     }
4029bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
4030bab1671fSRichard Henderson         temp_dead(s, ots);
4031bab1671fSRichard Henderson     }
4032bab1671fSRichard Henderson }
4033bab1671fSRichard Henderson 
4034dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
4035c896fe29Sbellard {
4036dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
4037dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
403882790a87SRichard Henderson     TCGRegSet i_allocated_regs;
403982790a87SRichard Henderson     TCGRegSet o_allocated_regs;
4040b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
4041b6638662SRichard Henderson     TCGReg reg;
4042c896fe29Sbellard     TCGArg arg;
4043c896fe29Sbellard     const TCGArgConstraint *arg_ct;
4044c896fe29Sbellard     TCGTemp *ts;
4045c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
4046c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
4047c896fe29Sbellard 
4048c896fe29Sbellard     nb_oargs = def->nb_oargs;
4049c896fe29Sbellard     nb_iargs = def->nb_iargs;
4050c896fe29Sbellard 
4051c896fe29Sbellard     /* copy constants */
4052c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
4053dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
4054c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
4055c896fe29Sbellard 
4056d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
4057d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
405882790a87SRichard Henderson 
4059c896fe29Sbellard     /* satisfy input constraints */
4060c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
4061d62816f2SRichard Henderson         TCGRegSet i_preferred_regs, o_preferred_regs;
4062d62816f2SRichard Henderson 
406366792f90SRichard Henderson         i = def->args_ct[nb_oargs + k].sort_index;
4064dd186292SRichard Henderson         arg = op->args[i];
4065c896fe29Sbellard         arg_ct = &def->args_ct[i];
406643439139SRichard Henderson         ts = arg_temp(arg);
406740ae5c62SRichard Henderson 
406840ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
406940ae5c62SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct)) {
4070c896fe29Sbellard             /* constant is OK for instruction */
4071c896fe29Sbellard             const_args[i] = 1;
4072c896fe29Sbellard             new_args[i] = ts->val;
4073d62816f2SRichard Henderson             continue;
4074c896fe29Sbellard         }
407540ae5c62SRichard Henderson 
4076d62816f2SRichard Henderson         i_preferred_regs = o_preferred_regs = 0;
4077bc2b17e6SRichard Henderson         if (arg_ct->ialias) {
4078d62816f2SRichard Henderson             o_preferred_regs = op->output_pref[arg_ct->alias_index];
4079c0522136SRichard Henderson 
4080c0522136SRichard Henderson             /*
4081c0522136SRichard Henderson              * If the input is readonly, then it cannot also be an
4082c0522136SRichard Henderson              * output and aliased to itself.  If the input is not
4083c0522136SRichard Henderson              * dead after the instruction, we must allocate a new
4084c0522136SRichard Henderson              * register and move it.
4085c0522136SRichard Henderson              */
4086c0522136SRichard Henderson             if (temp_readonly(ts) || !IS_DEAD_ARG(i)) {
4087c896fe29Sbellard                 goto allocate_in_reg;
4088c896fe29Sbellard             }
4089d62816f2SRichard Henderson 
4090c0522136SRichard Henderson             /*
4091c0522136SRichard Henderson              * Check if the current register has already been allocated
4092c0522136SRichard Henderson              * for another input aliased to an output.
4093c0522136SRichard Henderson              */
4094d62816f2SRichard Henderson             if (ts->val_type == TEMP_VAL_REG) {
4095d62816f2SRichard Henderson                 reg = ts->reg;
4096c0522136SRichard Henderson                 for (int k2 = 0; k2 < k; k2++) {
4097c0522136SRichard Henderson                     int i2 = def->args_ct[nb_oargs + k2].sort_index;
4098bc2b17e6SRichard Henderson                     if (def->args_ct[i2].ialias && reg == new_args[i2]) {
40997e1df267SAurelien Jarno                         goto allocate_in_reg;
41007e1df267SAurelien Jarno                     }
41017e1df267SAurelien Jarno                 }
41025ff9d6a4Sbellard             }
4103d62816f2SRichard Henderson             i_preferred_regs = o_preferred_regs;
4104866cb6cbSAurelien Jarno         }
4105d62816f2SRichard Henderson 
41069be0d080SRichard Henderson         temp_load(s, ts, arg_ct->regs, i_allocated_regs, i_preferred_regs);
4107c896fe29Sbellard         reg = ts->reg;
4108d62816f2SRichard Henderson 
4109c0522136SRichard Henderson         if (!tcg_regset_test_reg(arg_ct->regs, reg)) {
4110c896fe29Sbellard  allocate_in_reg:
4111c0522136SRichard Henderson             /*
4112c0522136SRichard Henderson              * Allocate a new register matching the constraint
4113c0522136SRichard Henderson              * and move the temporary register into it.
4114c0522136SRichard Henderson              */
4115d62816f2SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
4116d62816f2SRichard Henderson                       i_allocated_regs, 0);
41179be0d080SRichard Henderson             reg = tcg_reg_alloc(s, arg_ct->regs, i_allocated_regs,
4118d62816f2SRichard Henderson                                 o_preferred_regs, ts->indirect_base);
411978113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4120240c08d0SRichard Henderson                 /*
4121240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
4122240c08d0SRichard Henderson                  * temp back to its slot and load from there.
4123240c08d0SRichard Henderson                  */
4124240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
4125240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
4126240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
412778113e83SRichard Henderson             }
4128c896fe29Sbellard         }
4129c896fe29Sbellard         new_args[i] = reg;
4130c896fe29Sbellard         const_args[i] = 0;
413182790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
4132c896fe29Sbellard     }
4133c896fe29Sbellard 
4134c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
4135866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
4136866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
413743439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4138c896fe29Sbellard         }
4139c896fe29Sbellard     }
4140c896fe29Sbellard 
4141b4cb76e6SRichard Henderson     if (def->flags & TCG_OPF_COND_BRANCH) {
4142b4cb76e6SRichard Henderson         tcg_reg_alloc_cbranch(s, i_allocated_regs);
4143b4cb76e6SRichard Henderson     } else if (def->flags & TCG_OPF_BB_END) {
414482790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
4145a52ad07eSAurelien Jarno     } else {
4146c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
4147b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
4148c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4149c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
415082790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
4151c896fe29Sbellard                 }
4152c896fe29Sbellard             }
41533d5c5f87SAurelien Jarno         }
41543d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
41553d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
41563d5c5f87SAurelien Jarno                an exception. */
415782790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
4158c896fe29Sbellard         }
4159c896fe29Sbellard 
4160c896fe29Sbellard         /* satisfy the output constraints */
4161c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
416266792f90SRichard Henderson             i = def->args_ct[k].sort_index;
4163dd186292SRichard Henderson             arg = op->args[i];
4164c896fe29Sbellard             arg_ct = &def->args_ct[i];
416543439139SRichard Henderson             ts = arg_temp(arg);
4166d63e3b6eSRichard Henderson 
4167d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
4168e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
4169d63e3b6eSRichard Henderson 
4170bc2b17e6SRichard Henderson             if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
41715ff9d6a4Sbellard                 reg = new_args[arg_ct->alias_index];
4172bc2b17e6SRichard Henderson             } else if (arg_ct->newreg) {
41739be0d080SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->regs,
417482790a87SRichard Henderson                                     i_allocated_regs | o_allocated_regs,
417569e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
4176c896fe29Sbellard             } else {
41779be0d080SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
417869e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
4179c896fe29Sbellard             }
418082790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
4181639368ddSAurelien Jarno             if (ts->val_type == TEMP_VAL_REG) {
4182f8b2f202SRichard Henderson                 s->reg_to_temp[ts->reg] = NULL;
4183639368ddSAurelien Jarno             }
4184c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
4185c896fe29Sbellard             ts->reg = reg;
4186d63e3b6eSRichard Henderson             /*
4187d63e3b6eSRichard Henderson              * Temp value is modified, so the value kept in memory is
4188d63e3b6eSRichard Henderson              * potentially not the same.
4189d63e3b6eSRichard Henderson              */
4190c896fe29Sbellard             ts->mem_coherent = 0;
4191f8b2f202SRichard Henderson             s->reg_to_temp[reg] = ts;
4192c896fe29Sbellard             new_args[i] = reg;
4193c896fe29Sbellard         }
4194e8996ee0Sbellard     }
4195c896fe29Sbellard 
4196c896fe29Sbellard     /* emit instruction */
4197d2fd745fSRichard Henderson     if (def->flags & TCG_OPF_VECTOR) {
4198d2fd745fSRichard Henderson         tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
4199d2fd745fSRichard Henderson                        new_args, const_args);
4200d2fd745fSRichard Henderson     } else {
4201dd186292SRichard Henderson         tcg_out_op(s, op->opc, new_args, const_args);
4202d2fd745fSRichard Henderson     }
4203c896fe29Sbellard 
4204c896fe29Sbellard     /* move the outputs in the correct register if needed */
4205c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
420643439139SRichard Henderson         ts = arg_temp(op->args[i]);
4207d63e3b6eSRichard Henderson 
4208d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
4209e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
4210d63e3b6eSRichard Henderson 
4211ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
421298b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
421359d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4214f8bf00f1SRichard Henderson             temp_dead(s, ts);
4215ec7a869dSAurelien Jarno         }
4216c896fe29Sbellard     }
4217c896fe29Sbellard }
4218c896fe29Sbellard 
4219efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op)
4220efe86b21SRichard Henderson {
4221efe86b21SRichard Henderson     const TCGLifeData arg_life = op->life;
4222efe86b21SRichard Henderson     TCGTemp *ots, *itsl, *itsh;
4223efe86b21SRichard Henderson     TCGType vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
4224efe86b21SRichard Henderson 
4225efe86b21SRichard Henderson     /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */
4226efe86b21SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 32);
4227efe86b21SRichard Henderson     tcg_debug_assert(TCGOP_VECE(op) == MO_64);
4228efe86b21SRichard Henderson 
4229efe86b21SRichard Henderson     ots = arg_temp(op->args[0]);
4230efe86b21SRichard Henderson     itsl = arg_temp(op->args[1]);
4231efe86b21SRichard Henderson     itsh = arg_temp(op->args[2]);
4232efe86b21SRichard Henderson 
4233efe86b21SRichard Henderson     /* ENV should not be modified.  */
4234efe86b21SRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4235efe86b21SRichard Henderson 
4236efe86b21SRichard Henderson     /* Allocate the output register now.  */
4237efe86b21SRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
4238efe86b21SRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
4239efe86b21SRichard Henderson         TCGRegSet dup_out_regs =
4240efe86b21SRichard Henderson             tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
4241efe86b21SRichard Henderson 
4242efe86b21SRichard Henderson         /* Make sure to not spill the input registers. */
4243efe86b21SRichard Henderson         if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) {
4244efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsl->reg);
4245efe86b21SRichard Henderson         }
4246efe86b21SRichard Henderson         if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) {
4247efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsh->reg);
4248efe86b21SRichard Henderson         }
4249efe86b21SRichard Henderson 
4250efe86b21SRichard Henderson         ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
4251efe86b21SRichard Henderson                                  op->output_pref[0], ots->indirect_base);
4252efe86b21SRichard Henderson         ots->val_type = TEMP_VAL_REG;
4253efe86b21SRichard Henderson         ots->mem_coherent = 0;
4254efe86b21SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
4255efe86b21SRichard Henderson     }
4256efe86b21SRichard Henderson 
4257efe86b21SRichard Henderson     /* Promote dup2 of immediates to dupi_vec. */
4258efe86b21SRichard Henderson     if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) {
4259efe86b21SRichard Henderson         uint64_t val = deposit64(itsl->val, 32, 32, itsh->val);
4260efe86b21SRichard Henderson         MemOp vece = MO_64;
4261efe86b21SRichard Henderson 
4262efe86b21SRichard Henderson         if (val == dup_const(MO_8, val)) {
4263efe86b21SRichard Henderson             vece = MO_8;
4264efe86b21SRichard Henderson         } else if (val == dup_const(MO_16, val)) {
4265efe86b21SRichard Henderson             vece = MO_16;
4266efe86b21SRichard Henderson         } else if (val == dup_const(MO_32, val)) {
4267efe86b21SRichard Henderson             vece = MO_32;
4268efe86b21SRichard Henderson         }
4269efe86b21SRichard Henderson 
4270efe86b21SRichard Henderson         tcg_out_dupi_vec(s, vtype, vece, ots->reg, val);
4271efe86b21SRichard Henderson         goto done;
4272efe86b21SRichard Henderson     }
4273efe86b21SRichard Henderson 
4274efe86b21SRichard Henderson     /* If the two inputs form one 64-bit value, try dupm_vec. */
4275efe86b21SRichard Henderson     if (itsl + 1 == itsh && itsl->base_type == TCG_TYPE_I64) {
4276efe86b21SRichard Henderson         if (!itsl->mem_coherent) {
4277efe86b21SRichard Henderson             temp_sync(s, itsl, s->reserved_regs, 0, 0);
4278efe86b21SRichard Henderson         }
4279efe86b21SRichard Henderson         if (!itsh->mem_coherent) {
4280efe86b21SRichard Henderson             temp_sync(s, itsh, s->reserved_regs, 0, 0);
4281efe86b21SRichard Henderson         }
4282efe86b21SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
4283efe86b21SRichard Henderson         TCGTemp *its = itsh;
4284efe86b21SRichard Henderson #else
4285efe86b21SRichard Henderson         TCGTemp *its = itsl;
4286efe86b21SRichard Henderson #endif
4287efe86b21SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg,
4288efe86b21SRichard Henderson                              its->mem_base->reg, its->mem_offset)) {
4289efe86b21SRichard Henderson             goto done;
4290efe86b21SRichard Henderson         }
4291efe86b21SRichard Henderson     }
4292efe86b21SRichard Henderson 
4293efe86b21SRichard Henderson     /* Fall back to generic expansion. */
4294efe86b21SRichard Henderson     return false;
4295efe86b21SRichard Henderson 
4296efe86b21SRichard Henderson  done:
4297efe86b21SRichard Henderson     if (IS_DEAD_ARG(1)) {
4298efe86b21SRichard Henderson         temp_dead(s, itsl);
4299efe86b21SRichard Henderson     }
4300efe86b21SRichard Henderson     if (IS_DEAD_ARG(2)) {
4301efe86b21SRichard Henderson         temp_dead(s, itsh);
4302efe86b21SRichard Henderson     }
4303efe86b21SRichard Henderson     if (NEED_SYNC_ARG(0)) {
4304efe86b21SRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0));
4305efe86b21SRichard Henderson     } else if (IS_DEAD_ARG(0)) {
4306efe86b21SRichard Henderson         temp_dead(s, ots);
4307efe86b21SRichard Henderson     }
4308efe86b21SRichard Henderson     return true;
4309efe86b21SRichard Henderson }
4310efe86b21SRichard Henderson 
4311b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP
4312b03cce8eSbellard #define STACK_DIR(x) (-(x))
4313b03cce8eSbellard #else
4314b03cce8eSbellard #define STACK_DIR(x) (x)
4315b03cce8eSbellard #endif
4316b03cce8eSbellard 
4317dd186292SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
4318c896fe29Sbellard {
4319cd9090aaSRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
4320cd9090aaSRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
4321dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
4322b6638662SRichard Henderson     int flags, nb_regs, i;
4323b6638662SRichard Henderson     TCGReg reg;
4324cf066674SRichard Henderson     TCGArg arg;
4325c896fe29Sbellard     TCGTemp *ts;
4326d3452f1fSRichard Henderson     intptr_t stack_offset;
4327d3452f1fSRichard Henderson     size_t call_stack_size;
4328cf066674SRichard Henderson     tcg_insn_unit *func_addr;
4329cf066674SRichard Henderson     int allocate_args;
4330c896fe29Sbellard     TCGRegSet allocated_regs;
4331c896fe29Sbellard 
4332dd186292SRichard Henderson     func_addr = (tcg_insn_unit *)(intptr_t)op->args[nb_oargs + nb_iargs];
4333dd186292SRichard Henderson     flags = op->args[nb_oargs + nb_iargs + 1];
4334c896fe29Sbellard 
43356e17d0c5SStefan Weil     nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
4336c45cb8bbSRichard Henderson     if (nb_regs > nb_iargs) {
4337c45cb8bbSRichard Henderson         nb_regs = nb_iargs;
4338cf066674SRichard Henderson     }
4339c896fe29Sbellard 
4340c896fe29Sbellard     /* assign stack slots first */
4341c45cb8bbSRichard Henderson     call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long);
4342c896fe29Sbellard     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
4343c896fe29Sbellard         ~(TCG_TARGET_STACK_ALIGN - 1);
4344b03cce8eSbellard     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
4345b03cce8eSbellard     if (allocate_args) {
4346345649c0SBlue Swirl         /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
4347345649c0SBlue Swirl            preallocate call stack */
4348345649c0SBlue Swirl         tcg_abort();
4349b03cce8eSbellard     }
435039cf05d3Sbellard 
435139cf05d3Sbellard     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
4352c45cb8bbSRichard Henderson     for (i = nb_regs; i < nb_iargs; i++) {
4353dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
435439cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP
435539cf05d3Sbellard         stack_offset -= sizeof(tcg_target_long);
435639cf05d3Sbellard #endif
435739cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
435843439139SRichard Henderson             ts = arg_temp(arg);
435940ae5c62SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
4360b722452aSRichard Henderson                       s->reserved_regs, 0);
4361e4d5434cSblueswir1             tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
436239cf05d3Sbellard         }
436339cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP
436439cf05d3Sbellard         stack_offset += sizeof(tcg_target_long);
436539cf05d3Sbellard #endif
4366c896fe29Sbellard     }
4367c896fe29Sbellard 
4368c896fe29Sbellard     /* assign input registers */
4369d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
4370c896fe29Sbellard     for (i = 0; i < nb_regs; i++) {
4371dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
437239cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
437343439139SRichard Henderson             ts = arg_temp(arg);
4374c896fe29Sbellard             reg = tcg_target_call_iarg_regs[i];
437540ae5c62SRichard Henderson 
4376c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
4377c896fe29Sbellard                 if (ts->reg != reg) {
43784250da10SRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
437978113e83SRichard Henderson                     if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4380240c08d0SRichard Henderson                         /*
4381240c08d0SRichard Henderson                          * Cross register class move not supported.  Sync the
4382240c08d0SRichard Henderson                          * temp back to its slot and load from there.
4383240c08d0SRichard Henderson                          */
4384240c08d0SRichard Henderson                         temp_sync(s, ts, allocated_regs, 0, 0);
4385240c08d0SRichard Henderson                         tcg_out_ld(s, ts->type, reg,
4386240c08d0SRichard Henderson                                    ts->mem_base->reg, ts->mem_offset);
438778113e83SRichard Henderson                     }
4388c896fe29Sbellard                 }
4389c896fe29Sbellard             } else {
4390ccb1bb66SRichard Henderson                 TCGRegSet arg_set = 0;
439140ae5c62SRichard Henderson 
43924250da10SRichard Henderson                 tcg_reg_free(s, reg, allocated_regs);
439340ae5c62SRichard Henderson                 tcg_regset_set_reg(arg_set, reg);
4394b722452aSRichard Henderson                 temp_load(s, ts, arg_set, allocated_regs, 0);
4395c896fe29Sbellard             }
439640ae5c62SRichard Henderson 
4397c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
4398c896fe29Sbellard         }
439939cf05d3Sbellard     }
4400c896fe29Sbellard 
4401c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
4402866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4403866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
440443439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4405c896fe29Sbellard         }
4406c896fe29Sbellard     }
4407c896fe29Sbellard 
4408c896fe29Sbellard     /* clobber call registers */
4409c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4410c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
4411b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
4412c896fe29Sbellard         }
4413c896fe29Sbellard     }
4414c896fe29Sbellard 
441578505279SAurelien Jarno     /* Save globals if they might be written by the helper, sync them if
441678505279SAurelien Jarno        they might be read. */
441778505279SAurelien Jarno     if (flags & TCG_CALL_NO_READ_GLOBALS) {
441878505279SAurelien Jarno         /* Nothing to do */
441978505279SAurelien Jarno     } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) {
442078505279SAurelien Jarno         sync_globals(s, allocated_regs);
442178505279SAurelien Jarno     } else {
4422e8996ee0Sbellard         save_globals(s, allocated_regs);
4423b9c18f56Saurel32     }
4424c896fe29Sbellard 
4425cf066674SRichard Henderson     tcg_out_call(s, func_addr);
4426c896fe29Sbellard 
4427c896fe29Sbellard     /* assign output registers and emit moves if needed */
4428c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
4429dd186292SRichard Henderson         arg = op->args[i];
443043439139SRichard Henderson         ts = arg_temp(arg);
4431d63e3b6eSRichard Henderson 
4432d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
4433e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
4434d63e3b6eSRichard Henderson 
4435c896fe29Sbellard         reg = tcg_target_call_oarg_regs[i];
4436eabb7b91SAurelien Jarno         tcg_debug_assert(s->reg_to_temp[reg] == NULL);
4437639368ddSAurelien Jarno         if (ts->val_type == TEMP_VAL_REG) {
4438f8b2f202SRichard Henderson             s->reg_to_temp[ts->reg] = NULL;
4439639368ddSAurelien Jarno         }
4440c896fe29Sbellard         ts->val_type = TEMP_VAL_REG;
4441c896fe29Sbellard         ts->reg = reg;
4442c896fe29Sbellard         ts->mem_coherent = 0;
4443f8b2f202SRichard Henderson         s->reg_to_temp[reg] = ts;
4444ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
444598b4e186SRichard Henderson             temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i));
444659d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4447f8bf00f1SRichard Henderson             temp_dead(s, ts);
4448c896fe29Sbellard         }
4449c896fe29Sbellard     }
44508c11ad25SAurelien Jarno }
4451c896fe29Sbellard 
4452c896fe29Sbellard #ifdef CONFIG_PROFILER
4453c896fe29Sbellard 
4454c3fac113SEmilio G. Cota /* avoid copy/paste errors */
4455c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field)                       \
4456c3fac113SEmilio G. Cota     do {                                                \
4457d73415a3SStefan Hajnoczi         (to)->field += qatomic_read(&((from)->field));  \
4458c3fac113SEmilio G. Cota     } while (0)
4459c896fe29Sbellard 
4460c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field)                                       \
4461c3fac113SEmilio G. Cota     do {                                                                \
4462d73415a3SStefan Hajnoczi         typeof((from)->field) val__ = qatomic_read(&((from)->field));   \
4463c3fac113SEmilio G. Cota         if (val__ > (to)->field) {                                      \
4464c3fac113SEmilio G. Cota             (to)->field = val__;                                        \
4465c3fac113SEmilio G. Cota         }                                                               \
4466c3fac113SEmilio G. Cota     } while (0)
4467c3fac113SEmilio G. Cota 
4468c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */
4469c3fac113SEmilio G. Cota static inline
4470c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
4471c896fe29Sbellard {
4472d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
4473c3fac113SEmilio G. Cota     unsigned int i;
4474c3fac113SEmilio G. Cota 
44753468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4476d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
44773468b59eSEmilio G. Cota         const TCGProfile *orig = &s->prof;
4478c3fac113SEmilio G. Cota 
4479c3fac113SEmilio G. Cota         if (counters) {
448072fd2efbSEmilio G. Cota             PROF_ADD(prof, orig, cpu_exec_time);
4481c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count1);
4482c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count);
4483c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, op_count);
4484c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, op_count_max);
4485c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, temp_count);
4486c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, temp_count_max);
4487c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, del_op_count);
4488c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_in_len);
4489c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_out_len);
4490c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, search_out_len);
4491c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, interm_time);
4492c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_time);
4493c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, la_time);
4494c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, opt_time);
4495c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_count);
4496c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_time);
4497c3fac113SEmilio G. Cota         }
4498c3fac113SEmilio G. Cota         if (table) {
4499c896fe29Sbellard             int i;
4500d70724ceSzhanghailiang 
450115fc7daaSRichard Henderson             for (i = 0; i < NB_OPS; i++) {
4502c3fac113SEmilio G. Cota                 PROF_ADD(prof, orig, table_op_count[i]);
4503c3fac113SEmilio G. Cota             }
4504c3fac113SEmilio G. Cota         }
4505c3fac113SEmilio G. Cota     }
4506c3fac113SEmilio G. Cota }
4507c3fac113SEmilio G. Cota 
4508c3fac113SEmilio G. Cota #undef PROF_ADD
4509c3fac113SEmilio G. Cota #undef PROF_MAX
4510c3fac113SEmilio G. Cota 
4511c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof)
4512c3fac113SEmilio G. Cota {
4513c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, true, false);
4514c3fac113SEmilio G. Cota }
4515c3fac113SEmilio G. Cota 
4516c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof)
4517c3fac113SEmilio G. Cota {
4518c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, false, true);
4519c3fac113SEmilio G. Cota }
4520c3fac113SEmilio G. Cota 
4521d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
4522c3fac113SEmilio G. Cota {
4523c3fac113SEmilio G. Cota     TCGProfile prof = {};
4524c3fac113SEmilio G. Cota     int i;
4525c3fac113SEmilio G. Cota 
4526c3fac113SEmilio G. Cota     tcg_profile_snapshot_table(&prof);
4527c3fac113SEmilio G. Cota     for (i = 0; i < NB_OPS; i++) {
4528d4c51a0aSMarkus Armbruster         qemu_printf("%s %" PRId64 "\n", tcg_op_defs[i].name,
4529c3fac113SEmilio G. Cota                     prof.table_op_count[i]);
4530c896fe29Sbellard     }
4531c896fe29Sbellard }
453272fd2efbSEmilio G. Cota 
453372fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
453472fd2efbSEmilio G. Cota {
4535d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
453672fd2efbSEmilio G. Cota     unsigned int i;
453772fd2efbSEmilio G. Cota     int64_t ret = 0;
453872fd2efbSEmilio G. Cota 
453972fd2efbSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4540d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
454172fd2efbSEmilio G. Cota         const TCGProfile *prof = &s->prof;
454272fd2efbSEmilio G. Cota 
4543d73415a3SStefan Hajnoczi         ret += qatomic_read(&prof->cpu_exec_time);
454472fd2efbSEmilio G. Cota     }
454572fd2efbSEmilio G. Cota     return ret;
454672fd2efbSEmilio G. Cota }
4547246ae24dSMax Filippov #else
4548d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
4549246ae24dSMax Filippov {
4550d4c51a0aSMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4551246ae24dSMax Filippov }
455272fd2efbSEmilio G. Cota 
455372fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
455472fd2efbSEmilio G. Cota {
455572fd2efbSEmilio G. Cota     error_report("%s: TCG profiler not compiled", __func__);
455672fd2efbSEmilio G. Cota     exit(EXIT_FAILURE);
455772fd2efbSEmilio G. Cota }
4558c896fe29Sbellard #endif
4559c896fe29Sbellard 
4560c896fe29Sbellard 
45615bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
4562c896fe29Sbellard {
4563c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER
4564c3fac113SEmilio G. Cota     TCGProfile *prof = &s->prof;
4565c3fac113SEmilio G. Cota #endif
456615fa08f8SRichard Henderson     int i, num_insns;
456715fa08f8SRichard Henderson     TCGOp *op;
4568c896fe29Sbellard 
456904fe6400SRichard Henderson #ifdef CONFIG_PROFILER
457004fe6400SRichard Henderson     {
4571c1f543b7SEmilio G. Cota         int n = 0;
457204fe6400SRichard Henderson 
457315fa08f8SRichard Henderson         QTAILQ_FOREACH(op, &s->ops, link) {
457415fa08f8SRichard Henderson             n++;
457515fa08f8SRichard Henderson         }
4576d73415a3SStefan Hajnoczi         qatomic_set(&prof->op_count, prof->op_count + n);
4577c3fac113SEmilio G. Cota         if (n > prof->op_count_max) {
4578d73415a3SStefan Hajnoczi             qatomic_set(&prof->op_count_max, n);
457904fe6400SRichard Henderson         }
458004fe6400SRichard Henderson 
458104fe6400SRichard Henderson         n = s->nb_temps;
4582d73415a3SStefan Hajnoczi         qatomic_set(&prof->temp_count, prof->temp_count + n);
4583c3fac113SEmilio G. Cota         if (n > prof->temp_count_max) {
4584d73415a3SStefan Hajnoczi             qatomic_set(&prof->temp_count_max, n);
458504fe6400SRichard Henderson         }
458604fe6400SRichard Henderson     }
458704fe6400SRichard Henderson #endif
458804fe6400SRichard Henderson 
4589c896fe29Sbellard #ifdef DEBUG_DISAS
4590d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
4591d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
4592fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
459393fcfe39Saliguori         qemu_log("OP:\n");
45941894f69aSRichard Henderson         tcg_dump_ops(s, false);
459593fcfe39Saliguori         qemu_log("\n");
4596fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
4597c896fe29Sbellard     }
4598c896fe29Sbellard #endif
4599c896fe29Sbellard 
4600bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
4601bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
4602bef16ab4SRichard Henderson     {
4603bef16ab4SRichard Henderson         TCGLabel *l;
4604bef16ab4SRichard Henderson         bool error = false;
4605bef16ab4SRichard Henderson 
4606bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
4607bef16ab4SRichard Henderson             if (unlikely(!l->present) && l->refs) {
4608bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
4609bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
4610bef16ab4SRichard Henderson                 error = true;
4611bef16ab4SRichard Henderson             }
4612bef16ab4SRichard Henderson         }
4613bef16ab4SRichard Henderson         assert(!error);
4614bef16ab4SRichard Henderson     }
4615bef16ab4SRichard Henderson #endif
4616bef16ab4SRichard Henderson 
4617c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
4618d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
4619c5cc28ffSAurelien Jarno #endif
4620c5cc28ffSAurelien Jarno 
46218f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
4622c45cb8bbSRichard Henderson     tcg_optimize(s);
46238f2e8c07SKirill Batuzov #endif
46248f2e8c07SKirill Batuzov 
4625a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4626d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
4627d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time - profile_getclock());
4628a23a9ec6Sbellard #endif
4629c5cc28ffSAurelien Jarno 
4630b4fc67c7SRichard Henderson     reachable_code_pass(s);
4631b83eabeaSRichard Henderson     liveness_pass_1(s);
46325a18407fSRichard Henderson 
46335a18407fSRichard Henderson     if (s->nb_indirects > 0) {
46345a18407fSRichard Henderson #ifdef DEBUG_DISAS
46355a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
46365a18407fSRichard Henderson                      && qemu_log_in_addr_range(tb->pc))) {
4637fc59d2d8SRobert Foley             FILE *logfile = qemu_log_lock();
46385a18407fSRichard Henderson             qemu_log("OP before indirect lowering:\n");
46391894f69aSRichard Henderson             tcg_dump_ops(s, false);
46405a18407fSRichard Henderson             qemu_log("\n");
4641fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
46425a18407fSRichard Henderson         }
46435a18407fSRichard Henderson #endif
46445a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
4645b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
46465a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
4647b83eabeaSRichard Henderson             liveness_pass_1(s);
46485a18407fSRichard Henderson         }
46495a18407fSRichard Henderson     }
4650c5cc28ffSAurelien Jarno 
4651a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4652d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time + profile_getclock());
4653a23a9ec6Sbellard #endif
4654c896fe29Sbellard 
4655c896fe29Sbellard #ifdef DEBUG_DISAS
4656d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
4657d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
4658fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
4659c5cc28ffSAurelien Jarno         qemu_log("OP after optimization and liveness analysis:\n");
46601894f69aSRichard Henderson         tcg_dump_ops(s, true);
466193fcfe39Saliguori         qemu_log("\n");
4662fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
4663c896fe29Sbellard     }
4664c896fe29Sbellard #endif
4665c896fe29Sbellard 
4666c896fe29Sbellard     tcg_reg_alloc_start(s);
4667c896fe29Sbellard 
4668db0c51a3SRichard Henderson     /*
4669db0c51a3SRichard Henderson      * Reset the buffer pointers when restarting after overflow.
4670db0c51a3SRichard Henderson      * TODO: Move this into translate-all.c with the rest of the
4671db0c51a3SRichard Henderson      * buffer management.  Having only this done here is confusing.
4672db0c51a3SRichard Henderson      */
4673db0c51a3SRichard Henderson     s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr);
4674db0c51a3SRichard Henderson     s->code_ptr = s->code_buf;
4675c896fe29Sbellard 
4676659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
46776001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
4678659ef5cbSRichard Henderson #endif
467957a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
468057a26946SRichard Henderson     s->pool_labels = NULL;
468157a26946SRichard Henderson #endif
46829ecefc84SRichard Henderson 
4683fca8a500SRichard Henderson     num_insns = -1;
468415fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
4685c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
4686b3db8758Sblueswir1 
4687c896fe29Sbellard #ifdef CONFIG_PROFILER
4688d73415a3SStefan Hajnoczi         qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
4689c896fe29Sbellard #endif
4690c45cb8bbSRichard Henderson 
4691c896fe29Sbellard         switch (opc) {
4692c896fe29Sbellard         case INDEX_op_mov_i32:
4693c896fe29Sbellard         case INDEX_op_mov_i64:
4694d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
4695dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
4696c896fe29Sbellard             break;
4697bab1671fSRichard Henderson         case INDEX_op_dup_vec:
4698bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
4699bab1671fSRichard Henderson             break;
4700765b842aSRichard Henderson         case INDEX_op_insn_start:
4701fca8a500SRichard Henderson             if (num_insns >= 0) {
47029f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
47039f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
47049f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
47059f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
4706fca8a500SRichard Henderson             }
4707fca8a500SRichard Henderson             num_insns++;
4708bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
4709bad729e2SRichard Henderson                 target_ulong a;
4710bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
4711efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
4712bad729e2SRichard Henderson #else
4713efee3746SRichard Henderson                 a = op->args[i];
4714bad729e2SRichard Henderson #endif
4715fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
4716bad729e2SRichard Henderson             }
4717c896fe29Sbellard             break;
47185ff9d6a4Sbellard         case INDEX_op_discard:
471943439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
47205ff9d6a4Sbellard             break;
4721c896fe29Sbellard         case INDEX_op_set_label:
4722e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
472392ab8e7dSRichard Henderson             tcg_out_label(s, arg_label(op->args[0]));
4724c896fe29Sbellard             break;
4725c896fe29Sbellard         case INDEX_op_call:
4726dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
4727c45cb8bbSRichard Henderson             break;
4728efe86b21SRichard Henderson         case INDEX_op_dup2_vec:
4729efe86b21SRichard Henderson             if (tcg_reg_alloc_dup2(s, op)) {
4730efe86b21SRichard Henderson                 break;
4731efe86b21SRichard Henderson             }
4732efe86b21SRichard Henderson             /* fall through */
4733c896fe29Sbellard         default:
473425c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
4735be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
4736c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
4737c896fe29Sbellard                faster to have specialized register allocator functions for
4738c896fe29Sbellard                some common argument patterns */
4739dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
4740c896fe29Sbellard             break;
4741c896fe29Sbellard         }
47428d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
4743c896fe29Sbellard         check_regs(s);
4744c896fe29Sbellard #endif
4745b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
4746b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
4747b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
4748b125f9dcSRichard Henderson            generating code without having to check during generation.  */
4749644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
4750b125f9dcSRichard Henderson             return -1;
4751b125f9dcSRichard Henderson         }
47526e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
47536e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
47546e6c4efeSRichard Henderson             return -2;
47556e6c4efeSRichard Henderson         }
4756c896fe29Sbellard     }
4757fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
4758fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
4759c45cb8bbSRichard Henderson 
4760b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
4761659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
4762aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
4763aeee05f5SRichard Henderson     if (i < 0) {
4764aeee05f5SRichard Henderson         return i;
476523dceda6SRichard Henderson     }
4766659ef5cbSRichard Henderson #endif
476757a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
47681768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
47691768987bSRichard Henderson     if (i < 0) {
47701768987bSRichard Henderson         return i;
477157a26946SRichard Henderson     }
477257a26946SRichard Henderson #endif
47737ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
47747ecd02a0SRichard Henderson         return -2;
47757ecd02a0SRichard Henderson     }
4776c896fe29Sbellard 
4777df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
4778c896fe29Sbellard     /* flush instruction cache */
4779db0c51a3SRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
4780db0c51a3SRichard Henderson                         (uintptr_t)s->code_buf,
47811da8de39SRichard Henderson                         tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
4782df5d2b16SRichard Henderson #endif
47832aeabc08SStefan Weil 
47841813e175SRichard Henderson     return tcg_current_code_size(s);
4785c896fe29Sbellard }
4786c896fe29Sbellard 
4787a23a9ec6Sbellard #ifdef CONFIG_PROFILER
47883de2faa9SMarkus Armbruster void tcg_dump_info(void)
4789a23a9ec6Sbellard {
4790c3fac113SEmilio G. Cota     TCGProfile prof = {};
4791c3fac113SEmilio G. Cota     const TCGProfile *s;
4792c3fac113SEmilio G. Cota     int64_t tb_count;
4793c3fac113SEmilio G. Cota     int64_t tb_div_count;
4794c3fac113SEmilio G. Cota     int64_t tot;
4795c3fac113SEmilio G. Cota 
4796c3fac113SEmilio G. Cota     tcg_profile_snapshot_counters(&prof);
4797c3fac113SEmilio G. Cota     s = &prof;
4798c3fac113SEmilio G. Cota     tb_count = s->tb_count;
4799c3fac113SEmilio G. Cota     tb_div_count = tb_count ? tb_count : 1;
4800c3fac113SEmilio G. Cota     tot = s->interm_time + s->code_time;
4801a23a9ec6Sbellard 
48023de2faa9SMarkus Armbruster     qemu_printf("JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
4803a23a9ec6Sbellard                 tot, tot / 2.4e9);
48043de2faa9SMarkus Armbruster     qemu_printf("translated TBs      %" PRId64 " (aborted=%" PRId64
48053de2faa9SMarkus Armbruster                 " %0.1f%%)\n",
4806fca8a500SRichard Henderson                 tb_count, s->tb_count1 - tb_count,
4807fca8a500SRichard Henderson                 (double)(s->tb_count1 - s->tb_count)
4808fca8a500SRichard Henderson                 / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
48093de2faa9SMarkus Armbruster     qemu_printf("avg ops/TB          %0.1f max=%d\n",
4810fca8a500SRichard Henderson                 (double)s->op_count / tb_div_count, s->op_count_max);
48113de2faa9SMarkus Armbruster     qemu_printf("deleted ops/TB      %0.2f\n",
4812fca8a500SRichard Henderson                 (double)s->del_op_count / tb_div_count);
48133de2faa9SMarkus Armbruster     qemu_printf("avg temps/TB        %0.2f max=%d\n",
4814fca8a500SRichard Henderson                 (double)s->temp_count / tb_div_count, s->temp_count_max);
48153de2faa9SMarkus Armbruster     qemu_printf("avg host code/TB    %0.1f\n",
4816fca8a500SRichard Henderson                 (double)s->code_out_len / tb_div_count);
48173de2faa9SMarkus Armbruster     qemu_printf("avg search data/TB  %0.1f\n",
4818fca8a500SRichard Henderson                 (double)s->search_out_len / tb_div_count);
4819a23a9ec6Sbellard 
48203de2faa9SMarkus Armbruster     qemu_printf("cycles/op           %0.1f\n",
4821a23a9ec6Sbellard                 s->op_count ? (double)tot / s->op_count : 0);
48223de2faa9SMarkus Armbruster     qemu_printf("cycles/in byte      %0.1f\n",
4823a23a9ec6Sbellard                 s->code_in_len ? (double)tot / s->code_in_len : 0);
48243de2faa9SMarkus Armbruster     qemu_printf("cycles/out byte     %0.1f\n",
4825a23a9ec6Sbellard                 s->code_out_len ? (double)tot / s->code_out_len : 0);
48263de2faa9SMarkus Armbruster     qemu_printf("cycles/search byte     %0.1f\n",
4827fca8a500SRichard Henderson                 s->search_out_len ? (double)tot / s->search_out_len : 0);
4828fca8a500SRichard Henderson     if (tot == 0) {
4829a23a9ec6Sbellard         tot = 1;
4830fca8a500SRichard Henderson     }
48313de2faa9SMarkus Armbruster     qemu_printf("  gen_interm time   %0.1f%%\n",
4832a23a9ec6Sbellard                 (double)s->interm_time / tot * 100.0);
48333de2faa9SMarkus Armbruster     qemu_printf("  gen_code time     %0.1f%%\n",
4834a23a9ec6Sbellard                 (double)s->code_time / tot * 100.0);
48353de2faa9SMarkus Armbruster     qemu_printf("optim./code time    %0.1f%%\n",
4836c5cc28ffSAurelien Jarno                 (double)s->opt_time / (s->code_time ? s->code_time : 1)
4837c5cc28ffSAurelien Jarno                 * 100.0);
48383de2faa9SMarkus Armbruster     qemu_printf("liveness/code time  %0.1f%%\n",
4839a23a9ec6Sbellard                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
48403de2faa9SMarkus Armbruster     qemu_printf("cpu_restore count   %" PRId64 "\n",
4841a23a9ec6Sbellard                 s->restore_count);
48423de2faa9SMarkus Armbruster     qemu_printf("  avg cycles        %0.1f\n",
4843a23a9ec6Sbellard                 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
4844a23a9ec6Sbellard }
4845a23a9ec6Sbellard #else
48463de2faa9SMarkus Armbruster void tcg_dump_info(void)
4847a23a9ec6Sbellard {
48483de2faa9SMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4849a23a9ec6Sbellard }
4850a23a9ec6Sbellard #endif
4851813da627SRichard Henderson 
4852813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
48535872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
48545872bbf2SRichard Henderson 
48555872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
48565872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
48575872bbf2SRichard Henderson 
48585872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
48595872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
48605872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
48615872bbf2SRichard Henderson 
48625872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
48635872bbf2SRichard Henderson */
4864813da627SRichard Henderson 
4865813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
4866813da627SRichard Henderson typedef enum {
4867813da627SRichard Henderson     JIT_NOACTION = 0,
4868813da627SRichard Henderson     JIT_REGISTER_FN,
4869813da627SRichard Henderson     JIT_UNREGISTER_FN
4870813da627SRichard Henderson } jit_actions_t;
4871813da627SRichard Henderson 
4872813da627SRichard Henderson struct jit_code_entry {
4873813da627SRichard Henderson     struct jit_code_entry *next_entry;
4874813da627SRichard Henderson     struct jit_code_entry *prev_entry;
4875813da627SRichard Henderson     const void *symfile_addr;
4876813da627SRichard Henderson     uint64_t symfile_size;
4877813da627SRichard Henderson };
4878813da627SRichard Henderson 
4879813da627SRichard Henderson struct jit_descriptor {
4880813da627SRichard Henderson     uint32_t version;
4881813da627SRichard Henderson     uint32_t action_flag;
4882813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
4883813da627SRichard Henderson     struct jit_code_entry *first_entry;
4884813da627SRichard Henderson };
4885813da627SRichard Henderson 
4886813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
4887813da627SRichard Henderson void __jit_debug_register_code(void)
4888813da627SRichard Henderson {
4889813da627SRichard Henderson     asm("");
4890813da627SRichard Henderson }
4891813da627SRichard Henderson 
4892813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
4893813da627SRichard Henderson    the version before we can set it.  */
4894813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
4895813da627SRichard Henderson 
4896813da627SRichard Henderson /* End GDB interface.  */
4897813da627SRichard Henderson 
4898813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
4899813da627SRichard Henderson {
4900813da627SRichard Henderson     const char *p = strtab + 1;
4901813da627SRichard Henderson 
4902813da627SRichard Henderson     while (1) {
4903813da627SRichard Henderson         if (strcmp(p, str) == 0) {
4904813da627SRichard Henderson             return p - strtab;
4905813da627SRichard Henderson         }
4906813da627SRichard Henderson         p += strlen(p) + 1;
4907813da627SRichard Henderson     }
4908813da627SRichard Henderson }
4909813da627SRichard Henderson 
4910755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size,
49112c90784aSRichard Henderson                                  const void *debug_frame,
49122c90784aSRichard Henderson                                  size_t debug_frame_size)
4913813da627SRichard Henderson {
49145872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
49155872bbf2SRichard Henderson         uint32_t  len;
49165872bbf2SRichard Henderson         uint16_t  version;
49175872bbf2SRichard Henderson         uint32_t  abbrev;
49185872bbf2SRichard Henderson         uint8_t   ptr_size;
49195872bbf2SRichard Henderson         uint8_t   cu_die;
49205872bbf2SRichard Henderson         uint16_t  cu_lang;
49215872bbf2SRichard Henderson         uintptr_t cu_low_pc;
49225872bbf2SRichard Henderson         uintptr_t cu_high_pc;
49235872bbf2SRichard Henderson         uint8_t   fn_die;
49245872bbf2SRichard Henderson         char      fn_name[16];
49255872bbf2SRichard Henderson         uintptr_t fn_low_pc;
49265872bbf2SRichard Henderson         uintptr_t fn_high_pc;
49275872bbf2SRichard Henderson         uint8_t   cu_eoc;
49285872bbf2SRichard Henderson     };
4929813da627SRichard Henderson 
4930813da627SRichard Henderson     struct ElfImage {
4931813da627SRichard Henderson         ElfW(Ehdr) ehdr;
4932813da627SRichard Henderson         ElfW(Phdr) phdr;
49335872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
49345872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
49355872bbf2SRichard Henderson         struct DebugInfo di;
49365872bbf2SRichard Henderson         uint8_t    da[24];
49375872bbf2SRichard Henderson         char       str[80];
49385872bbf2SRichard Henderson     };
49395872bbf2SRichard Henderson 
49405872bbf2SRichard Henderson     struct ElfImage *img;
49415872bbf2SRichard Henderson 
49425872bbf2SRichard Henderson     static const struct ElfImage img_template = {
49435872bbf2SRichard Henderson         .ehdr = {
49445872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
49455872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
49465872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
49475872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
49485872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
49495872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
49505872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
49515872bbf2SRichard Henderson             .e_type = ET_EXEC,
49525872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
49535872bbf2SRichard Henderson             .e_version = EV_CURRENT,
49545872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
49555872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
49565872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
49575872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
49585872bbf2SRichard Henderson             .e_phnum = 1,
49595872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
49605872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
49615872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
4962abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
4963abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
4964abbb3eaeSRichard Henderson #endif
4965abbb3eaeSRichard Henderson #ifdef ELF_OSABI
4966abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
4967abbb3eaeSRichard Henderson #endif
49685872bbf2SRichard Henderson         },
49695872bbf2SRichard Henderson         .phdr = {
49705872bbf2SRichard Henderson             .p_type = PT_LOAD,
49715872bbf2SRichard Henderson             .p_flags = PF_X,
49725872bbf2SRichard Henderson         },
49735872bbf2SRichard Henderson         .shdr = {
49745872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
49755872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
49765872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
49775872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
49785872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
49795872bbf2SRichard Henderson             [1] = { /* .text */
49805872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
49815872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
49825872bbf2SRichard Henderson             },
49835872bbf2SRichard Henderson             [2] = { /* .debug_info */
49845872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
49855872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
49865872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
49875872bbf2SRichard Henderson             },
49885872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
49895872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
49905872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
49915872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
49925872bbf2SRichard Henderson             },
49935872bbf2SRichard Henderson             [4] = { /* .debug_frame */
49945872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
49955872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
49965872bbf2SRichard Henderson             },
49975872bbf2SRichard Henderson             [5] = { /* .symtab */
49985872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
49995872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
50005872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
50015872bbf2SRichard Henderson                 .sh_info = 1,
50025872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
50035872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
50045872bbf2SRichard Henderson             },
50055872bbf2SRichard Henderson             [6] = { /* .strtab */
50065872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
50075872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
50085872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
50095872bbf2SRichard Henderson             }
50105872bbf2SRichard Henderson         },
50115872bbf2SRichard Henderson         .sym = {
50125872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
50135872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
50145872bbf2SRichard Henderson                 .st_shndx = 1,
50155872bbf2SRichard Henderson             }
50165872bbf2SRichard Henderson         },
50175872bbf2SRichard Henderson         .di = {
50185872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
50195872bbf2SRichard Henderson             .version = 2,
50205872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
50215872bbf2SRichard Henderson             .cu_die = 1,
50225872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
50235872bbf2SRichard Henderson             .fn_die = 2,
50245872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
50255872bbf2SRichard Henderson         },
50265872bbf2SRichard Henderson         .da = {
50275872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
50285872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
50295872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
50305872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
50315872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
50325872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
50335872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
50345872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
50355872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
50365872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
50375872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
50385872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
50395872bbf2SRichard Henderson             0           /* no more abbrev */
50405872bbf2SRichard Henderson         },
50415872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
50425872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
5043813da627SRichard Henderson     };
5044813da627SRichard Henderson 
5045813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
5046813da627SRichard Henderson     static struct jit_code_entry one_entry;
5047813da627SRichard Henderson 
50485872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
5049813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
50502c90784aSRichard Henderson     DebugFrameHeader *dfh;
5051813da627SRichard Henderson 
50525872bbf2SRichard Henderson     img = g_malloc(img_size);
50535872bbf2SRichard Henderson     *img = img_template;
5054813da627SRichard Henderson 
50555872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
50565872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
50575872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
5058813da627SRichard Henderson 
50595872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
50605872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
50615872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
5062813da627SRichard Henderson 
50635872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
50645872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
50655872bbf2SRichard Henderson 
50665872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
50675872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
50685872bbf2SRichard Henderson 
50695872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
50705872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
50715872bbf2SRichard Henderson 
50725872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
50735872bbf2SRichard Henderson     img->sym[1].st_value = buf;
50745872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
50755872bbf2SRichard Henderson 
50765872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
507745aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
50785872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
507945aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
5080813da627SRichard Henderson 
50812c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
50822c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
50832c90784aSRichard Henderson     dfh->fde.func_start = buf;
50842c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
50852c90784aSRichard Henderson 
5086813da627SRichard Henderson #ifdef DEBUG_JIT
5087813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
5088813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
5089813da627SRichard Henderson     {
5090813da627SRichard Henderson         FILE *f = fopen("/tmp/qemu.jit", "w+b");
5091813da627SRichard Henderson         if (f) {
50925872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
5093813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
5094813da627SRichard Henderson             }
5095813da627SRichard Henderson             fclose(f);
5096813da627SRichard Henderson         }
5097813da627SRichard Henderson     }
5098813da627SRichard Henderson #endif
5099813da627SRichard Henderson 
5100813da627SRichard Henderson     one_entry.symfile_addr = img;
5101813da627SRichard Henderson     one_entry.symfile_size = img_size;
5102813da627SRichard Henderson 
5103813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
5104813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
5105813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
5106813da627SRichard Henderson     __jit_debug_register_code();
5107813da627SRichard Henderson }
5108813da627SRichard Henderson #else
51095872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
51105872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
5111813da627SRichard Henderson 
5112755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
51132c90784aSRichard Henderson                                  const void *debug_frame,
51142c90784aSRichard Henderson                                  size_t debug_frame_size)
5115813da627SRichard Henderson {
5116813da627SRichard Henderson }
5117813da627SRichard Henderson 
5118755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size)
5119813da627SRichard Henderson {
5120813da627SRichard Henderson }
5121813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
5122db432672SRichard Henderson 
5123db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
5124db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
5125db432672SRichard Henderson {
5126db432672SRichard Henderson     g_assert_not_reached();
5127db432672SRichard Henderson }
5128db432672SRichard Henderson #endif
5129