xref: /qemu/tcg/tcg.c (revision efe86b21ead9b5d256ce90c378e31681c5e243a5)
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);
72f69d277eSRichard Henderson static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode);
73e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
746ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
752ba7fae2SRichard Henderson                         intptr_t value, intptr_t addend);
76c896fe29Sbellard 
77497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts.  */
78497a22ebSRichard Henderson typedef struct {
79497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
80497a22ebSRichard Henderson     uint32_t id;
81497a22ebSRichard Henderson     uint8_t version;
82497a22ebSRichard Henderson     char augmentation[1];
83497a22ebSRichard Henderson     uint8_t code_align;
84497a22ebSRichard Henderson     uint8_t data_align;
85497a22ebSRichard Henderson     uint8_t return_column;
86497a22ebSRichard Henderson } DebugFrameCIE;
87497a22ebSRichard Henderson 
88497a22ebSRichard Henderson typedef struct QEMU_PACKED {
89497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
90497a22ebSRichard Henderson     uint32_t cie_offset;
91edee2579SRichard Henderson     uintptr_t func_start;
92edee2579SRichard Henderson     uintptr_t func_len;
93497a22ebSRichard Henderson } DebugFrameFDEHeader;
94497a22ebSRichard Henderson 
952c90784aSRichard Henderson typedef struct QEMU_PACKED {
962c90784aSRichard Henderson     DebugFrameCIE cie;
972c90784aSRichard Henderson     DebugFrameFDEHeader fde;
982c90784aSRichard Henderson } DebugFrameHeader;
992c90784aSRichard Henderson 
100755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
1012c90784aSRichard Henderson                                  const void *debug_frame,
1022c90784aSRichard Henderson                                  size_t debug_frame_size)
103813da627SRichard Henderson     __attribute__((unused));
104813da627SRichard Henderson 
105139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */
106069ea736SRichard Henderson static const char *target_parse_constraint(TCGArgConstraint *ct,
107069ea736SRichard Henderson                                            const char *ct_str, TCGType type);
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 
352139c1837SPaolo Bonzini #include "tcg-target.c.inc"
353c896fe29Sbellard 
354be2cdc5eSEmilio G. Cota /* compare a pointer @ptr and a tb_tc @s */
355be2cdc5eSEmilio G. Cota static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s)
356be2cdc5eSEmilio G. Cota {
357be2cdc5eSEmilio G. Cota     if (ptr >= s->ptr + s->size) {
358be2cdc5eSEmilio G. Cota         return 1;
359be2cdc5eSEmilio G. Cota     } else if (ptr < s->ptr) {
360be2cdc5eSEmilio G. Cota         return -1;
361be2cdc5eSEmilio G. Cota     }
362be2cdc5eSEmilio G. Cota     return 0;
363be2cdc5eSEmilio G. Cota }
364be2cdc5eSEmilio G. Cota 
365be2cdc5eSEmilio G. Cota static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp)
366be2cdc5eSEmilio G. Cota {
367be2cdc5eSEmilio G. Cota     const struct tb_tc *a = ap;
368be2cdc5eSEmilio G. Cota     const struct tb_tc *b = bp;
369be2cdc5eSEmilio G. Cota 
370be2cdc5eSEmilio G. Cota     /*
371be2cdc5eSEmilio G. Cota      * When both sizes are set, we know this isn't a lookup.
372be2cdc5eSEmilio G. Cota      * This is the most likely case: every TB must be inserted; lookups
373be2cdc5eSEmilio G. Cota      * are a lot less frequent.
374be2cdc5eSEmilio G. Cota      */
375be2cdc5eSEmilio G. Cota     if (likely(a->size && b->size)) {
376be2cdc5eSEmilio G. Cota         if (a->ptr > b->ptr) {
377be2cdc5eSEmilio G. Cota             return 1;
378be2cdc5eSEmilio G. Cota         } else if (a->ptr < b->ptr) {
379be2cdc5eSEmilio G. Cota             return -1;
380be2cdc5eSEmilio G. Cota         }
381be2cdc5eSEmilio G. Cota         /* a->ptr == b->ptr should happen only on deletions */
382be2cdc5eSEmilio G. Cota         g_assert(a->size == b->size);
383be2cdc5eSEmilio G. Cota         return 0;
384be2cdc5eSEmilio G. Cota     }
385be2cdc5eSEmilio G. Cota     /*
386be2cdc5eSEmilio G. Cota      * All lookups have either .size field set to 0.
387be2cdc5eSEmilio G. Cota      * From the glib sources we see that @ap is always the lookup key. However
388be2cdc5eSEmilio G. Cota      * the docs provide no guarantee, so we just mark this case as likely.
389be2cdc5eSEmilio G. Cota      */
390be2cdc5eSEmilio G. Cota     if (likely(a->size == 0)) {
391be2cdc5eSEmilio G. Cota         return ptr_cmp_tb_tc(a->ptr, b);
392be2cdc5eSEmilio G. Cota     }
393be2cdc5eSEmilio G. Cota     return ptr_cmp_tb_tc(b->ptr, a);
394be2cdc5eSEmilio G. Cota }
395be2cdc5eSEmilio G. Cota 
396be2cdc5eSEmilio G. Cota static void tcg_region_trees_init(void)
397be2cdc5eSEmilio G. Cota {
398be2cdc5eSEmilio G. Cota     size_t i;
399be2cdc5eSEmilio G. Cota 
400be2cdc5eSEmilio G. Cota     tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize);
401be2cdc5eSEmilio G. Cota     region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size);
402be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
403be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
404be2cdc5eSEmilio G. Cota 
405be2cdc5eSEmilio G. Cota         qemu_mutex_init(&rt->lock);
406be2cdc5eSEmilio G. Cota         rt->tree = g_tree_new(tb_tc_cmp);
407be2cdc5eSEmilio G. Cota     }
408be2cdc5eSEmilio G. Cota }
409be2cdc5eSEmilio G. Cota 
410db0c51a3SRichard Henderson static struct tcg_region_tree *tc_ptr_to_region_tree(const void *cp)
411be2cdc5eSEmilio G. Cota {
412db0c51a3SRichard Henderson     void *p = tcg_splitwx_to_rw(cp);
413be2cdc5eSEmilio G. Cota     size_t region_idx;
414be2cdc5eSEmilio G. Cota 
415be2cdc5eSEmilio G. Cota     if (p < region.start_aligned) {
416be2cdc5eSEmilio G. Cota         region_idx = 0;
417be2cdc5eSEmilio G. Cota     } else {
418be2cdc5eSEmilio G. Cota         ptrdiff_t offset = p - region.start_aligned;
419be2cdc5eSEmilio G. Cota 
420be2cdc5eSEmilio G. Cota         if (offset > region.stride * (region.n - 1)) {
421be2cdc5eSEmilio G. Cota             region_idx = region.n - 1;
422be2cdc5eSEmilio G. Cota         } else {
423be2cdc5eSEmilio G. Cota             region_idx = offset / region.stride;
424be2cdc5eSEmilio G. Cota         }
425be2cdc5eSEmilio G. Cota     }
426be2cdc5eSEmilio G. Cota     return region_trees + region_idx * tree_size;
427be2cdc5eSEmilio G. Cota }
428be2cdc5eSEmilio G. Cota 
429be2cdc5eSEmilio G. Cota void tcg_tb_insert(TranslationBlock *tb)
430be2cdc5eSEmilio G. Cota {
431be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
432be2cdc5eSEmilio G. Cota 
433be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
434be2cdc5eSEmilio G. Cota     g_tree_insert(rt->tree, &tb->tc, tb);
435be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
436be2cdc5eSEmilio G. Cota }
437be2cdc5eSEmilio G. Cota 
438be2cdc5eSEmilio G. Cota void tcg_tb_remove(TranslationBlock *tb)
439be2cdc5eSEmilio G. Cota {
440be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
441be2cdc5eSEmilio G. Cota 
442be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
443be2cdc5eSEmilio G. Cota     g_tree_remove(rt->tree, &tb->tc);
444be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
445be2cdc5eSEmilio G. Cota }
446be2cdc5eSEmilio G. Cota 
447be2cdc5eSEmilio G. Cota /*
448be2cdc5eSEmilio G. Cota  * Find the TB 'tb' such that
449be2cdc5eSEmilio G. Cota  * tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size
450be2cdc5eSEmilio G. Cota  * Return NULL if not found.
451be2cdc5eSEmilio G. Cota  */
452be2cdc5eSEmilio G. Cota TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr)
453be2cdc5eSEmilio G. Cota {
454be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr);
455be2cdc5eSEmilio G. Cota     TranslationBlock *tb;
456be2cdc5eSEmilio G. Cota     struct tb_tc s = { .ptr = (void *)tc_ptr };
457be2cdc5eSEmilio G. Cota 
458be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
459be2cdc5eSEmilio G. Cota     tb = g_tree_lookup(rt->tree, &s);
460be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
461be2cdc5eSEmilio G. Cota     return tb;
462be2cdc5eSEmilio G. Cota }
463be2cdc5eSEmilio G. Cota 
464be2cdc5eSEmilio G. Cota static void tcg_region_tree_lock_all(void)
465be2cdc5eSEmilio G. Cota {
466be2cdc5eSEmilio G. Cota     size_t i;
467be2cdc5eSEmilio G. Cota 
468be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
469be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
470be2cdc5eSEmilio G. Cota 
471be2cdc5eSEmilio G. Cota         qemu_mutex_lock(&rt->lock);
472be2cdc5eSEmilio G. Cota     }
473be2cdc5eSEmilio G. Cota }
474be2cdc5eSEmilio G. Cota 
475be2cdc5eSEmilio G. Cota static void tcg_region_tree_unlock_all(void)
476be2cdc5eSEmilio G. Cota {
477be2cdc5eSEmilio G. Cota     size_t i;
478be2cdc5eSEmilio G. Cota 
479be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
480be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
481be2cdc5eSEmilio G. Cota 
482be2cdc5eSEmilio G. Cota         qemu_mutex_unlock(&rt->lock);
483be2cdc5eSEmilio G. Cota     }
484be2cdc5eSEmilio G. Cota }
485be2cdc5eSEmilio G. Cota 
486be2cdc5eSEmilio G. Cota void tcg_tb_foreach(GTraverseFunc func, gpointer user_data)
487be2cdc5eSEmilio G. Cota {
488be2cdc5eSEmilio G. Cota     size_t i;
489be2cdc5eSEmilio G. Cota 
490be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
491be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
492be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
493be2cdc5eSEmilio G. Cota 
494be2cdc5eSEmilio G. Cota         g_tree_foreach(rt->tree, func, user_data);
495be2cdc5eSEmilio G. Cota     }
496be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
497be2cdc5eSEmilio G. Cota }
498be2cdc5eSEmilio G. Cota 
499be2cdc5eSEmilio G. Cota size_t tcg_nb_tbs(void)
500be2cdc5eSEmilio G. Cota {
501be2cdc5eSEmilio G. Cota     size_t nb_tbs = 0;
502be2cdc5eSEmilio G. Cota     size_t i;
503be2cdc5eSEmilio G. Cota 
504be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
505be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
506be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
507be2cdc5eSEmilio G. Cota 
508be2cdc5eSEmilio G. Cota         nb_tbs += g_tree_nnodes(rt->tree);
509be2cdc5eSEmilio G. Cota     }
510be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
511be2cdc5eSEmilio G. Cota     return nb_tbs;
512be2cdc5eSEmilio G. Cota }
513be2cdc5eSEmilio G. Cota 
514938e897aSEmilio G. Cota static gboolean tcg_region_tree_traverse(gpointer k, gpointer v, gpointer data)
515938e897aSEmilio G. Cota {
516938e897aSEmilio G. Cota     TranslationBlock *tb = v;
517938e897aSEmilio G. Cota 
518938e897aSEmilio G. Cota     tb_destroy(tb);
519938e897aSEmilio G. Cota     return FALSE;
520938e897aSEmilio G. Cota }
521938e897aSEmilio G. Cota 
522be2cdc5eSEmilio G. Cota static void tcg_region_tree_reset_all(void)
523be2cdc5eSEmilio G. Cota {
524be2cdc5eSEmilio G. Cota     size_t i;
525be2cdc5eSEmilio G. Cota 
526be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
527be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
528be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
529be2cdc5eSEmilio G. Cota 
530938e897aSEmilio G. Cota         g_tree_foreach(rt->tree, tcg_region_tree_traverse, NULL);
531be2cdc5eSEmilio G. Cota         /* Increment the refcount first so that destroy acts as a reset */
532be2cdc5eSEmilio G. Cota         g_tree_ref(rt->tree);
533be2cdc5eSEmilio G. Cota         g_tree_destroy(rt->tree);
534be2cdc5eSEmilio G. Cota     }
535be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
536be2cdc5eSEmilio G. Cota }
537be2cdc5eSEmilio G. Cota 
538e8feb96fSEmilio G. Cota static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend)
539e8feb96fSEmilio G. Cota {
540e8feb96fSEmilio G. Cota     void *start, *end;
541e8feb96fSEmilio G. Cota 
542e8feb96fSEmilio G. Cota     start = region.start_aligned + curr_region * region.stride;
543e8feb96fSEmilio G. Cota     end = start + region.size;
544e8feb96fSEmilio G. Cota 
545e8feb96fSEmilio G. Cota     if (curr_region == 0) {
546e8feb96fSEmilio G. Cota         start = region.start;
547e8feb96fSEmilio G. Cota     }
548e8feb96fSEmilio G. Cota     if (curr_region == region.n - 1) {
549e8feb96fSEmilio G. Cota         end = region.end;
550e8feb96fSEmilio G. Cota     }
551e8feb96fSEmilio G. Cota 
552e8feb96fSEmilio G. Cota     *pstart = start;
553e8feb96fSEmilio G. Cota     *pend = end;
554e8feb96fSEmilio G. Cota }
555e8feb96fSEmilio G. Cota 
556e8feb96fSEmilio G. Cota static void tcg_region_assign(TCGContext *s, size_t curr_region)
557e8feb96fSEmilio G. Cota {
558e8feb96fSEmilio G. Cota     void *start, *end;
559e8feb96fSEmilio G. Cota 
560e8feb96fSEmilio G. Cota     tcg_region_bounds(curr_region, &start, &end);
561e8feb96fSEmilio G. Cota 
562e8feb96fSEmilio G. Cota     s->code_gen_buffer = start;
563e8feb96fSEmilio G. Cota     s->code_gen_ptr = start;
564e8feb96fSEmilio G. Cota     s->code_gen_buffer_size = end - start;
565e8feb96fSEmilio G. Cota     s->code_gen_highwater = end - TCG_HIGHWATER;
566e8feb96fSEmilio G. Cota }
567e8feb96fSEmilio G. Cota 
568e8feb96fSEmilio G. Cota static bool tcg_region_alloc__locked(TCGContext *s)
569e8feb96fSEmilio G. Cota {
570e8feb96fSEmilio G. Cota     if (region.current == region.n) {
571e8feb96fSEmilio G. Cota         return true;
572e8feb96fSEmilio G. Cota     }
573e8feb96fSEmilio G. Cota     tcg_region_assign(s, region.current);
574e8feb96fSEmilio G. Cota     region.current++;
575e8feb96fSEmilio G. Cota     return false;
576e8feb96fSEmilio G. Cota }
577e8feb96fSEmilio G. Cota 
578e8feb96fSEmilio G. Cota /*
579e8feb96fSEmilio G. Cota  * Request a new region once the one in use has filled up.
580e8feb96fSEmilio G. Cota  * Returns true on error.
581e8feb96fSEmilio G. Cota  */
582e8feb96fSEmilio G. Cota static bool tcg_region_alloc(TCGContext *s)
583e8feb96fSEmilio G. Cota {
584e8feb96fSEmilio G. Cota     bool err;
585e8feb96fSEmilio G. Cota     /* read the region size now; alloc__locked will overwrite it on success */
586e8feb96fSEmilio G. Cota     size_t size_full = s->code_gen_buffer_size;
587e8feb96fSEmilio G. Cota 
588e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
589e8feb96fSEmilio G. Cota     err = tcg_region_alloc__locked(s);
590e8feb96fSEmilio G. Cota     if (!err) {
591e8feb96fSEmilio G. Cota         region.agg_size_full += size_full - TCG_HIGHWATER;
592e8feb96fSEmilio G. Cota     }
593e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
594e8feb96fSEmilio G. Cota     return err;
595e8feb96fSEmilio G. Cota }
596e8feb96fSEmilio G. Cota 
597e8feb96fSEmilio G. Cota /*
598e8feb96fSEmilio G. Cota  * Perform a context's first region allocation.
599e8feb96fSEmilio G. Cota  * This function does _not_ increment region.agg_size_full.
600e8feb96fSEmilio G. Cota  */
601e8feb96fSEmilio G. Cota static inline bool tcg_region_initial_alloc__locked(TCGContext *s)
602e8feb96fSEmilio G. Cota {
603e8feb96fSEmilio G. Cota     return tcg_region_alloc__locked(s);
604e8feb96fSEmilio G. Cota }
605e8feb96fSEmilio G. Cota 
606e8feb96fSEmilio G. Cota /* Call from a safe-work context */
607e8feb96fSEmilio G. Cota void tcg_region_reset_all(void)
608e8feb96fSEmilio G. Cota {
609d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
610e8feb96fSEmilio G. Cota     unsigned int i;
611e8feb96fSEmilio G. Cota 
612e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
613e8feb96fSEmilio G. Cota     region.current = 0;
614e8feb96fSEmilio G. Cota     region.agg_size_full = 0;
615e8feb96fSEmilio G. Cota 
6163468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
617d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
6183468b59eSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(s);
619e8feb96fSEmilio G. Cota 
620e8feb96fSEmilio G. Cota         g_assert(!err);
621e8feb96fSEmilio G. Cota     }
622e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
623be2cdc5eSEmilio G. Cota 
624be2cdc5eSEmilio G. Cota     tcg_region_tree_reset_all();
625e8feb96fSEmilio G. Cota }
626e8feb96fSEmilio G. Cota 
6273468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
6283468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
6293468b59eSEmilio G. Cota {
6303468b59eSEmilio G. Cota     return 1;
6313468b59eSEmilio G. Cota }
6323468b59eSEmilio G. Cota #else
6333468b59eSEmilio G. Cota /*
6343468b59eSEmilio G. Cota  * It is likely that some vCPUs will translate more code than others, so we
6353468b59eSEmilio G. Cota  * first try to set more regions than max_cpus, with those regions being of
6363468b59eSEmilio G. Cota  * reasonable size. If that's not possible we make do by evenly dividing
6373468b59eSEmilio G. Cota  * the code_gen_buffer among the vCPUs.
6383468b59eSEmilio G. Cota  */
6393468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
6403468b59eSEmilio G. Cota {
6413468b59eSEmilio G. Cota     size_t i;
6423468b59eSEmilio G. Cota 
6433468b59eSEmilio G. Cota     /* Use a single region if all we have is one vCPU thread */
6445cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY)
6455cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
6465cc8767dSLike Xu     unsigned int max_cpus = ms->smp.max_cpus;
6475cc8767dSLike Xu #endif
6483468b59eSEmilio G. Cota     if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) {
6493468b59eSEmilio G. Cota         return 1;
6503468b59eSEmilio G. Cota     }
6513468b59eSEmilio G. Cota 
6523468b59eSEmilio G. Cota     /* Try to have more regions than max_cpus, with each region being >= 2 MB */
6533468b59eSEmilio G. Cota     for (i = 8; i > 0; i--) {
6543468b59eSEmilio G. Cota         size_t regions_per_thread = i;
6553468b59eSEmilio G. Cota         size_t region_size;
6563468b59eSEmilio G. Cota 
6573468b59eSEmilio G. Cota         region_size = tcg_init_ctx.code_gen_buffer_size;
6583468b59eSEmilio G. Cota         region_size /= max_cpus * regions_per_thread;
6593468b59eSEmilio G. Cota 
6603468b59eSEmilio G. Cota         if (region_size >= 2 * 1024u * 1024) {
6613468b59eSEmilio G. Cota             return max_cpus * regions_per_thread;
6623468b59eSEmilio G. Cota         }
6633468b59eSEmilio G. Cota     }
6643468b59eSEmilio G. Cota     /* If we can't, then just allocate one region per vCPU thread */
6653468b59eSEmilio G. Cota     return max_cpus;
6663468b59eSEmilio G. Cota }
6673468b59eSEmilio G. Cota #endif
6683468b59eSEmilio G. Cota 
669e8feb96fSEmilio G. Cota /*
670e8feb96fSEmilio G. Cota  * Initializes region partitioning.
671e8feb96fSEmilio G. Cota  *
672e8feb96fSEmilio G. Cota  * Called at init time from the parent thread (i.e. the one calling
673e8feb96fSEmilio G. Cota  * tcg_context_init), after the target's TCG globals have been set.
6743468b59eSEmilio G. Cota  *
6753468b59eSEmilio G. Cota  * Region partitioning works by splitting code_gen_buffer into separate regions,
6763468b59eSEmilio G. Cota  * and then assigning regions to TCG threads so that the threads can translate
6773468b59eSEmilio G. Cota  * code in parallel without synchronization.
6783468b59eSEmilio G. Cota  *
6793468b59eSEmilio G. Cota  * In softmmu the number of TCG threads is bounded by max_cpus, so we use at
6803468b59eSEmilio G. Cota  * least max_cpus regions in MTTCG. In !MTTCG we use a single region.
6813468b59eSEmilio G. Cota  * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...])
6823468b59eSEmilio G. Cota  * must have been parsed before calling this function, since it calls
6833468b59eSEmilio G. Cota  * qemu_tcg_mttcg_enabled().
6843468b59eSEmilio G. Cota  *
6853468b59eSEmilio G. Cota  * In user-mode we use a single region.  Having multiple regions in user-mode
6863468b59eSEmilio G. Cota  * is not supported, because the number of vCPU threads (recall that each thread
6873468b59eSEmilio G. Cota  * spawned by the guest corresponds to a vCPU thread) is only bounded by the
6883468b59eSEmilio G. Cota  * OS, and usually this number is huge (tens of thousands is not uncommon).
6893468b59eSEmilio G. Cota  * Thus, given this large bound on the number of vCPU threads and the fact
6903468b59eSEmilio G. Cota  * that code_gen_buffer is allocated at compile-time, we cannot guarantee
6913468b59eSEmilio G. Cota  * that the availability of at least one region per vCPU thread.
6923468b59eSEmilio G. Cota  *
6933468b59eSEmilio G. Cota  * However, this user-mode limitation is unlikely to be a significant problem
6943468b59eSEmilio G. Cota  * in practice. Multi-threaded guests share most if not all of their translated
6953468b59eSEmilio G. Cota  * code, which makes parallel code generation less appealing than in softmmu.
696e8feb96fSEmilio G. Cota  */
697e8feb96fSEmilio G. Cota void tcg_region_init(void)
698e8feb96fSEmilio G. Cota {
699e8feb96fSEmilio G. Cota     void *buf = tcg_init_ctx.code_gen_buffer;
700e8feb96fSEmilio G. Cota     void *aligned;
701e8feb96fSEmilio G. Cota     size_t size = tcg_init_ctx.code_gen_buffer_size;
702e8feb96fSEmilio G. Cota     size_t page_size = qemu_real_host_page_size;
703e8feb96fSEmilio G. Cota     size_t region_size;
704e8feb96fSEmilio G. Cota     size_t n_regions;
705e8feb96fSEmilio G. Cota     size_t i;
706db0c51a3SRichard Henderson     uintptr_t splitwx_diff;
707e8feb96fSEmilio G. Cota 
7083468b59eSEmilio G. Cota     n_regions = tcg_n_regions();
709e8feb96fSEmilio G. Cota 
710e8feb96fSEmilio G. Cota     /* The first region will be 'aligned - buf' bytes larger than the others */
711e8feb96fSEmilio G. Cota     aligned = QEMU_ALIGN_PTR_UP(buf, page_size);
712e8feb96fSEmilio G. Cota     g_assert(aligned < tcg_init_ctx.code_gen_buffer + size);
713e8feb96fSEmilio G. Cota     /*
714e8feb96fSEmilio G. Cota      * Make region_size a multiple of page_size, using aligned as the start.
715e8feb96fSEmilio G. Cota      * As a result of this we might end up with a few extra pages at the end of
716e8feb96fSEmilio G. Cota      * the buffer; we will assign those to the last region.
717e8feb96fSEmilio G. Cota      */
718e8feb96fSEmilio G. Cota     region_size = (size - (aligned - buf)) / n_regions;
719e8feb96fSEmilio G. Cota     region_size = QEMU_ALIGN_DOWN(region_size, page_size);
720e8feb96fSEmilio G. Cota 
721e8feb96fSEmilio G. Cota     /* A region must have at least 2 pages; one code, one guard */
722e8feb96fSEmilio G. Cota     g_assert(region_size >= 2 * page_size);
723e8feb96fSEmilio G. Cota 
724e8feb96fSEmilio G. Cota     /* init the region struct */
725e8feb96fSEmilio G. Cota     qemu_mutex_init(&region.lock);
726e8feb96fSEmilio G. Cota     region.n = n_regions;
727e8feb96fSEmilio G. Cota     region.size = region_size - page_size;
728e8feb96fSEmilio G. Cota     region.stride = region_size;
729e8feb96fSEmilio G. Cota     region.start = buf;
730e8feb96fSEmilio G. Cota     region.start_aligned = aligned;
731e8feb96fSEmilio G. Cota     /* page-align the end, since its last page will be a guard page */
732e8feb96fSEmilio G. Cota     region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size);
733e8feb96fSEmilio G. Cota     /* account for that last guard page */
734e8feb96fSEmilio G. Cota     region.end -= page_size;
735e8feb96fSEmilio G. Cota 
736e8feb96fSEmilio G. Cota     /* set guard pages */
737db0c51a3SRichard Henderson     splitwx_diff = tcg_splitwx_diff;
738e8feb96fSEmilio G. Cota     for (i = 0; i < region.n; i++) {
739e8feb96fSEmilio G. Cota         void *start, *end;
740e8feb96fSEmilio G. Cota         int rc;
741e8feb96fSEmilio G. Cota 
742e8feb96fSEmilio G. Cota         tcg_region_bounds(i, &start, &end);
743e8feb96fSEmilio G. Cota         rc = qemu_mprotect_none(end, page_size);
744e8feb96fSEmilio G. Cota         g_assert(!rc);
745db0c51a3SRichard Henderson         if (splitwx_diff) {
746db0c51a3SRichard Henderson             rc = qemu_mprotect_none(end + splitwx_diff, page_size);
747db0c51a3SRichard Henderson             g_assert(!rc);
748db0c51a3SRichard Henderson         }
749e8feb96fSEmilio G. Cota     }
750e8feb96fSEmilio G. Cota 
751be2cdc5eSEmilio G. Cota     tcg_region_trees_init();
752be2cdc5eSEmilio G. Cota 
7533468b59eSEmilio G. Cota     /* In user-mode we support only one ctx, so do the initial allocation now */
7543468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
755e8feb96fSEmilio G. Cota     {
756e8feb96fSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(tcg_ctx);
757e8feb96fSEmilio G. Cota 
758e8feb96fSEmilio G. Cota         g_assert(!err);
759e8feb96fSEmilio G. Cota     }
7603468b59eSEmilio G. Cota #endif
761e8feb96fSEmilio G. Cota }
762e8feb96fSEmilio G. Cota 
763db0c51a3SRichard Henderson #ifdef CONFIG_DEBUG_TCG
764db0c51a3SRichard Henderson const void *tcg_splitwx_to_rx(void *rw)
765db0c51a3SRichard Henderson {
766db0c51a3SRichard Henderson     /* Pass NULL pointers unchanged. */
767db0c51a3SRichard Henderson     if (rw) {
768db0c51a3SRichard Henderson         g_assert(in_code_gen_buffer(rw));
769db0c51a3SRichard Henderson         rw += tcg_splitwx_diff;
770db0c51a3SRichard Henderson     }
771db0c51a3SRichard Henderson     return rw;
772db0c51a3SRichard Henderson }
773db0c51a3SRichard Henderson 
774db0c51a3SRichard Henderson void *tcg_splitwx_to_rw(const void *rx)
775db0c51a3SRichard Henderson {
776db0c51a3SRichard Henderson     /* Pass NULL pointers unchanged. */
777db0c51a3SRichard Henderson     if (rx) {
778db0c51a3SRichard Henderson         rx -= tcg_splitwx_diff;
779db0c51a3SRichard Henderson         /* Assert that we end with a pointer in the rw region. */
780db0c51a3SRichard Henderson         g_assert(in_code_gen_buffer(rx));
781db0c51a3SRichard Henderson     }
782db0c51a3SRichard Henderson     return (void *)rx;
783db0c51a3SRichard Henderson }
784db0c51a3SRichard Henderson #endif /* CONFIG_DEBUG_TCG */
785db0c51a3SRichard Henderson 
78638b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s)
78738b47b19SEmilio G. Cota {
78838b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
78938b47b19SEmilio G. Cota     s->plugin_tb = g_new0(struct qemu_plugin_tb, 1);
79038b47b19SEmilio G. Cota     s->plugin_tb->insns =
79138b47b19SEmilio G. Cota         g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn);
79238b47b19SEmilio G. Cota #endif
79338b47b19SEmilio G. Cota }
79438b47b19SEmilio G. Cota 
795e8feb96fSEmilio G. Cota /*
7963468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
7973468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
7983468b59eSEmilio G. Cota  * before initiating translation.
7993468b59eSEmilio G. Cota  *
8003468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
8013468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
8023468b59eSEmilio G. Cota  *
8033468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
8043468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
8053468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
8063468b59eSEmilio G. Cota  *
8073468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
8083468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
8093468b59eSEmilio G. Cota  */
8103468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
8113468b59eSEmilio G. Cota void tcg_register_thread(void)
8123468b59eSEmilio G. Cota {
8133468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
8143468b59eSEmilio G. Cota }
8153468b59eSEmilio G. Cota #else
8163468b59eSEmilio G. Cota void tcg_register_thread(void)
8173468b59eSEmilio G. Cota {
8185cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
8193468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
8203468b59eSEmilio G. Cota     unsigned int i, n;
8213468b59eSEmilio G. Cota     bool err;
8223468b59eSEmilio G. Cota 
8233468b59eSEmilio G. Cota     *s = tcg_init_ctx;
8243468b59eSEmilio G. Cota 
8253468b59eSEmilio G. Cota     /* Relink mem_base.  */
8263468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
8273468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
8283468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
8293468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
8303468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
8313468b59eSEmilio G. Cota         }
8323468b59eSEmilio G. Cota     }
8333468b59eSEmilio G. Cota 
8343468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
835d73415a3SStefan Hajnoczi     n = qatomic_fetch_inc(&n_tcg_ctxs);
8365cc8767dSLike Xu     g_assert(n < ms->smp.max_cpus);
837d73415a3SStefan Hajnoczi     qatomic_set(&tcg_ctxs[n], s);
8383468b59eSEmilio G. Cota 
83938b47b19SEmilio G. Cota     if (n > 0) {
84038b47b19SEmilio G. Cota         alloc_tcg_plugin_context(s);
84138b47b19SEmilio G. Cota     }
84238b47b19SEmilio G. Cota 
8433468b59eSEmilio G. Cota     tcg_ctx = s;
8443468b59eSEmilio G. Cota     qemu_mutex_lock(&region.lock);
8453468b59eSEmilio G. Cota     err = tcg_region_initial_alloc__locked(tcg_ctx);
8463468b59eSEmilio G. Cota     g_assert(!err);
8473468b59eSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
8483468b59eSEmilio G. Cota }
8493468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
8503468b59eSEmilio G. Cota 
8513468b59eSEmilio G. Cota /*
852e8feb96fSEmilio G. Cota  * Returns the size (in bytes) of all translated code (i.e. from all regions)
853e8feb96fSEmilio G. Cota  * currently in the cache.
854e8feb96fSEmilio G. Cota  * See also: tcg_code_capacity()
855e8feb96fSEmilio G. Cota  * Do not confuse with tcg_current_code_size(); that one applies to a single
856e8feb96fSEmilio G. Cota  * TCG context.
857e8feb96fSEmilio G. Cota  */
858e8feb96fSEmilio G. Cota size_t tcg_code_size(void)
859e8feb96fSEmilio G. Cota {
860d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
861e8feb96fSEmilio G. Cota     unsigned int i;
862e8feb96fSEmilio G. Cota     size_t total;
863e8feb96fSEmilio G. Cota 
864e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
865e8feb96fSEmilio G. Cota     total = region.agg_size_full;
8663468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
867d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
868e8feb96fSEmilio G. Cota         size_t size;
869e8feb96fSEmilio G. Cota 
870d73415a3SStefan Hajnoczi         size = qatomic_read(&s->code_gen_ptr) - s->code_gen_buffer;
871e8feb96fSEmilio G. Cota         g_assert(size <= s->code_gen_buffer_size);
872e8feb96fSEmilio G. Cota         total += size;
873e8feb96fSEmilio G. Cota     }
874e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
875e8feb96fSEmilio G. Cota     return total;
876e8feb96fSEmilio G. Cota }
877e8feb96fSEmilio G. Cota 
878e8feb96fSEmilio G. Cota /*
879e8feb96fSEmilio G. Cota  * Returns the code capacity (in bytes) of the entire cache, i.e. including all
880e8feb96fSEmilio G. Cota  * regions.
881e8feb96fSEmilio G. Cota  * See also: tcg_code_size()
882e8feb96fSEmilio G. Cota  */
883e8feb96fSEmilio G. Cota size_t tcg_code_capacity(void)
884e8feb96fSEmilio G. Cota {
885e8feb96fSEmilio G. Cota     size_t guard_size, capacity;
886e8feb96fSEmilio G. Cota 
887e8feb96fSEmilio G. Cota     /* no need for synchronization; these variables are set at init time */
888e8feb96fSEmilio G. Cota     guard_size = region.stride - region.size;
889e8feb96fSEmilio G. Cota     capacity = region.end + guard_size - region.start;
890e8feb96fSEmilio G. Cota     capacity -= region.n * (guard_size + TCG_HIGHWATER);
891e8feb96fSEmilio G. Cota     return capacity;
892e8feb96fSEmilio G. Cota }
893e8feb96fSEmilio G. Cota 
894128ed227SEmilio G. Cota size_t tcg_tb_phys_invalidate_count(void)
895128ed227SEmilio G. Cota {
896d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
897128ed227SEmilio G. Cota     unsigned int i;
898128ed227SEmilio G. Cota     size_t total = 0;
899128ed227SEmilio G. Cota 
900128ed227SEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
901d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
902128ed227SEmilio G. Cota 
903d73415a3SStefan Hajnoczi         total += qatomic_read(&s->tb_phys_invalidate_count);
904128ed227SEmilio G. Cota     }
905128ed227SEmilio G. Cota     return total;
906128ed227SEmilio G. Cota }
907128ed227SEmilio G. Cota 
908c896fe29Sbellard /* pool based memory allocation */
909c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
910c896fe29Sbellard {
911c896fe29Sbellard     TCGPool *p;
912c896fe29Sbellard     int pool_size;
913c896fe29Sbellard 
914c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
915c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
9167267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
917c896fe29Sbellard         p->size = size;
9184055299eSKirill Batuzov         p->next = s->pool_first_large;
9194055299eSKirill Batuzov         s->pool_first_large = p;
9204055299eSKirill Batuzov         return p->data;
921c896fe29Sbellard     } else {
922c896fe29Sbellard         p = s->pool_current;
923c896fe29Sbellard         if (!p) {
924c896fe29Sbellard             p = s->pool_first;
925c896fe29Sbellard             if (!p)
926c896fe29Sbellard                 goto new_pool;
927c896fe29Sbellard         } else {
928c896fe29Sbellard             if (!p->next) {
929c896fe29Sbellard             new_pool:
930c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
9317267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
932c896fe29Sbellard                 p->size = pool_size;
933c896fe29Sbellard                 p->next = NULL;
934c896fe29Sbellard                 if (s->pool_current)
935c896fe29Sbellard                     s->pool_current->next = p;
936c896fe29Sbellard                 else
937c896fe29Sbellard                     s->pool_first = p;
938c896fe29Sbellard             } else {
939c896fe29Sbellard                 p = p->next;
940c896fe29Sbellard             }
941c896fe29Sbellard         }
942c896fe29Sbellard     }
943c896fe29Sbellard     s->pool_current = p;
944c896fe29Sbellard     s->pool_cur = p->data + size;
945c896fe29Sbellard     s->pool_end = p->data + p->size;
946c896fe29Sbellard     return p->data;
947c896fe29Sbellard }
948c896fe29Sbellard 
949c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
950c896fe29Sbellard {
9514055299eSKirill Batuzov     TCGPool *p, *t;
9524055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
9534055299eSKirill Batuzov         t = p->next;
9544055299eSKirill Batuzov         g_free(p);
9554055299eSKirill Batuzov     }
9564055299eSKirill Batuzov     s->pool_first_large = NULL;
957c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
958c896fe29Sbellard     s->pool_current = NULL;
959c896fe29Sbellard }
960c896fe29Sbellard 
961100b5e01SRichard Henderson typedef struct TCGHelperInfo {
962100b5e01SRichard Henderson     void *func;
963100b5e01SRichard Henderson     const char *name;
964afb49896SRichard Henderson     unsigned flags;
965afb49896SRichard Henderson     unsigned sizemask;
966100b5e01SRichard Henderson } TCGHelperInfo;
967100b5e01SRichard Henderson 
9682ef6175aSRichard Henderson #include "exec/helper-proto.h"
9692ef6175aSRichard Henderson 
970100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = {
9712ef6175aSRichard Henderson #include "exec/helper-tcg.h"
972100b5e01SRichard Henderson };
973619205fdSEmilio G. Cota static GHashTable *helper_table;
974100b5e01SRichard Henderson 
97591478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
976f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
9771c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
9781c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
97991478cefSRichard Henderson 
980c896fe29Sbellard void tcg_context_init(TCGContext *s)
981c896fe29Sbellard {
982100b5e01SRichard Henderson     int op, total_args, n, i;
983c896fe29Sbellard     TCGOpDef *def;
984c896fe29Sbellard     TCGArgConstraint *args_ct;
9851c2adb95SRichard Henderson     TCGTemp *ts;
986c896fe29Sbellard 
987c896fe29Sbellard     memset(s, 0, sizeof(*s));
988c896fe29Sbellard     s->nb_globals = 0;
989c896fe29Sbellard 
990c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
991c896fe29Sbellard        space */
992c896fe29Sbellard     total_args = 0;
993c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
994c896fe29Sbellard         def = &tcg_op_defs[op];
995c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
996c896fe29Sbellard         total_args += n;
997c896fe29Sbellard     }
998c896fe29Sbellard 
999bc2b17e6SRichard Henderson     args_ct = g_new0(TCGArgConstraint, total_args);
1000c896fe29Sbellard 
1001c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
1002c896fe29Sbellard         def = &tcg_op_defs[op];
1003c896fe29Sbellard         def->args_ct = args_ct;
1004c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
1005c896fe29Sbellard         args_ct += n;
1006c896fe29Sbellard     }
1007c896fe29Sbellard 
10085cd8f621SRichard Henderson     /* Register helpers.  */
100984fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
1010619205fdSEmilio G. Cota     helper_table = g_hash_table_new(NULL, NULL);
101184fd9dd3SRichard Henderson 
1012100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
101384fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
101472866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
1015100b5e01SRichard Henderson     }
10165cd8f621SRichard Henderson 
1017c896fe29Sbellard     tcg_target_init(s);
1018f69d277eSRichard Henderson     process_op_defs(s);
101991478cefSRichard Henderson 
102091478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
102191478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
102291478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
102391478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
102491478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
102591478cefSRichard Henderson             break;
102691478cefSRichard Henderson         }
102791478cefSRichard Henderson     }
102891478cefSRichard Henderson     for (i = 0; i < n; ++i) {
102991478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
103091478cefSRichard Henderson     }
103191478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
103291478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
103391478cefSRichard Henderson     }
1034b1311c4aSEmilio G. Cota 
103538b47b19SEmilio G. Cota     alloc_tcg_plugin_context(s);
103638b47b19SEmilio G. Cota 
1037b1311c4aSEmilio G. Cota     tcg_ctx = s;
10383468b59eSEmilio G. Cota     /*
10393468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
10403468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
10413468b59eSEmilio G. Cota      * reasoning behind this.
10423468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
10433468b59eSEmilio G. Cota      */
10443468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
1045df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
1046df2cce29SEmilio G. Cota     n_tcg_ctxs = 1;
10473468b59eSEmilio G. Cota #else
10485cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
10495cc8767dSLike Xu     unsigned int max_cpus = ms->smp.max_cpus;
10503468b59eSEmilio G. Cota     tcg_ctxs = g_new(TCGContext *, max_cpus);
10513468b59eSEmilio G. Cota #endif
10521c2adb95SRichard Henderson 
10531c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
10541c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
10551c2adb95SRichard Henderson     cpu_env = temp_tcgv_ptr(ts);
10569002ec79SRichard Henderson }
1057b03cce8eSbellard 
10586e3b2bfdSEmilio G. Cota /*
10596e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
10606e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
10616e3b2bfdSEmilio G. Cota  */
10626e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
10636e3b2bfdSEmilio G. Cota {
10646e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
10656e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
10666e3b2bfdSEmilio G. Cota     void *next;
10676e3b2bfdSEmilio G. Cota 
1068e8feb96fSEmilio G. Cota  retry:
10696e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
10706e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
10716e3b2bfdSEmilio G. Cota 
10726e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
1073e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
10746e3b2bfdSEmilio G. Cota             return NULL;
10756e3b2bfdSEmilio G. Cota         }
1076e8feb96fSEmilio G. Cota         goto retry;
1077e8feb96fSEmilio G. Cota     }
1078d73415a3SStefan Hajnoczi     qatomic_set(&s->code_gen_ptr, next);
107957a26946SRichard Henderson     s->data_gen_ptr = NULL;
10806e3b2bfdSEmilio G. Cota     return tb;
10816e3b2bfdSEmilio G. Cota }
10826e3b2bfdSEmilio G. Cota 
10839002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
10849002ec79SRichard Henderson {
10858163b749SRichard Henderson     size_t prologue_size, total_size;
10868163b749SRichard Henderson     void *buf0, *buf1;
10878163b749SRichard Henderson 
10888163b749SRichard Henderson     /* Put the prologue at the beginning of code_gen_buffer.  */
10898163b749SRichard Henderson     buf0 = s->code_gen_buffer;
10905b38ee31SRichard Henderson     total_size = s->code_gen_buffer_size;
10918163b749SRichard Henderson     s->code_ptr = buf0;
10928163b749SRichard Henderson     s->code_buf = buf0;
10935b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
1094b91ccb31SRichard Henderson 
1095db0c51a3SRichard Henderson     /*
1096db0c51a3SRichard Henderson      * The region trees are not yet configured, but tcg_splitwx_to_rx
1097db0c51a3SRichard Henderson      * needs the bounds for an assert.
1098db0c51a3SRichard Henderson      */
1099db0c51a3SRichard Henderson     region.start = buf0;
1100db0c51a3SRichard Henderson     region.end = buf0 + total_size;
1101db0c51a3SRichard Henderson 
1102b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1103db0c51a3SRichard Henderson     tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(buf0);
1104b91ccb31SRichard Henderson #endif
11058163b749SRichard Henderson 
11065b38ee31SRichard Henderson     /* Compute a high-water mark, at which we voluntarily flush the buffer
11075b38ee31SRichard Henderson        and start over.  The size here is arbitrary, significantly larger
11085b38ee31SRichard Henderson        than we expect the code generation for any one opcode to require.  */
11095b38ee31SRichard Henderson     s->code_gen_highwater = s->code_gen_buffer + (total_size - TCG_HIGHWATER);
11105b38ee31SRichard Henderson 
11115b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
11125b38ee31SRichard Henderson     s->pool_labels = NULL;
11135b38ee31SRichard Henderson #endif
11145b38ee31SRichard Henderson 
11158163b749SRichard Henderson     /* Generate the prologue.  */
1116b03cce8eSbellard     tcg_target_qemu_prologue(s);
11175b38ee31SRichard Henderson 
11185b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
11195b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
11205b38ee31SRichard Henderson     {
11211768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
11221768987bSRichard Henderson         tcg_debug_assert(result == 0);
11235b38ee31SRichard Henderson     }
11245b38ee31SRichard Henderson #endif
11255b38ee31SRichard Henderson 
11268163b749SRichard Henderson     buf1 = s->code_ptr;
1127df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1128db0c51a3SRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(buf0), (uintptr_t)buf0,
11291da8de39SRichard Henderson                         tcg_ptr_byte_diff(buf1, buf0));
1130df5d2b16SRichard Henderson #endif
11318163b749SRichard Henderson 
11328163b749SRichard Henderson     /* Deduct the prologue from the buffer.  */
11338163b749SRichard Henderson     prologue_size = tcg_current_code_size(s);
11348163b749SRichard Henderson     s->code_gen_ptr = buf1;
11358163b749SRichard Henderson     s->code_gen_buffer = buf1;
11368163b749SRichard Henderson     s->code_buf = buf1;
11375b38ee31SRichard Henderson     total_size -= prologue_size;
11388163b749SRichard Henderson     s->code_gen_buffer_size = total_size;
11398163b749SRichard Henderson 
1140755bf9e5SRichard Henderson     tcg_register_jit(tcg_splitwx_to_rx(s->code_gen_buffer), total_size);
1141d6b64b2bSRichard Henderson 
1142d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
1143d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
1144fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
11458163b749SRichard Henderson         qemu_log("PROLOGUE: [size=%zu]\n", prologue_size);
11465b38ee31SRichard Henderson         if (s->data_gen_ptr) {
11475b38ee31SRichard Henderson             size_t code_size = s->data_gen_ptr - buf0;
11485b38ee31SRichard Henderson             size_t data_size = prologue_size - code_size;
11495b38ee31SRichard Henderson             size_t i;
11505b38ee31SRichard Henderson 
11514c389f6eSRichard Henderson             log_disas(buf0, code_size);
11525b38ee31SRichard Henderson 
11535b38ee31SRichard Henderson             for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
11545b38ee31SRichard Henderson                 if (sizeof(tcg_target_ulong) == 8) {
11555b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
11565b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
11575b38ee31SRichard Henderson                              *(uint64_t *)(s->data_gen_ptr + i));
11585b38ee31SRichard Henderson                 } else {
11595b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .long  0x%08x\n",
11605b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
11615b38ee31SRichard Henderson                              *(uint32_t *)(s->data_gen_ptr + i));
11625b38ee31SRichard Henderson                 }
11635b38ee31SRichard Henderson             }
11645b38ee31SRichard Henderson         } else {
11654c389f6eSRichard Henderson             log_disas(buf0, prologue_size);
11665b38ee31SRichard Henderson         }
1167d6b64b2bSRichard Henderson         qemu_log("\n");
1168d6b64b2bSRichard Henderson         qemu_log_flush();
1169fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
1170d6b64b2bSRichard Henderson     }
1171d6b64b2bSRichard Henderson #endif
1172cedbcb01SEmilio G. Cota 
1173cedbcb01SEmilio G. Cota     /* Assert that goto_ptr is implemented completely.  */
1174cedbcb01SEmilio G. Cota     if (TCG_TARGET_HAS_goto_ptr) {
11758b5c2b62SRichard Henderson         tcg_debug_assert(tcg_code_gen_epilogue != NULL);
1176cedbcb01SEmilio G. Cota     }
1177c896fe29Sbellard }
1178c896fe29Sbellard 
1179c896fe29Sbellard void tcg_func_start(TCGContext *s)
1180c896fe29Sbellard {
1181c896fe29Sbellard     tcg_pool_reset(s);
1182c896fe29Sbellard     s->nb_temps = s->nb_globals;
11830ec9eabcSRichard Henderson 
11840ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
11850ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
11860ec9eabcSRichard Henderson 
1187c0522136SRichard Henderson     /* No constant temps have been previously allocated. */
1188c0522136SRichard Henderson     for (int i = 0; i < TCG_TYPE_COUNT; ++i) {
1189c0522136SRichard Henderson         if (s->const_table[i]) {
1190c0522136SRichard Henderson             g_hash_table_remove_all(s->const_table[i]);
1191c0522136SRichard Henderson         }
1192c0522136SRichard Henderson     }
1193c0522136SRichard Henderson 
1194abebf925SRichard Henderson     s->nb_ops = 0;
1195c896fe29Sbellard     s->nb_labels = 0;
1196c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1197c896fe29Sbellard 
11980a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
11990a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
12000a209d4bSRichard Henderson #endif
12010a209d4bSRichard Henderson 
120215fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
120315fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
1204bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
1205c896fe29Sbellard }
1206c896fe29Sbellard 
12077ca4b752SRichard Henderson static inline TCGTemp *tcg_temp_alloc(TCGContext *s)
12087ca4b752SRichard Henderson {
12097ca4b752SRichard Henderson     int n = s->nb_temps++;
12107ca4b752SRichard Henderson     tcg_debug_assert(n < TCG_MAX_TEMPS);
12117ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
12127ca4b752SRichard Henderson }
12137ca4b752SRichard Henderson 
12147ca4b752SRichard Henderson static inline TCGTemp *tcg_global_alloc(TCGContext *s)
12157ca4b752SRichard Henderson {
1216fa477d25SRichard Henderson     TCGTemp *ts;
1217fa477d25SRichard Henderson 
12187ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
12197ca4b752SRichard Henderson     s->nb_globals++;
1220fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1221ee17db83SRichard Henderson     ts->kind = TEMP_GLOBAL;
1222fa477d25SRichard Henderson 
1223fa477d25SRichard Henderson     return ts;
1224c896fe29Sbellard }
1225c896fe29Sbellard 
1226085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1227b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1228c896fe29Sbellard {
1229c896fe29Sbellard     TCGTemp *ts;
1230c896fe29Sbellard 
1231b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
1232c896fe29Sbellard         tcg_abort();
1233b3a62939SRichard Henderson     }
12347ca4b752SRichard Henderson 
12357ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1236c896fe29Sbellard     ts->base_type = type;
1237c896fe29Sbellard     ts->type = type;
1238ee17db83SRichard Henderson     ts->kind = TEMP_FIXED;
1239c896fe29Sbellard     ts->reg = reg;
1240c896fe29Sbellard     ts->name = name;
1241c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
12427ca4b752SRichard Henderson 
1243085272b3SRichard Henderson     return ts;
1244a7812ae4Spbrook }
1245a7812ae4Spbrook 
1246b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1247a7812ae4Spbrook {
1248b3a62939SRichard Henderson     s->frame_start = start;
1249b3a62939SRichard Henderson     s->frame_end = start + size;
1250085272b3SRichard Henderson     s->frame_temp
1251085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1252b3a62939SRichard Henderson }
1253a7812ae4Spbrook 
1254085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
1255e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
1256c896fe29Sbellard {
1257b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1258dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
12597ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1260b3915dbbSRichard Henderson     int indirect_reg = 0, bigendian = 0;
12617ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
12627ca4b752SRichard Henderson     bigendian = 1;
12637ca4b752SRichard Henderson #endif
1264c896fe29Sbellard 
1265c0522136SRichard Henderson     switch (base_ts->kind) {
1266c0522136SRichard Henderson     case TEMP_FIXED:
1267c0522136SRichard Henderson         break;
1268c0522136SRichard Henderson     case TEMP_GLOBAL:
12695a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
12705a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1271b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
12725a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
12735a18407fSRichard Henderson                             ? 2 : 1);
12745a18407fSRichard Henderson         indirect_reg = 1;
1275c0522136SRichard Henderson         break;
1276c0522136SRichard Henderson     default:
1277c0522136SRichard Henderson         g_assert_not_reached();
1278b3915dbbSRichard Henderson     }
1279b3915dbbSRichard Henderson 
12807ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
12817ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1282c896fe29Sbellard         char buf[64];
12837ca4b752SRichard Henderson 
12847ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1285c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1286b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1287c896fe29Sbellard         ts->mem_allocated = 1;
1288b3a62939SRichard Henderson         ts->mem_base = base_ts;
12897ca4b752SRichard Henderson         ts->mem_offset = offset + bigendian * 4;
1290c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1291c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1292c896fe29Sbellard         ts->name = strdup(buf);
1293c896fe29Sbellard 
12947ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
12957ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
12967ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1297b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
12987ca4b752SRichard Henderson         ts2->mem_allocated = 1;
12997ca4b752SRichard Henderson         ts2->mem_base = base_ts;
13007ca4b752SRichard Henderson         ts2->mem_offset = offset + (1 - bigendian) * 4;
1301c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1302c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1303120c1084SRichard Henderson         ts2->name = strdup(buf);
13047ca4b752SRichard Henderson     } else {
1305c896fe29Sbellard         ts->base_type = type;
1306c896fe29Sbellard         ts->type = type;
1307b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1308c896fe29Sbellard         ts->mem_allocated = 1;
1309b3a62939SRichard Henderson         ts->mem_base = base_ts;
1310c896fe29Sbellard         ts->mem_offset = offset;
1311c896fe29Sbellard         ts->name = name;
1312c896fe29Sbellard     }
1313085272b3SRichard Henderson     return ts;
1314c896fe29Sbellard }
1315c896fe29Sbellard 
13165bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local)
1317c896fe29Sbellard {
1318b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1319ee17db83SRichard Henderson     TCGTempKind kind = temp_local ? TEMP_LOCAL : TEMP_NORMAL;
1320c896fe29Sbellard     TCGTemp *ts;
1321641d5fbeSbellard     int idx, k;
1322c896fe29Sbellard 
13230ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
13240ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
13250ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
13260ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
13270ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
13280ec9eabcSRichard Henderson 
1329e8996ee0Sbellard         ts = &s->temps[idx];
1330e8996ee0Sbellard         ts->temp_allocated = 1;
13317ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
1332ee17db83SRichard Henderson         tcg_debug_assert(ts->kind == kind);
1333e8996ee0Sbellard     } else {
13347ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
13357ca4b752SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
13367ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
13377ca4b752SRichard Henderson 
1338c896fe29Sbellard             ts->base_type = type;
1339c896fe29Sbellard             ts->type = TCG_TYPE_I32;
1340e8996ee0Sbellard             ts->temp_allocated = 1;
1341ee17db83SRichard Henderson             ts->kind = kind;
13427ca4b752SRichard Henderson 
13437ca4b752SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
13447ca4b752SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
13457ca4b752SRichard Henderson             ts2->type = TCG_TYPE_I32;
13467ca4b752SRichard Henderson             ts2->temp_allocated = 1;
1347ee17db83SRichard Henderson             ts2->kind = kind;
13487ca4b752SRichard Henderson         } else {
1349c896fe29Sbellard             ts->base_type = type;
1350c896fe29Sbellard             ts->type = type;
1351e8996ee0Sbellard             ts->temp_allocated = 1;
1352ee17db83SRichard Henderson             ts->kind = kind;
1353c896fe29Sbellard         }
1354e8996ee0Sbellard     }
135527bfd83cSPeter Maydell 
135627bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
135727bfd83cSPeter Maydell     s->temps_in_use++;
135827bfd83cSPeter Maydell #endif
1359085272b3SRichard Henderson     return ts;
1360c896fe29Sbellard }
1361c896fe29Sbellard 
1362d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1363d2fd745fSRichard Henderson {
1364d2fd745fSRichard Henderson     TCGTemp *t;
1365d2fd745fSRichard Henderson 
1366d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1367d2fd745fSRichard Henderson     switch (type) {
1368d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1369d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1370d2fd745fSRichard Henderson         break;
1371d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1372d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1373d2fd745fSRichard Henderson         break;
1374d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1375d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1376d2fd745fSRichard Henderson         break;
1377d2fd745fSRichard Henderson     default:
1378d2fd745fSRichard Henderson         g_assert_not_reached();
1379d2fd745fSRichard Henderson     }
1380d2fd745fSRichard Henderson #endif
1381d2fd745fSRichard Henderson 
1382d2fd745fSRichard Henderson     t = tcg_temp_new_internal(type, 0);
1383d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1384d2fd745fSRichard Henderson }
1385d2fd745fSRichard Henderson 
1386d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1387d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1388d2fd745fSRichard Henderson {
1389d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1390d2fd745fSRichard Henderson 
1391d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1392d2fd745fSRichard Henderson 
1393d2fd745fSRichard Henderson     t = tcg_temp_new_internal(t->base_type, 0);
1394d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1395d2fd745fSRichard Henderson }
1396d2fd745fSRichard Henderson 
13975bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1398c896fe29Sbellard {
1399b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1400085272b3SRichard Henderson     int k, idx;
1401c896fe29Sbellard 
1402c0522136SRichard Henderson     /* In order to simplify users of tcg_constant_*, silently ignore free. */
1403c0522136SRichard Henderson     if (ts->kind == TEMP_CONST) {
1404c0522136SRichard Henderson         return;
1405c0522136SRichard Henderson     }
1406c0522136SRichard Henderson 
140727bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
140827bfd83cSPeter Maydell     s->temps_in_use--;
140927bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
141027bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
141127bfd83cSPeter Maydell     }
141227bfd83cSPeter Maydell #endif
141327bfd83cSPeter Maydell 
1414ee17db83SRichard Henderson     tcg_debug_assert(ts->kind < TEMP_GLOBAL);
1415eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
1416e8996ee0Sbellard     ts->temp_allocated = 0;
14170ec9eabcSRichard Henderson 
1418085272b3SRichard Henderson     idx = temp_idx(ts);
1419ee17db83SRichard Henderson     k = ts->base_type + (ts->kind == TEMP_NORMAL ? 0 : TCG_TYPE_COUNT);
14200ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
1421e8996ee0Sbellard }
1422e8996ee0Sbellard 
1423c0522136SRichard Henderson TCGTemp *tcg_constant_internal(TCGType type, int64_t val)
1424c0522136SRichard Henderson {
1425c0522136SRichard Henderson     TCGContext *s = tcg_ctx;
1426c0522136SRichard Henderson     GHashTable *h = s->const_table[type];
1427c0522136SRichard Henderson     TCGTemp *ts;
1428c0522136SRichard Henderson 
1429c0522136SRichard Henderson     if (h == NULL) {
1430c0522136SRichard Henderson         h = g_hash_table_new(g_int64_hash, g_int64_equal);
1431c0522136SRichard Henderson         s->const_table[type] = h;
1432c0522136SRichard Henderson     }
1433c0522136SRichard Henderson 
1434c0522136SRichard Henderson     ts = g_hash_table_lookup(h, &val);
1435c0522136SRichard Henderson     if (ts == NULL) {
1436c0522136SRichard Henderson         ts = tcg_temp_alloc(s);
1437c0522136SRichard Henderson 
1438c0522136SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
1439c0522136SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
1440c0522136SRichard Henderson 
1441c0522136SRichard Henderson             ts->base_type = TCG_TYPE_I64;
1442c0522136SRichard Henderson             ts->type = TCG_TYPE_I32;
1443c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1444c0522136SRichard Henderson             ts->temp_allocated = 1;
1445c0522136SRichard Henderson             /*
1446c0522136SRichard Henderson              * Retain the full value of the 64-bit constant in the low
1447c0522136SRichard Henderson              * part, so that the hash table works.  Actual uses will
1448c0522136SRichard Henderson              * truncate the value to the low part.
1449c0522136SRichard Henderson              */
1450c0522136SRichard Henderson             ts->val = val;
1451c0522136SRichard Henderson 
1452c0522136SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
1453c0522136SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
1454c0522136SRichard Henderson             ts2->type = TCG_TYPE_I32;
1455c0522136SRichard Henderson             ts2->kind = TEMP_CONST;
1456c0522136SRichard Henderson             ts2->temp_allocated = 1;
1457c0522136SRichard Henderson             ts2->val = val >> 32;
1458c0522136SRichard Henderson         } else {
1459c0522136SRichard Henderson             ts->base_type = type;
1460c0522136SRichard Henderson             ts->type = type;
1461c0522136SRichard Henderson             ts->kind = TEMP_CONST;
1462c0522136SRichard Henderson             ts->temp_allocated = 1;
1463c0522136SRichard Henderson             ts->val = val;
1464c0522136SRichard Henderson         }
1465c0522136SRichard Henderson         g_hash_table_insert(h, &ts->val, ts);
1466c0522136SRichard Henderson     }
1467c0522136SRichard Henderson 
1468c0522136SRichard Henderson     return ts;
1469c0522136SRichard Henderson }
1470c0522136SRichard Henderson 
1471c0522136SRichard Henderson TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val)
1472c0522136SRichard Henderson {
1473c0522136SRichard Henderson     val = dup_const(vece, val);
1474c0522136SRichard Henderson     return temp_tcgv_vec(tcg_constant_internal(type, val));
1475c0522136SRichard Henderson }
1476c0522136SRichard Henderson 
147788d4005bSRichard Henderson TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val)
147888d4005bSRichard Henderson {
147988d4005bSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
148088d4005bSRichard Henderson 
148188d4005bSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
148288d4005bSRichard Henderson     return tcg_constant_vec(t->base_type, vece, val);
148388d4005bSRichard Henderson }
148488d4005bSRichard Henderson 
1485a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
1486a7812ae4Spbrook {
1487a7812ae4Spbrook     TCGv_i32 t0;
1488a7812ae4Spbrook     t0 = tcg_temp_new_i32();
1489e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
1490e8996ee0Sbellard     return t0;
1491c896fe29Sbellard }
1492c896fe29Sbellard 
1493a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
1494c896fe29Sbellard {
1495a7812ae4Spbrook     TCGv_i64 t0;
1496a7812ae4Spbrook     t0 = tcg_temp_new_i64();
1497e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
1498e8996ee0Sbellard     return t0;
1499c896fe29Sbellard }
1500c896fe29Sbellard 
1501a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
1502bdffd4a9Saurel32 {
1503a7812ae4Spbrook     TCGv_i32 t0;
1504a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
1505bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
1506bdffd4a9Saurel32     return t0;
1507bdffd4a9Saurel32 }
1508bdffd4a9Saurel32 
1509a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
1510bdffd4a9Saurel32 {
1511a7812ae4Spbrook     TCGv_i64 t0;
1512a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
1513bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
1514bdffd4a9Saurel32     return t0;
1515bdffd4a9Saurel32 }
1516bdffd4a9Saurel32 
151727bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
151827bfd83cSPeter Maydell void tcg_clear_temp_count(void)
151927bfd83cSPeter Maydell {
1520b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
152127bfd83cSPeter Maydell     s->temps_in_use = 0;
152227bfd83cSPeter Maydell }
152327bfd83cSPeter Maydell 
152427bfd83cSPeter Maydell int tcg_check_temp_count(void)
152527bfd83cSPeter Maydell {
1526b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
152727bfd83cSPeter Maydell     if (s->temps_in_use) {
152827bfd83cSPeter Maydell         /* Clear the count so that we don't give another
152927bfd83cSPeter Maydell          * warning immediately next time around.
153027bfd83cSPeter Maydell          */
153127bfd83cSPeter Maydell         s->temps_in_use = 0;
153227bfd83cSPeter Maydell         return 1;
153327bfd83cSPeter Maydell     }
153427bfd83cSPeter Maydell     return 0;
153527bfd83cSPeter Maydell }
153627bfd83cSPeter Maydell #endif
153727bfd83cSPeter Maydell 
1538be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1539be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1540be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1541be0f34b5SRichard Henderson {
1542d2fd745fSRichard Henderson     const bool have_vec
1543d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1544d2fd745fSRichard Henderson 
1545be0f34b5SRichard Henderson     switch (op) {
1546be0f34b5SRichard Henderson     case INDEX_op_discard:
1547be0f34b5SRichard Henderson     case INDEX_op_set_label:
1548be0f34b5SRichard Henderson     case INDEX_op_call:
1549be0f34b5SRichard Henderson     case INDEX_op_br:
1550be0f34b5SRichard Henderson     case INDEX_op_mb:
1551be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1552be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1553be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1554be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i32:
1555be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i32:
1556be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i64:
1557be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i64:
1558be0f34b5SRichard Henderson         return true;
1559be0f34b5SRichard Henderson 
156007ce0b05SRichard Henderson     case INDEX_op_qemu_st8_i32:
156107ce0b05SRichard Henderson         return TCG_TARGET_HAS_qemu_st8_i32;
156207ce0b05SRichard Henderson 
1563be0f34b5SRichard Henderson     case INDEX_op_goto_ptr:
1564be0f34b5SRichard Henderson         return TCG_TARGET_HAS_goto_ptr;
1565be0f34b5SRichard Henderson 
1566be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1567be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1568be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1569be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1570be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1571be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1572be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1573be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1574be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1575be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1576be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1577be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1578be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1579be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1580be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1581be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1582be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1583be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1584be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1585be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1586be0f34b5SRichard Henderson         return true;
1587be0f34b5SRichard Henderson 
1588be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1589be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1590be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1591be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1592be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1593be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1594be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1595be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1596be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1597be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1598be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1599be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1600be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1601be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1602be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1603be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1604be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1605be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1606be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1607be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1608fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
1609fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
1610be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1611be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1612be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1613be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1614be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1615be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1616be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1617be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1618be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1619be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1620be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1621be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1622be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1623be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1624be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1625be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1626be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1627be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1628be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1629be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1630be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1631be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1632be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1633be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1634be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1635be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1636be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1637be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1638be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1639be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1640be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1641be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1642be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1643be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1644be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1645be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1646be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1647be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1648be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1649be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1650be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1651be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1652be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1653be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1654be0f34b5SRichard Henderson 
1655be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1656be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1657be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1658be0f34b5SRichard Henderson 
1659be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1660be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1661be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1662be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1663be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1664be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1665be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1666be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1667be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1668be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1669be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1670be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1671be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1672be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1673be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1674be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1675be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1676be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1677be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1678be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1679be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1680be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1681be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1682be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1683be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1684be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1685be0f34b5SRichard Henderson 
1686be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1687be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1688be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1689be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1690be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1691be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1692be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1693be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1694be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1695be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
1696be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
1697be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
1698be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
1699be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
1700be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
1701be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
1702be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
1703be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
1704be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
1705be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
1706fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
1707fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
1708be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
1709be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrl_i64_i32;
1710be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
1711be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrh_i64_i32;
1712be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
1713be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
1714be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
1715be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
1716be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
1717be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
1718be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
1719be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
1720be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
1721be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
1722be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
1723be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
1724be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
1725be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
1726be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
1727be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
1728be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
1729be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
1730be0f34b5SRichard Henderson     case INDEX_op_not_i64:
1731be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
1732be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
1733be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
1734be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
1735be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
1736be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
1737be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
1738be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
1739be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
1740be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
1741be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
1742be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
1743be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
1744be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
1745be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
1746be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
1747be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
1748be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
1749be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
1750be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
1751be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
1752be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
1753be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
1754be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
1755be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
1756be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
1757be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
1758be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
1759be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
1760be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
1761be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
1762be0f34b5SRichard Henderson 
1763d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
1764d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
176537ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
1766d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
1767d2fd745fSRichard Henderson     case INDEX_op_st_vec:
1768d2fd745fSRichard Henderson     case INDEX_op_add_vec:
1769d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
1770d2fd745fSRichard Henderson     case INDEX_op_and_vec:
1771d2fd745fSRichard Henderson     case INDEX_op_or_vec:
1772d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
1773212be173SRichard Henderson     case INDEX_op_cmp_vec:
1774d2fd745fSRichard Henderson         return have_vec;
1775d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
1776d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
1777d2fd745fSRichard Henderson     case INDEX_op_not_vec:
1778d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
1779d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
1780d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
1781bcefc902SRichard Henderson     case INDEX_op_abs_vec:
1782bcefc902SRichard Henderson         return have_vec && TCG_TARGET_HAS_abs_vec;
1783d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
1784d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
1785d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
1786d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
17873774030aSRichard Henderson     case INDEX_op_mul_vec:
17883774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
1789d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
1790d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
1791d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
1792d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
1793d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
1794d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
1795d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
1796d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
1797d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
1798d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
1799d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
1800d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
1801b0f7e744SRichard Henderson     case INDEX_op_rotli_vec:
1802b0f7e744SRichard Henderson         return have_vec && TCG_TARGET_HAS_roti_vec;
180323850a74SRichard Henderson     case INDEX_op_rotls_vec:
180423850a74SRichard Henderson         return have_vec && TCG_TARGET_HAS_rots_vec;
18055d0ceda9SRichard Henderson     case INDEX_op_rotlv_vec:
18065d0ceda9SRichard Henderson     case INDEX_op_rotrv_vec:
18075d0ceda9SRichard Henderson         return have_vec && TCG_TARGET_HAS_rotv_vec;
18088afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
18098afaf050SRichard Henderson     case INDEX_op_usadd_vec:
18108afaf050SRichard Henderson     case INDEX_op_sssub_vec:
18118afaf050SRichard Henderson     case INDEX_op_ussub_vec:
18128afaf050SRichard Henderson         return have_vec && TCG_TARGET_HAS_sat_vec;
1813dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
1814dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
1815dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
1816dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
1817dd0a0fcdSRichard Henderson         return have_vec && TCG_TARGET_HAS_minmax_vec;
181838dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
181938dc1294SRichard Henderson         return have_vec && TCG_TARGET_HAS_bitsel_vec;
1820f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
1821f75da298SRichard Henderson         return have_vec && TCG_TARGET_HAS_cmpsel_vec;
1822d2fd745fSRichard Henderson 
1823db432672SRichard Henderson     default:
1824db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
1825db432672SRichard Henderson         return true;
1826be0f34b5SRichard Henderson     }
1827be0f34b5SRichard Henderson }
1828be0f34b5SRichard Henderson 
182939cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment
183039cf05d3Sbellard    and endian swap. Maybe it would be better to do the alignment
183139cf05d3Sbellard    and endian swap in tcg_reg_alloc_call(). */
1832ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
1833c896fe29Sbellard {
183475e8b9b7SRichard Henderson     int i, real_args, nb_rets, pi;
1835bbb8a1b4SRichard Henderson     unsigned sizemask, flags;
1836afb49896SRichard Henderson     TCGHelperInfo *info;
183775e8b9b7SRichard Henderson     TCGOp *op;
1838afb49896SRichard Henderson 
1839619205fdSEmilio G. Cota     info = g_hash_table_lookup(helper_table, (gpointer)func);
1840bbb8a1b4SRichard Henderson     flags = info->flags;
1841bbb8a1b4SRichard Henderson     sizemask = info->sizemask;
18422bece2c8SRichard Henderson 
184338b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
184438b47b19SEmilio G. Cota     /* detect non-plugin helpers */
184538b47b19SEmilio G. Cota     if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) {
184638b47b19SEmilio G. Cota         tcg_ctx->plugin_insn->calls_helpers = true;
184738b47b19SEmilio G. Cota     }
184838b47b19SEmilio G. Cota #endif
184938b47b19SEmilio G. Cota 
185034b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
185134b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
185234b1a49cSRichard Henderson     /* We have 64-bit values in one register, but need to pass as two
185334b1a49cSRichard Henderson        separate parameters.  Split them.  */
185434b1a49cSRichard Henderson     int orig_sizemask = sizemask;
185534b1a49cSRichard Henderson     int orig_nargs = nargs;
185634b1a49cSRichard Henderson     TCGv_i64 retl, reth;
1857ae8b75dcSRichard Henderson     TCGTemp *split_args[MAX_OPC_PARAM];
185834b1a49cSRichard Henderson 
1859f764718dSRichard Henderson     retl = NULL;
1860f764718dSRichard Henderson     reth = NULL;
186134b1a49cSRichard Henderson     if (sizemask != 0) {
186234b1a49cSRichard Henderson         for (i = real_args = 0; i < nargs; ++i) {
186334b1a49cSRichard Henderson             int is_64bit = sizemask & (1 << (i+1)*2);
186434b1a49cSRichard Henderson             if (is_64bit) {
1865085272b3SRichard Henderson                 TCGv_i64 orig = temp_tcgv_i64(args[i]);
186634b1a49cSRichard Henderson                 TCGv_i32 h = tcg_temp_new_i32();
186734b1a49cSRichard Henderson                 TCGv_i32 l = tcg_temp_new_i32();
186834b1a49cSRichard Henderson                 tcg_gen_extr_i64_i32(l, h, orig);
1869ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(h);
1870ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(l);
187134b1a49cSRichard Henderson             } else {
187234b1a49cSRichard Henderson                 split_args[real_args++] = args[i];
187334b1a49cSRichard Henderson             }
187434b1a49cSRichard Henderson         }
187534b1a49cSRichard Henderson         nargs = real_args;
187634b1a49cSRichard Henderson         args = split_args;
187734b1a49cSRichard Henderson         sizemask = 0;
187834b1a49cSRichard Henderson     }
187934b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
18802bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
18812bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
18822bece2c8SRichard Henderson         int is_signed = sizemask & (2 << (i+1)*2);
18832bece2c8SRichard Henderson         if (!is_64bit) {
18842bece2c8SRichard Henderson             TCGv_i64 temp = tcg_temp_new_i64();
1885085272b3SRichard Henderson             TCGv_i64 orig = temp_tcgv_i64(args[i]);
18862bece2c8SRichard Henderson             if (is_signed) {
18872bece2c8SRichard Henderson                 tcg_gen_ext32s_i64(temp, orig);
18882bece2c8SRichard Henderson             } else {
18892bece2c8SRichard Henderson                 tcg_gen_ext32u_i64(temp, orig);
18902bece2c8SRichard Henderson             }
1891ae8b75dcSRichard Henderson             args[i] = tcgv_i64_temp(temp);
18922bece2c8SRichard Henderson         }
18932bece2c8SRichard Henderson     }
18942bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
18952bece2c8SRichard Henderson 
189615fa08f8SRichard Henderson     op = tcg_emit_op(INDEX_op_call);
189775e8b9b7SRichard Henderson 
189875e8b9b7SRichard Henderson     pi = 0;
1899ae8b75dcSRichard Henderson     if (ret != NULL) {
190034b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
190134b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
190234b1a49cSRichard Henderson         if (orig_sizemask & 1) {
190334b1a49cSRichard Henderson             /* The 32-bit ABI is going to return the 64-bit value in
190434b1a49cSRichard Henderson                the %o0/%o1 register pair.  Prepare for this by using
190534b1a49cSRichard Henderson                two return temporaries, and reassemble below.  */
190634b1a49cSRichard Henderson             retl = tcg_temp_new_i64();
190734b1a49cSRichard Henderson             reth = tcg_temp_new_i64();
1908ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(reth);
1909ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(retl);
191034b1a49cSRichard Henderson             nb_rets = 2;
191134b1a49cSRichard Henderson         } else {
1912ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
191334b1a49cSRichard Henderson             nb_rets = 1;
191434b1a49cSRichard Henderson         }
191534b1a49cSRichard Henderson #else
191634b1a49cSRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) {
191702eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
1918ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1919ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1920a7812ae4Spbrook #else
1921ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1922ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1923a7812ae4Spbrook #endif
1924a7812ae4Spbrook             nb_rets = 2;
192534b1a49cSRichard Henderson         } else {
1926ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1927a7812ae4Spbrook             nb_rets = 1;
1928a7812ae4Spbrook         }
192934b1a49cSRichard Henderson #endif
1930a7812ae4Spbrook     } else {
1931a7812ae4Spbrook         nb_rets = 0;
1932a7812ae4Spbrook     }
1933cd9090aaSRichard Henderson     TCGOP_CALLO(op) = nb_rets;
193475e8b9b7SRichard Henderson 
1935a7812ae4Spbrook     real_args = 0;
1936a7812ae4Spbrook     for (i = 0; i < nargs; i++) {
19372bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
1938bbb8a1b4SRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
193939cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS
194039cf05d3Sbellard             /* some targets want aligned 64 bit args */
1941ebd486d5Smalc             if (real_args & 1) {
194275e8b9b7SRichard Henderson                 op->args[pi++] = TCG_CALL_DUMMY_ARG;
1943ebd486d5Smalc                 real_args++;
194439cf05d3Sbellard             }
194539cf05d3Sbellard #endif
19463f90f252SRichard Henderson            /* If stack grows up, then we will be placing successive
19473f90f252SRichard Henderson               arguments at lower addresses, which means we need to
19483f90f252SRichard Henderson               reverse the order compared to how we would normally
19493f90f252SRichard Henderson               treat either big or little-endian.  For those arguments
19503f90f252SRichard Henderson               that will wind up in registers, this still works for
19513f90f252SRichard Henderson               HPPA (the only current STACK_GROWSUP target) since the
19523f90f252SRichard Henderson               argument registers are *also* allocated in decreasing
19533f90f252SRichard Henderson               order.  If another such target is added, this logic may
19543f90f252SRichard Henderson               have to get more complicated to differentiate between
19553f90f252SRichard Henderson               stack arguments and register arguments.  */
195602eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
1957ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1958ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1959c896fe29Sbellard #else
1960ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1961ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1962c896fe29Sbellard #endif
1963a7812ae4Spbrook             real_args += 2;
19642bece2c8SRichard Henderson             continue;
19652bece2c8SRichard Henderson         }
19662bece2c8SRichard Henderson 
1967ae8b75dcSRichard Henderson         op->args[pi++] = temp_arg(args[i]);
1968a7812ae4Spbrook         real_args++;
1969c896fe29Sbellard     }
197075e8b9b7SRichard Henderson     op->args[pi++] = (uintptr_t)func;
197175e8b9b7SRichard Henderson     op->args[pi++] = flags;
1972cd9090aaSRichard Henderson     TCGOP_CALLI(op) = real_args;
1973a7812ae4Spbrook 
197475e8b9b7SRichard Henderson     /* Make sure the fields didn't overflow.  */
1975cd9090aaSRichard Henderson     tcg_debug_assert(TCGOP_CALLI(op) == real_args);
197675e8b9b7SRichard Henderson     tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
19772bece2c8SRichard Henderson 
197834b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
197934b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
198034b1a49cSRichard Henderson     /* Free all of the parts we allocated above.  */
198134b1a49cSRichard Henderson     for (i = real_args = 0; i < orig_nargs; ++i) {
198234b1a49cSRichard Henderson         int is_64bit = orig_sizemask & (1 << (i+1)*2);
198334b1a49cSRichard Henderson         if (is_64bit) {
1984085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
1985085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
198634b1a49cSRichard Henderson         } else {
198734b1a49cSRichard Henderson             real_args++;
198834b1a49cSRichard Henderson         }
198934b1a49cSRichard Henderson     }
199034b1a49cSRichard Henderson     if (orig_sizemask & 1) {
199134b1a49cSRichard Henderson         /* The 32-bit ABI returned two 32-bit pieces.  Re-assemble them.
199234b1a49cSRichard Henderson            Note that describing these as TCGv_i64 eliminates an unnecessary
199334b1a49cSRichard Henderson            zero-extension that tcg_gen_concat_i32_i64 would create.  */
1994085272b3SRichard Henderson         tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth);
199534b1a49cSRichard Henderson         tcg_temp_free_i64(retl);
199634b1a49cSRichard Henderson         tcg_temp_free_i64(reth);
199734b1a49cSRichard Henderson     }
199834b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
19992bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
20002bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
20012bece2c8SRichard Henderson         if (!is_64bit) {
2002085272b3SRichard Henderson             tcg_temp_free_internal(args[i]);
20032bece2c8SRichard Henderson         }
20042bece2c8SRichard Henderson     }
20052bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
2006a7812ae4Spbrook }
2007c896fe29Sbellard 
20088fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
2009c896fe29Sbellard {
2010ac3b8891SRichard Henderson     int i, n;
2011ac3b8891SRichard Henderson 
2012ee17db83SRichard Henderson     for (i = 0, n = s->nb_temps; i < n; i++) {
2013ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2014ee17db83SRichard Henderson         TCGTempVal val = TEMP_VAL_MEM;
2015ee17db83SRichard Henderson 
2016ee17db83SRichard Henderson         switch (ts->kind) {
2017c0522136SRichard Henderson         case TEMP_CONST:
2018c0522136SRichard Henderson             val = TEMP_VAL_CONST;
2019c0522136SRichard Henderson             break;
2020ee17db83SRichard Henderson         case TEMP_FIXED:
2021ee17db83SRichard Henderson             val = TEMP_VAL_REG;
2022ee17db83SRichard Henderson             break;
2023ee17db83SRichard Henderson         case TEMP_GLOBAL:
2024ee17db83SRichard Henderson             break;
2025ee17db83SRichard Henderson         case TEMP_NORMAL:
2026ee17db83SRichard Henderson             val = TEMP_VAL_DEAD;
2027ee17db83SRichard Henderson             /* fall through */
2028ee17db83SRichard Henderson         case TEMP_LOCAL:
2029e8996ee0Sbellard             ts->mem_allocated = 0;
2030ee17db83SRichard Henderson             break;
2031ee17db83SRichard Henderson         default:
2032ee17db83SRichard Henderson             g_assert_not_reached();
2033ee17db83SRichard Henderson         }
2034ee17db83SRichard Henderson         ts->val_type = val;
2035e8996ee0Sbellard     }
2036f8b2f202SRichard Henderson 
2037f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
2038c896fe29Sbellard }
2039c896fe29Sbellard 
2040f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
2041f8b2f202SRichard Henderson                                  TCGTemp *ts)
2042c896fe29Sbellard {
20431807f4c4SRichard Henderson     int idx = temp_idx(ts);
2044ac56dd48Spbrook 
2045ee17db83SRichard Henderson     switch (ts->kind) {
2046ee17db83SRichard Henderson     case TEMP_FIXED:
2047ee17db83SRichard Henderson     case TEMP_GLOBAL:
2048ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
2049ee17db83SRichard Henderson         break;
2050ee17db83SRichard Henderson     case TEMP_LOCAL:
2051641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
2052ee17db83SRichard Henderson         break;
2053ee17db83SRichard Henderson     case TEMP_NORMAL:
2054ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
2055ee17db83SRichard Henderson         break;
2056c0522136SRichard Henderson     case TEMP_CONST:
2057c0522136SRichard Henderson         switch (ts->type) {
2058c0522136SRichard Henderson         case TCG_TYPE_I32:
2059c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%x", (int32_t)ts->val);
2060c0522136SRichard Henderson             break;
2061c0522136SRichard Henderson #if TCG_TARGET_REG_BITS > 32
2062c0522136SRichard Henderson         case TCG_TYPE_I64:
2063c0522136SRichard Henderson             snprintf(buf, buf_size, "$0x%" PRIx64, ts->val);
2064c0522136SRichard Henderson             break;
2065c0522136SRichard Henderson #endif
2066c0522136SRichard Henderson         case TCG_TYPE_V64:
2067c0522136SRichard Henderson         case TCG_TYPE_V128:
2068c0522136SRichard Henderson         case TCG_TYPE_V256:
2069c0522136SRichard Henderson             snprintf(buf, buf_size, "v%d$0x%" PRIx64,
2070c0522136SRichard Henderson                      64 << (ts->type - TCG_TYPE_V64), ts->val);
2071c0522136SRichard Henderson             break;
2072c0522136SRichard Henderson         default:
2073c0522136SRichard Henderson             g_assert_not_reached();
2074c0522136SRichard Henderson         }
2075c0522136SRichard Henderson         break;
2076c896fe29Sbellard     }
2077c896fe29Sbellard     return buf;
2078c896fe29Sbellard }
2079c896fe29Sbellard 
208043439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
208143439139SRichard Henderson                              int buf_size, TCGArg arg)
2082f8b2f202SRichard Henderson {
208343439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
2084f8b2f202SRichard Henderson }
2085f8b2f202SRichard Henderson 
20866e085f72SRichard Henderson /* Find helper name.  */
20876e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val)
2088e8996ee0Sbellard {
20896e085f72SRichard Henderson     const char *ret = NULL;
2090619205fdSEmilio G. Cota     if (helper_table) {
2091619205fdSEmilio G. Cota         TCGHelperInfo *info = g_hash_table_lookup(helper_table, (gpointer)val);
209272866e82SRichard Henderson         if (info) {
209372866e82SRichard Henderson             ret = info->name;
209472866e82SRichard Henderson         }
2095e8996ee0Sbellard     }
20966e085f72SRichard Henderson     return ret;
20974dc81f28Sbellard }
20984dc81f28Sbellard 
2099f48f3edeSblueswir1 static const char * const cond_name[] =
2100f48f3edeSblueswir1 {
21010aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
21020aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
2103f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
2104f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
2105f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
2106f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
2107f48f3edeSblueswir1     [TCG_COND_LE] = "le",
2108f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
2109f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
2110f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
2111f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
2112f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
2113f48f3edeSblueswir1 };
2114f48f3edeSblueswir1 
2115f713d6adSRichard Henderson static const char * const ldst_name[] =
2116f713d6adSRichard Henderson {
2117f713d6adSRichard Henderson     [MO_UB]   = "ub",
2118f713d6adSRichard Henderson     [MO_SB]   = "sb",
2119f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
2120f713d6adSRichard Henderson     [MO_LESW] = "lesw",
2121f713d6adSRichard Henderson     [MO_LEUL] = "leul",
2122f713d6adSRichard Henderson     [MO_LESL] = "lesl",
2123f713d6adSRichard Henderson     [MO_LEQ]  = "leq",
2124f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
2125f713d6adSRichard Henderson     [MO_BESW] = "besw",
2126f713d6adSRichard Henderson     [MO_BEUL] = "beul",
2127f713d6adSRichard Henderson     [MO_BESL] = "besl",
2128f713d6adSRichard Henderson     [MO_BEQ]  = "beq",
2129f713d6adSRichard Henderson };
2130f713d6adSRichard Henderson 
21311f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
213252bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY
21331f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
21341f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
21351f00b27fSSergey Sorokin #else
21361f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
21371f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
21381f00b27fSSergey Sorokin #endif
21391f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
21401f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
21411f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
21421f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
21431f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
21441f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
21451f00b27fSSergey Sorokin };
21461f00b27fSSergey Sorokin 
2147b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
2148b016486eSRichard Henderson {
2149b016486eSRichard Henderson     return (d & (d - 1)) == 0;
2150b016486eSRichard Henderson }
2151b016486eSRichard Henderson 
2152b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
2153b016486eSRichard Henderson {
2154b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
2155b016486eSRichard Henderson         return ctz32(d);
2156b016486eSRichard Henderson     } else {
2157b016486eSRichard Henderson         return ctz64(d);
2158b016486eSRichard Henderson     }
2159b016486eSRichard Henderson }
2160b016486eSRichard Henderson 
21611894f69aSRichard Henderson static void tcg_dump_ops(TCGContext *s, bool have_prefs)
2162c896fe29Sbellard {
2163c896fe29Sbellard     char buf[128];
2164c45cb8bbSRichard Henderson     TCGOp *op;
2165c896fe29Sbellard 
216615fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
2167c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
2168c45cb8bbSRichard Henderson         const TCGOpDef *def;
2169c45cb8bbSRichard Henderson         TCGOpcode c;
2170bdfb460eSRichard Henderson         int col = 0;
2171c45cb8bbSRichard Henderson 
2172c45cb8bbSRichard Henderson         c = op->opc;
2173c896fe29Sbellard         def = &tcg_op_defs[c];
2174c45cb8bbSRichard Henderson 
2175765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
2176b016486eSRichard Henderson             nb_oargs = 0;
217715fa08f8SRichard Henderson             col += qemu_log("\n ----");
21789aef40edSRichard Henderson 
21799aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
21809aef40edSRichard Henderson                 target_ulong a;
21817e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
2182efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
21837e4597d7Sbellard #else
2184efee3746SRichard Henderson                 a = op->args[i];
21857e4597d7Sbellard #endif
2186bdfb460eSRichard Henderson                 col += qemu_log(" " TARGET_FMT_lx, a);
2187eeacee4dSBlue Swirl             }
21887e4597d7Sbellard         } else if (c == INDEX_op_call) {
2189c896fe29Sbellard             /* variable number of arguments */
2190cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2191cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2192c896fe29Sbellard             nb_cargs = def->nb_cargs;
2193b03cce8eSbellard 
2194cf066674SRichard Henderson             /* function name, flags, out args */
2195bdfb460eSRichard Henderson             col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name,
2196efee3746SRichard Henderson                             tcg_find_helper(s, op->args[nb_oargs + nb_iargs]),
2197efee3746SRichard Henderson                             op->args[nb_oargs + nb_iargs + 1], nb_oargs);
2198b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
219943439139SRichard Henderson                 col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf),
2200efee3746SRichard Henderson                                                        op->args[i]));
2201b03cce8eSbellard             }
2202cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
2203efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
2204cf066674SRichard Henderson                 const char *t = "<dummy>";
2205cf066674SRichard Henderson                 if (arg != TCG_CALL_DUMMY_ARG) {
220643439139SRichard Henderson                     t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
2207b03cce8eSbellard                 }
2208bdfb460eSRichard Henderson                 col += qemu_log(",%s", t);
2209e8996ee0Sbellard             }
2210b03cce8eSbellard         } else {
2211bdfb460eSRichard Henderson             col += qemu_log(" %s ", def->name);
2212c45cb8bbSRichard Henderson 
2213c896fe29Sbellard             nb_oargs = def->nb_oargs;
2214c896fe29Sbellard             nb_iargs = def->nb_iargs;
2215c896fe29Sbellard             nb_cargs = def->nb_cargs;
2216c896fe29Sbellard 
2217d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
2218d2fd745fSRichard Henderson                 col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op),
2219d2fd745fSRichard Henderson                                 8 << TCGOP_VECE(op));
2220d2fd745fSRichard Henderson             }
2221d2fd745fSRichard Henderson 
2222c896fe29Sbellard             k = 0;
2223c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
2224eeacee4dSBlue Swirl                 if (k != 0) {
2225bdfb460eSRichard Henderson                     col += qemu_log(",");
2226eeacee4dSBlue Swirl                 }
222743439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2228efee3746SRichard Henderson                                                       op->args[k++]));
2229c896fe29Sbellard             }
2230c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
2231eeacee4dSBlue Swirl                 if (k != 0) {
2232bdfb460eSRichard Henderson                     col += qemu_log(",");
2233eeacee4dSBlue Swirl                 }
223443439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2235efee3746SRichard Henderson                                                       op->args[k++]));
2236c896fe29Sbellard             }
2237be210acbSRichard Henderson             switch (c) {
2238be210acbSRichard Henderson             case INDEX_op_brcond_i32:
2239ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
2240ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
2241be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
2242be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
2243ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
2244be210acbSRichard Henderson             case INDEX_op_setcond_i64:
2245ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
2246212be173SRichard Henderson             case INDEX_op_cmp_vec:
2247f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
2248efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
2249efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
2250efee3746SRichard Henderson                     col += qemu_log(",%s", cond_name[op->args[k++]]);
2251eeacee4dSBlue Swirl                 } else {
2252efee3746SRichard Henderson                     col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]);
2253eeacee4dSBlue Swirl                 }
2254f48f3edeSblueswir1                 i = 1;
2255be210acbSRichard Henderson                 break;
2256f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
2257f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
225807ce0b05SRichard Henderson             case INDEX_op_qemu_st8_i32:
2259f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
2260f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
226159227d5dSRichard Henderson                 {
2262efee3746SRichard Henderson                     TCGMemOpIdx oi = op->args[k++];
226314776ab5STony Nguyen                     MemOp op = get_memop(oi);
226459227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
226559227d5dSRichard Henderson 
226659c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
2267bdfb460eSRichard Henderson                         col += qemu_log(",$0x%x,%u", op, ix);
226859c4b7e8SRichard Henderson                     } else {
22691f00b27fSSergey Sorokin                         const char *s_al, *s_op;
22701f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
227159c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
2272bdfb460eSRichard Henderson                         col += qemu_log(",%s%s,%u", s_al, s_op, ix);
2273f713d6adSRichard Henderson                     }
2274f713d6adSRichard Henderson                     i = 1;
227559227d5dSRichard Henderson                 }
2276f713d6adSRichard Henderson                 break;
2277be210acbSRichard Henderson             default:
2278f48f3edeSblueswir1                 i = 0;
2279be210acbSRichard Henderson                 break;
2280be210acbSRichard Henderson             }
228151e3972cSRichard Henderson             switch (c) {
228251e3972cSRichard Henderson             case INDEX_op_set_label:
228351e3972cSRichard Henderson             case INDEX_op_br:
228451e3972cSRichard Henderson             case INDEX_op_brcond_i32:
228551e3972cSRichard Henderson             case INDEX_op_brcond_i64:
228651e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2287efee3746SRichard Henderson                 col += qemu_log("%s$L%d", k ? "," : "",
2288efee3746SRichard Henderson                                 arg_label(op->args[k])->id);
228951e3972cSRichard Henderson                 i++, k++;
229051e3972cSRichard Henderson                 break;
229151e3972cSRichard Henderson             default:
229251e3972cSRichard Henderson                 break;
2293eeacee4dSBlue Swirl             }
229451e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
2295efee3746SRichard Henderson                 col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]);
2296bdfb460eSRichard Henderson             }
2297bdfb460eSRichard Henderson         }
2298bdfb460eSRichard Henderson 
22991894f69aSRichard Henderson         if (have_prefs || op->life) {
23007606488cSRobert Foley 
23017606488cSRobert Foley             QemuLogFile *logfile;
23027606488cSRobert Foley 
23037606488cSRobert Foley             rcu_read_lock();
2304d73415a3SStefan Hajnoczi             logfile = qatomic_rcu_read(&qemu_logfile);
23057606488cSRobert Foley             if (logfile) {
23061894f69aSRichard Henderson                 for (; col < 40; ++col) {
23077606488cSRobert Foley                     putc(' ', logfile->fd);
2308bdfb460eSRichard Henderson                 }
23091894f69aSRichard Henderson             }
23107606488cSRobert Foley             rcu_read_unlock();
23117606488cSRobert Foley         }
23121894f69aSRichard Henderson 
23131894f69aSRichard Henderson         if (op->life) {
23141894f69aSRichard Henderson             unsigned life = op->life;
2315bdfb460eSRichard Henderson 
2316bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
2317bdfb460eSRichard Henderson                 qemu_log("  sync:");
2318bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
2319bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
2320bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2321bdfb460eSRichard Henderson                     }
2322bdfb460eSRichard Henderson                 }
2323bdfb460eSRichard Henderson             }
2324bdfb460eSRichard Henderson             life /= DEAD_ARG;
2325bdfb460eSRichard Henderson             if (life) {
2326bdfb460eSRichard Henderson                 qemu_log("  dead:");
2327bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
2328bdfb460eSRichard Henderson                     if (life & 1) {
2329bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2330bdfb460eSRichard Henderson                     }
2331bdfb460eSRichard Henderson                 }
2332c896fe29Sbellard             }
2333b03cce8eSbellard         }
23341894f69aSRichard Henderson 
23351894f69aSRichard Henderson         if (have_prefs) {
23361894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
23371894f69aSRichard Henderson                 TCGRegSet set = op->output_pref[i];
23381894f69aSRichard Henderson 
23391894f69aSRichard Henderson                 if (i == 0) {
23401894f69aSRichard Henderson                     qemu_log("  pref=");
23411894f69aSRichard Henderson                 } else {
23421894f69aSRichard Henderson                     qemu_log(",");
23431894f69aSRichard Henderson                 }
23441894f69aSRichard Henderson                 if (set == 0) {
23451894f69aSRichard Henderson                     qemu_log("none");
23461894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
23471894f69aSRichard Henderson                     qemu_log("all");
23481894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
23491894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
23501894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
23511894f69aSRichard Henderson                     qemu_log("%s", tcg_target_reg_names[reg]);
23521894f69aSRichard Henderson #endif
23531894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
23541894f69aSRichard Henderson                     qemu_log("%#x", (uint32_t)set);
23551894f69aSRichard Henderson                 } else {
23561894f69aSRichard Henderson                     qemu_log("%#" PRIx64, (uint64_t)set);
23571894f69aSRichard Henderson                 }
23581894f69aSRichard Henderson             }
23591894f69aSRichard Henderson         }
23601894f69aSRichard Henderson 
2361eeacee4dSBlue Swirl         qemu_log("\n");
2362c896fe29Sbellard     }
2363c896fe29Sbellard }
2364c896fe29Sbellard 
2365c896fe29Sbellard /* we give more priority to constraints with less registers */
2366c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2367c896fe29Sbellard {
236874a11790SRichard Henderson     const TCGArgConstraint *arg_ct = &def->args_ct[k];
236974a11790SRichard Henderson     int n;
2370c896fe29Sbellard 
2371bc2b17e6SRichard Henderson     if (arg_ct->oalias) {
2372c896fe29Sbellard         /* an alias is equivalent to a single register */
2373c896fe29Sbellard         n = 1;
2374c896fe29Sbellard     } else {
237574a11790SRichard Henderson         n = ctpop64(arg_ct->regs);
2376c896fe29Sbellard     }
2377c896fe29Sbellard     return TCG_TARGET_NB_REGS - n + 1;
2378c896fe29Sbellard }
2379c896fe29Sbellard 
2380c896fe29Sbellard /* sort from highest priority to lowest */
2381c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2382c896fe29Sbellard {
238366792f90SRichard Henderson     int i, j;
238466792f90SRichard Henderson     TCGArgConstraint *a = def->args_ct;
2385c896fe29Sbellard 
238666792f90SRichard Henderson     for (i = 0; i < n; i++) {
238766792f90SRichard Henderson         a[start + i].sort_index = start + i;
238866792f90SRichard Henderson     }
238966792f90SRichard Henderson     if (n <= 1) {
2390c896fe29Sbellard         return;
239166792f90SRichard Henderson     }
2392c896fe29Sbellard     for (i = 0; i < n - 1; i++) {
2393c896fe29Sbellard         for (j = i + 1; j < n; j++) {
239466792f90SRichard Henderson             int p1 = get_constraint_priority(def, a[start + i].sort_index);
239566792f90SRichard Henderson             int p2 = get_constraint_priority(def, a[start + j].sort_index);
2396c896fe29Sbellard             if (p1 < p2) {
239766792f90SRichard Henderson                 int tmp = a[start + i].sort_index;
239866792f90SRichard Henderson                 a[start + i].sort_index = a[start + j].sort_index;
239966792f90SRichard Henderson                 a[start + j].sort_index = tmp;
2400c896fe29Sbellard             }
2401c896fe29Sbellard         }
2402c896fe29Sbellard     }
2403c896fe29Sbellard }
2404c896fe29Sbellard 
2405f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2406c896fe29Sbellard {
2407a9751609SRichard Henderson     TCGOpcode op;
2408c896fe29Sbellard 
2409f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
2410f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
2411f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
2412069ea736SRichard Henderson         TCGType type;
2413069ea736SRichard Henderson         int i, nb_args;
2414f69d277eSRichard Henderson 
2415f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
2416f69d277eSRichard Henderson             continue;
2417f69d277eSRichard Henderson         }
2418f69d277eSRichard Henderson 
2419c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
2420f69d277eSRichard Henderson         if (nb_args == 0) {
2421f69d277eSRichard Henderson             continue;
2422f69d277eSRichard Henderson         }
2423f69d277eSRichard Henderson 
2424f69d277eSRichard Henderson         tdefs = tcg_target_op_def(op);
2425f69d277eSRichard Henderson         /* Missing TCGTargetOpDef entry. */
2426f69d277eSRichard Henderson         tcg_debug_assert(tdefs != NULL);
2427f69d277eSRichard Henderson 
2428069ea736SRichard Henderson         type = (def->flags & TCG_OPF_64BIT ? TCG_TYPE_I64 : TCG_TYPE_I32);
2429c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2430f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
2431f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2432eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2433f69d277eSRichard Henderson 
243417280ff4SRichard Henderson             while (*ct_str != '\0') {
243517280ff4SRichard Henderson                 switch(*ct_str) {
243617280ff4SRichard Henderson                 case '0' ... '9':
243717280ff4SRichard Henderson                     {
243817280ff4SRichard Henderson                         int oarg = *ct_str - '0';
243917280ff4SRichard Henderson                         tcg_debug_assert(ct_str == tdefs->args_ct_str[i]);
2440eabb7b91SAurelien Jarno                         tcg_debug_assert(oarg < def->nb_oargs);
244174a11790SRichard Henderson                         tcg_debug_assert(def->args_ct[oarg].regs != 0);
2442c896fe29Sbellard                         def->args_ct[i] = def->args_ct[oarg];
2443bc2b17e6SRichard Henderson                         /* The output sets oalias.  */
2444bc2b17e6SRichard Henderson                         def->args_ct[oarg].oalias = true;
24455ff9d6a4Sbellard                         def->args_ct[oarg].alias_index = i;
2446bc2b17e6SRichard Henderson                         /* The input sets ialias. */
2447bc2b17e6SRichard Henderson                         def->args_ct[i].ialias = true;
24485ff9d6a4Sbellard                         def->args_ct[i].alias_index = oarg;
244917280ff4SRichard Henderson                     }
245017280ff4SRichard Henderson                     ct_str++;
2451c896fe29Sbellard                     break;
245282790a87SRichard Henderson                 case '&':
2453bc2b17e6SRichard Henderson                     def->args_ct[i].newreg = true;
245482790a87SRichard Henderson                     ct_str++;
245582790a87SRichard Henderson                     break;
2456c896fe29Sbellard                 case 'i':
2457c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2458c896fe29Sbellard                     ct_str++;
2459c896fe29Sbellard                     break;
2460c896fe29Sbellard                 default:
2461069ea736SRichard Henderson                     ct_str = target_parse_constraint(&def->args_ct[i],
2462069ea736SRichard Henderson                                                      ct_str, type);
2463f69d277eSRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2464069ea736SRichard Henderson                     tcg_debug_assert(ct_str != NULL);
2465c896fe29Sbellard                 }
2466c896fe29Sbellard             }
2467c896fe29Sbellard         }
2468c896fe29Sbellard 
2469c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2470eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2471c68aaa18SStefan Weil 
2472c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
2473c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
2474c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
2475c896fe29Sbellard     }
2476c896fe29Sbellard }
2477c896fe29Sbellard 
24780c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
24790c627cdcSRichard Henderson {
2480d88a117eSRichard Henderson     TCGLabel *label;
2481d88a117eSRichard Henderson 
2482d88a117eSRichard Henderson     switch (op->opc) {
2483d88a117eSRichard Henderson     case INDEX_op_br:
2484d88a117eSRichard Henderson         label = arg_label(op->args[0]);
2485d88a117eSRichard Henderson         label->refs--;
2486d88a117eSRichard Henderson         break;
2487d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
2488d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
2489d88a117eSRichard Henderson         label = arg_label(op->args[3]);
2490d88a117eSRichard Henderson         label->refs--;
2491d88a117eSRichard Henderson         break;
2492d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
2493d88a117eSRichard Henderson         label = arg_label(op->args[5]);
2494d88a117eSRichard Henderson         label->refs--;
2495d88a117eSRichard Henderson         break;
2496d88a117eSRichard Henderson     default:
2497d88a117eSRichard Henderson         break;
2498d88a117eSRichard Henderson     }
2499d88a117eSRichard Henderson 
250015fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
250115fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
2502abebf925SRichard Henderson     s->nb_ops--;
25030c627cdcSRichard Henderson 
25040c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
2505d73415a3SStefan Hajnoczi     qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
25060c627cdcSRichard Henderson #endif
25070c627cdcSRichard Henderson }
25080c627cdcSRichard Henderson 
250915fa08f8SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc)
251015fa08f8SRichard Henderson {
251115fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
251215fa08f8SRichard Henderson     TCGOp *op;
251315fa08f8SRichard Henderson 
251415fa08f8SRichard Henderson     if (likely(QTAILQ_EMPTY(&s->free_ops))) {
251515fa08f8SRichard Henderson         op = tcg_malloc(sizeof(TCGOp));
251615fa08f8SRichard Henderson     } else {
251715fa08f8SRichard Henderson         op = QTAILQ_FIRST(&s->free_ops);
251815fa08f8SRichard Henderson         QTAILQ_REMOVE(&s->free_ops, op, link);
251915fa08f8SRichard Henderson     }
252015fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
252115fa08f8SRichard Henderson     op->opc = opc;
2522abebf925SRichard Henderson     s->nb_ops++;
252315fa08f8SRichard Henderson 
252415fa08f8SRichard Henderson     return op;
252515fa08f8SRichard Henderson }
252615fa08f8SRichard Henderson 
252715fa08f8SRichard Henderson TCGOp *tcg_emit_op(TCGOpcode opc)
252815fa08f8SRichard Henderson {
252915fa08f8SRichard Henderson     TCGOp *op = tcg_op_alloc(opc);
253015fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
253115fa08f8SRichard Henderson     return op;
253215fa08f8SRichard Henderson }
253315fa08f8SRichard Henderson 
2534ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
25355a18407fSRichard Henderson {
253615fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
253715fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
25385a18407fSRichard Henderson     return new_op;
25395a18407fSRichard Henderson }
25405a18407fSRichard Henderson 
2541ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
25425a18407fSRichard Henderson {
254315fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
254415fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
25455a18407fSRichard Henderson     return new_op;
25465a18407fSRichard Henderson }
25475a18407fSRichard Henderson 
2548b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
2549b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s)
2550b4fc67c7SRichard Henderson {
2551b4fc67c7SRichard Henderson     TCGOp *op, *op_next;
2552b4fc67c7SRichard Henderson     bool dead = false;
2553b4fc67c7SRichard Henderson 
2554b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
2555b4fc67c7SRichard Henderson         bool remove = dead;
2556b4fc67c7SRichard Henderson         TCGLabel *label;
2557b4fc67c7SRichard Henderson         int call_flags;
2558b4fc67c7SRichard Henderson 
2559b4fc67c7SRichard Henderson         switch (op->opc) {
2560b4fc67c7SRichard Henderson         case INDEX_op_set_label:
2561b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
2562b4fc67c7SRichard Henderson             if (label->refs == 0) {
2563b4fc67c7SRichard Henderson                 /*
2564b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
2565b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
2566b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
2567b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
2568b4fc67c7SRichard Henderson                  * little to be gained by iterating.
2569b4fc67c7SRichard Henderson                  */
2570b4fc67c7SRichard Henderson                 remove = true;
2571b4fc67c7SRichard Henderson             } else {
2572b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
2573b4fc67c7SRichard Henderson                 dead = false;
2574b4fc67c7SRichard Henderson                 remove = false;
2575b4fc67c7SRichard Henderson 
2576b4fc67c7SRichard Henderson                 /*
2577b4fc67c7SRichard Henderson                  * Optimization can fold conditional branches to unconditional.
2578b4fc67c7SRichard Henderson                  * If we find a label with one reference which is preceded by
2579b4fc67c7SRichard Henderson                  * an unconditional branch to it, remove both.  This needed to
2580b4fc67c7SRichard Henderson                  * wait until the dead code in between them was removed.
2581b4fc67c7SRichard Henderson                  */
2582b4fc67c7SRichard Henderson                 if (label->refs == 1) {
2583eae3eb3eSPaolo Bonzini                     TCGOp *op_prev = QTAILQ_PREV(op, link);
2584b4fc67c7SRichard Henderson                     if (op_prev->opc == INDEX_op_br &&
2585b4fc67c7SRichard Henderson                         label == arg_label(op_prev->args[0])) {
2586b4fc67c7SRichard Henderson                         tcg_op_remove(s, op_prev);
2587b4fc67c7SRichard Henderson                         remove = true;
2588b4fc67c7SRichard Henderson                     }
2589b4fc67c7SRichard Henderson                 }
2590b4fc67c7SRichard Henderson             }
2591b4fc67c7SRichard Henderson             break;
2592b4fc67c7SRichard Henderson 
2593b4fc67c7SRichard Henderson         case INDEX_op_br:
2594b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
2595b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
2596b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
2597b4fc67c7SRichard Henderson             dead = true;
2598b4fc67c7SRichard Henderson             break;
2599b4fc67c7SRichard Henderson 
2600b4fc67c7SRichard Henderson         case INDEX_op_call:
2601b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
2602b4fc67c7SRichard Henderson             call_flags = op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1];
2603b4fc67c7SRichard Henderson             if (call_flags & TCG_CALL_NO_RETURN) {
2604b4fc67c7SRichard Henderson                 dead = true;
2605b4fc67c7SRichard Henderson             }
2606b4fc67c7SRichard Henderson             break;
2607b4fc67c7SRichard Henderson 
2608b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
2609b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
2610b4fc67c7SRichard Henderson             remove = false;
2611b4fc67c7SRichard Henderson             break;
2612b4fc67c7SRichard Henderson 
2613b4fc67c7SRichard Henderson         default:
2614b4fc67c7SRichard Henderson             break;
2615b4fc67c7SRichard Henderson         }
2616b4fc67c7SRichard Henderson 
2617b4fc67c7SRichard Henderson         if (remove) {
2618b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
2619b4fc67c7SRichard Henderson         }
2620b4fc67c7SRichard Henderson     }
2621b4fc67c7SRichard Henderson }
2622b4fc67c7SRichard Henderson 
2623c70fbf0aSRichard Henderson #define TS_DEAD  1
2624c70fbf0aSRichard Henderson #define TS_MEM   2
2625c70fbf0aSRichard Henderson 
26265a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
26275a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
26285a18407fSRichard Henderson 
262925f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
263025f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
263125f49c5fSRichard Henderson {
263225f49c5fSRichard Henderson     return ts->state_ptr;
263325f49c5fSRichard Henderson }
263425f49c5fSRichard Henderson 
263525f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
263625f49c5fSRichard Henderson  * maximal regset for its type.
263725f49c5fSRichard Henderson  */
263825f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
263925f49c5fSRichard Henderson {
264025f49c5fSRichard Henderson     *la_temp_pref(ts)
264125f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
264225f49c5fSRichard Henderson }
264325f49c5fSRichard Henderson 
26449c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
26459c43b68dSAurelien Jarno    should be in memory. */
26462616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
2647c896fe29Sbellard {
2648b83eabeaSRichard Henderson     int i;
2649b83eabeaSRichard Henderson 
2650b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2651b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
265225f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2653b83eabeaSRichard Henderson     }
2654b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2655b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
265625f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2657b83eabeaSRichard Henderson     }
2658c896fe29Sbellard }
2659c896fe29Sbellard 
26609c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
26619c43b68dSAurelien Jarno    and local temps should be in memory. */
26622616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
2663641d5fbeSbellard {
2664b83eabeaSRichard Henderson     int i;
2665641d5fbeSbellard 
2666ee17db83SRichard Henderson     for (i = 0; i < nt; ++i) {
2667ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2668ee17db83SRichard Henderson         int state;
2669ee17db83SRichard Henderson 
2670ee17db83SRichard Henderson         switch (ts->kind) {
2671ee17db83SRichard Henderson         case TEMP_FIXED:
2672ee17db83SRichard Henderson         case TEMP_GLOBAL:
2673ee17db83SRichard Henderson         case TEMP_LOCAL:
2674ee17db83SRichard Henderson             state = TS_DEAD | TS_MEM;
2675ee17db83SRichard Henderson             break;
2676ee17db83SRichard Henderson         case TEMP_NORMAL:
2677c0522136SRichard Henderson         case TEMP_CONST:
2678ee17db83SRichard Henderson             state = TS_DEAD;
2679ee17db83SRichard Henderson             break;
2680ee17db83SRichard Henderson         default:
2681ee17db83SRichard Henderson             g_assert_not_reached();
2682c70fbf0aSRichard Henderson         }
2683ee17db83SRichard Henderson         ts->state = state;
2684ee17db83SRichard Henderson         la_reset_pref(ts);
2685641d5fbeSbellard     }
2686641d5fbeSbellard }
2687641d5fbeSbellard 
2688f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
2689f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
2690f65a061cSRichard Henderson {
2691f65a061cSRichard Henderson     int i;
2692f65a061cSRichard Henderson 
2693f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
269425f49c5fSRichard Henderson         int state = s->temps[i].state;
269525f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
269625f49c5fSRichard Henderson         if (state == TS_DEAD) {
269725f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
269825f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
269925f49c5fSRichard Henderson         }
2700f65a061cSRichard Henderson     }
2701f65a061cSRichard Henderson }
2702f65a061cSRichard Henderson 
2703b4cb76e6SRichard Henderson /*
2704b4cb76e6SRichard Henderson  * liveness analysis: conditional branch: all temps are dead,
2705b4cb76e6SRichard Henderson  * globals and local temps should be synced.
2706b4cb76e6SRichard Henderson  */
2707b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
2708b4cb76e6SRichard Henderson {
2709b4cb76e6SRichard Henderson     la_global_sync(s, ng);
2710b4cb76e6SRichard Henderson 
2711b4cb76e6SRichard Henderson     for (int i = ng; i < nt; ++i) {
2712c0522136SRichard Henderson         TCGTemp *ts = &s->temps[i];
2713c0522136SRichard Henderson         int state;
2714c0522136SRichard Henderson 
2715c0522136SRichard Henderson         switch (ts->kind) {
2716c0522136SRichard Henderson         case TEMP_LOCAL:
2717c0522136SRichard Henderson             state = ts->state;
2718c0522136SRichard Henderson             ts->state = state | TS_MEM;
2719b4cb76e6SRichard Henderson             if (state != TS_DEAD) {
2720b4cb76e6SRichard Henderson                 continue;
2721b4cb76e6SRichard Henderson             }
2722c0522136SRichard Henderson             break;
2723c0522136SRichard Henderson         case TEMP_NORMAL:
2724b4cb76e6SRichard Henderson             s->temps[i].state = TS_DEAD;
2725c0522136SRichard Henderson             break;
2726c0522136SRichard Henderson         case TEMP_CONST:
2727c0522136SRichard Henderson             continue;
2728c0522136SRichard Henderson         default:
2729c0522136SRichard Henderson             g_assert_not_reached();
2730b4cb76e6SRichard Henderson         }
2731b4cb76e6SRichard Henderson         la_reset_pref(&s->temps[i]);
2732b4cb76e6SRichard Henderson     }
2733b4cb76e6SRichard Henderson }
2734b4cb76e6SRichard Henderson 
2735f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
2736f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
2737f65a061cSRichard Henderson {
2738f65a061cSRichard Henderson     int i;
2739f65a061cSRichard Henderson 
2740f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
2741f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
274225f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
274325f49c5fSRichard Henderson     }
274425f49c5fSRichard Henderson }
274525f49c5fSRichard Henderson 
274625f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
274725f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
274825f49c5fSRichard Henderson {
274925f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
275025f49c5fSRichard Henderson     int i;
275125f49c5fSRichard Henderson 
275225f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
275325f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
275425f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
275525f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
275625f49c5fSRichard Henderson             TCGRegSet set = *pset;
275725f49c5fSRichard Henderson 
275825f49c5fSRichard Henderson             set &= mask;
275925f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
276025f49c5fSRichard Henderson             if (set == 0) {
276125f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
276225f49c5fSRichard Henderson             }
276325f49c5fSRichard Henderson             *pset = set;
276425f49c5fSRichard Henderson         }
2765f65a061cSRichard Henderson     }
2766f65a061cSRichard Henderson }
2767f65a061cSRichard Henderson 
2768a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
2769c896fe29Sbellard    given input arguments is dead. Instructions updating dead
2770c896fe29Sbellard    temporaries are removed. */
2771b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s)
2772c896fe29Sbellard {
2773c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
27742616c808SRichard Henderson     int nb_temps = s->nb_temps;
277515fa08f8SRichard Henderson     TCGOp *op, *op_prev;
277625f49c5fSRichard Henderson     TCGRegSet *prefs;
277725f49c5fSRichard Henderson     int i;
277825f49c5fSRichard Henderson 
277925f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
278025f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
278125f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
278225f49c5fSRichard Henderson     }
2783c896fe29Sbellard 
2784ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
27852616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
2786c896fe29Sbellard 
2787eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
278825f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
2789c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
2790c45cb8bbSRichard Henderson         bool have_opc_new2;
2791a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
279225f49c5fSRichard Henderson         TCGTemp *ts;
2793c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2794c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2795c45cb8bbSRichard Henderson 
2796c45cb8bbSRichard Henderson         switch (opc) {
2797c896fe29Sbellard         case INDEX_op_call:
2798c6e113f5Sbellard             {
2799c6e113f5Sbellard                 int call_flags;
280025f49c5fSRichard Henderson                 int nb_call_regs;
2801c6e113f5Sbellard 
2802cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
2803cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
2804efee3746SRichard Henderson                 call_flags = op->args[nb_oargs + nb_iargs + 1];
2805c6e113f5Sbellard 
2806c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
280778505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
2808c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
280925f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
281025f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
2811c6e113f5Sbellard                             goto do_not_remove_call;
2812c6e113f5Sbellard                         }
28139c43b68dSAurelien Jarno                     }
2814c45cb8bbSRichard Henderson                     goto do_remove;
2815152c35aaSRichard Henderson                 }
2816c6e113f5Sbellard             do_not_remove_call:
2817c896fe29Sbellard 
281825f49c5fSRichard Henderson                 /* Output args are dead.  */
2819c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
282025f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
282125f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
2822a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
28236b64b624SAurelien Jarno                     }
282425f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
2825a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
28269c43b68dSAurelien Jarno                     }
282725f49c5fSRichard Henderson                     ts->state = TS_DEAD;
282825f49c5fSRichard Henderson                     la_reset_pref(ts);
282925f49c5fSRichard Henderson 
283025f49c5fSRichard Henderson                     /* Not used -- it will be tcg_target_call_oarg_regs[i].  */
283125f49c5fSRichard Henderson                     op->output_pref[i] = 0;
2832c896fe29Sbellard                 }
2833c896fe29Sbellard 
283478505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
283578505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
2836f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
2837c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
2838f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
2839b9c18f56Saurel32                 }
2840c896fe29Sbellard 
284125f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
2842866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
284325f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
284425f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
2845a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
2846c896fe29Sbellard                     }
2847c896fe29Sbellard                 }
284825f49c5fSRichard Henderson 
284925f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
285025f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
285125f49c5fSRichard Henderson 
285225f49c5fSRichard Henderson                 nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
285325f49c5fSRichard Henderson 
285425f49c5fSRichard Henderson                 /* Input arguments are live for preceding opcodes.  */
285525f49c5fSRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
285625f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
285725f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
285825f49c5fSRichard Henderson                         /* For those arguments that die, and will be allocated
285925f49c5fSRichard Henderson                          * in registers, clear the register set for that arg,
286025f49c5fSRichard Henderson                          * to be filled in below.  For args that will be on
286125f49c5fSRichard Henderson                          * the stack, reset to any available reg.
286225f49c5fSRichard Henderson                          */
286325f49c5fSRichard Henderson                         *la_temp_pref(ts)
286425f49c5fSRichard Henderson                             = (i < nb_call_regs ? 0 :
286525f49c5fSRichard Henderson                                tcg_target_available_regs[ts->type]);
286625f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
286725f49c5fSRichard Henderson                     }
286825f49c5fSRichard Henderson                 }
286925f49c5fSRichard Henderson 
287025f49c5fSRichard Henderson                 /* For each input argument, add its input register to prefs.
287125f49c5fSRichard Henderson                    If a temp is used once, this produces a single set bit.  */
287225f49c5fSRichard Henderson                 for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) {
287325f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
287425f49c5fSRichard Henderson                     if (ts) {
287525f49c5fSRichard Henderson                         tcg_regset_set_reg(*la_temp_pref(ts),
287625f49c5fSRichard Henderson                                            tcg_target_call_iarg_regs[i]);
2877c70fbf0aSRichard Henderson                     }
2878c19f47bfSAurelien Jarno                 }
2879c6e113f5Sbellard             }
2880c896fe29Sbellard             break;
2881765b842aSRichard Henderson         case INDEX_op_insn_start:
2882c896fe29Sbellard             break;
28835ff9d6a4Sbellard         case INDEX_op_discard:
28845ff9d6a4Sbellard             /* mark the temporary as dead */
288525f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
288625f49c5fSRichard Henderson             ts->state = TS_DEAD;
288725f49c5fSRichard Henderson             la_reset_pref(ts);
28885ff9d6a4Sbellard             break;
28891305c451SRichard Henderson 
28901305c451SRichard Henderson         case INDEX_op_add2_i32:
2891c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
2892f1fae40cSRichard Henderson             goto do_addsub2;
28931305c451SRichard Henderson         case INDEX_op_sub2_i32:
2894c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
2895f1fae40cSRichard Henderson             goto do_addsub2;
2896f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
2897c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
2898f1fae40cSRichard Henderson             goto do_addsub2;
2899f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
2900c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
2901f1fae40cSRichard Henderson         do_addsub2:
29021305c451SRichard Henderson             nb_iargs = 4;
29031305c451SRichard Henderson             nb_oargs = 2;
29041305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
29051305c451SRichard Henderson                the low part.  The result can be optimized to a simple
29061305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
29071305c451SRichard Henderson                cpu mode is set to 32 bit.  */
2908b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2909b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
29101305c451SRichard Henderson                     goto do_remove;
29111305c451SRichard Henderson                 }
2912c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
2913c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
2914c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2915efee3746SRichard Henderson                 op->args[1] = op->args[2];
2916efee3746SRichard Henderson                 op->args[2] = op->args[4];
29171305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
29181305c451SRichard Henderson                 nb_iargs = 2;
29191305c451SRichard Henderson                 nb_oargs = 1;
29201305c451SRichard Henderson             }
29211305c451SRichard Henderson             goto do_not_remove;
29221305c451SRichard Henderson 
29231414968aSRichard Henderson         case INDEX_op_mulu2_i32:
2924c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2925c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
2926c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
292703271524SRichard Henderson             goto do_mul2;
2928f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
2929c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2930c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
2931c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
2932f1fae40cSRichard Henderson             goto do_mul2;
2933f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
2934c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2935c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
2936c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
293703271524SRichard Henderson             goto do_mul2;
2938f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
2939c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2940c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
2941c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
294203271524SRichard Henderson             goto do_mul2;
2943f1fae40cSRichard Henderson         do_mul2:
29441414968aSRichard Henderson             nb_iargs = 2;
29451414968aSRichard Henderson             nb_oargs = 2;
2946b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2947b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
294803271524SRichard Henderson                     /* Both parts of the operation are dead.  */
29491414968aSRichard Henderson                     goto do_remove;
29501414968aSRichard Henderson                 }
295103271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
2952c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2953efee3746SRichard Henderson                 op->args[1] = op->args[2];
2954efee3746SRichard Henderson                 op->args[2] = op->args[3];
2955b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
295603271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
2957c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
2958efee3746SRichard Henderson                 op->args[0] = op->args[1];
2959efee3746SRichard Henderson                 op->args[1] = op->args[2];
2960efee3746SRichard Henderson                 op->args[2] = op->args[3];
296103271524SRichard Henderson             } else {
296203271524SRichard Henderson                 goto do_not_remove;
296303271524SRichard Henderson             }
296403271524SRichard Henderson             /* Mark the single-word operation live.  */
29651414968aSRichard Henderson             nb_oargs = 1;
29661414968aSRichard Henderson             goto do_not_remove;
29671414968aSRichard Henderson 
2968c896fe29Sbellard         default:
29691305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
2970c896fe29Sbellard             nb_iargs = def->nb_iargs;
2971c896fe29Sbellard             nb_oargs = def->nb_oargs;
2972c896fe29Sbellard 
2973c896fe29Sbellard             /* Test if the operation can be removed because all
29745ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
29755ff9d6a4Sbellard                implies side effects */
29765ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
2977c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
2978b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
2979c896fe29Sbellard                         goto do_not_remove;
2980c896fe29Sbellard                     }
29819c43b68dSAurelien Jarno                 }
2982152c35aaSRichard Henderson                 goto do_remove;
2983152c35aaSRichard Henderson             }
2984152c35aaSRichard Henderson             goto do_not_remove;
2985152c35aaSRichard Henderson 
29861305c451SRichard Henderson         do_remove:
29870c627cdcSRichard Henderson             tcg_op_remove(s, op);
2988152c35aaSRichard Henderson             break;
2989152c35aaSRichard Henderson 
2990c896fe29Sbellard         do_not_remove:
2991c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
299225f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
299325f49c5fSRichard Henderson 
299425f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
299525f49c5fSRichard Henderson                 op->output_pref[i] = *la_temp_pref(ts);
299625f49c5fSRichard Henderson 
299725f49c5fSRichard Henderson                 /* Output args are dead.  */
299825f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2999a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
30006b64b624SAurelien Jarno                 }
300125f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
3002a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
30039c43b68dSAurelien Jarno                 }
300425f49c5fSRichard Henderson                 ts->state = TS_DEAD;
300525f49c5fSRichard Henderson                 la_reset_pref(ts);
3006c896fe29Sbellard             }
3007c896fe29Sbellard 
300825f49c5fSRichard Henderson             /* If end of basic block, update.  */
3009ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
3010ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
3011b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_COND_BRANCH) {
3012b4cb76e6SRichard Henderson                 la_bb_sync(s, nb_globals, nb_temps);
3013ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
30142616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
30153d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
3016f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
301725f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
301825f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
301925f49c5fSRichard Henderson                 }
3020c896fe29Sbellard             }
3021c896fe29Sbellard 
302225f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
3023866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
302425f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
302525f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
3026a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
3027c896fe29Sbellard                 }
3028c19f47bfSAurelien Jarno             }
302925f49c5fSRichard Henderson 
303025f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
3031c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
303225f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
303325f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
303425f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
303525f49c5fSRichard Henderson                        all regs for the type.  */
303625f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
303725f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
303825f49c5fSRichard Henderson                 }
303925f49c5fSRichard Henderson             }
304025f49c5fSRichard Henderson 
304125f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
304225f49c5fSRichard Henderson             switch (opc) {
304325f49c5fSRichard Henderson             case INDEX_op_mov_i32:
304425f49c5fSRichard Henderson             case INDEX_op_mov_i64:
304525f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
304625f49c5fSRichard Henderson                    have proper constraints.  That said, special case
304725f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
304825f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
304925f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
305025f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
305125f49c5fSRichard Henderson                 }
305225f49c5fSRichard Henderson                 break;
305325f49c5fSRichard Henderson 
305425f49c5fSRichard Henderson             default:
305525f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
305625f49c5fSRichard Henderson                     const TCGArgConstraint *ct = &def->args_ct[i];
305725f49c5fSRichard Henderson                     TCGRegSet set, *pset;
305825f49c5fSRichard Henderson 
305925f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
306025f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
306125f49c5fSRichard Henderson                     set = *pset;
306225f49c5fSRichard Henderson 
30639be0d080SRichard Henderson                     set &= ct->regs;
3064bc2b17e6SRichard Henderson                     if (ct->ialias) {
306525f49c5fSRichard Henderson                         set &= op->output_pref[ct->alias_index];
306625f49c5fSRichard Henderson                     }
306725f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
306825f49c5fSRichard Henderson                     if (set == 0) {
30699be0d080SRichard Henderson                         set = ct->regs;
307025f49c5fSRichard Henderson                     }
307125f49c5fSRichard Henderson                     *pset = set;
307225f49c5fSRichard Henderson                 }
307325f49c5fSRichard Henderson                 break;
3074c896fe29Sbellard             }
3075c896fe29Sbellard             break;
3076c896fe29Sbellard         }
3077bee158cbSRichard Henderson         op->life = arg_life;
3078c896fe29Sbellard     }
30791ff0a2c5SEvgeny Voevodin }
3080c896fe29Sbellard 
30815a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
3082b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s)
30835a18407fSRichard Henderson {
30845a18407fSRichard Henderson     int nb_globals = s->nb_globals;
308515fa08f8SRichard Henderson     int nb_temps, i;
30865a18407fSRichard Henderson     bool changes = false;
308715fa08f8SRichard Henderson     TCGOp *op, *op_next;
30885a18407fSRichard Henderson 
30895a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
30905a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
30915a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
30925a18407fSRichard Henderson         if (its->indirect_reg) {
30935a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
30945a18407fSRichard Henderson             dts->type = its->type;
30955a18407fSRichard Henderson             dts->base_type = its->base_type;
3096b83eabeaSRichard Henderson             its->state_ptr = dts;
3097b83eabeaSRichard Henderson         } else {
3098b83eabeaSRichard Henderson             its->state_ptr = NULL;
30995a18407fSRichard Henderson         }
3100b83eabeaSRichard Henderson         /* All globals begin dead.  */
3101b83eabeaSRichard Henderson         its->state = TS_DEAD;
31025a18407fSRichard Henderson     }
3103b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
3104b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
3105b83eabeaSRichard Henderson         its->state_ptr = NULL;
3106b83eabeaSRichard Henderson         its->state = TS_DEAD;
3107b83eabeaSRichard Henderson     }
31085a18407fSRichard Henderson 
310915fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
31105a18407fSRichard Henderson         TCGOpcode opc = op->opc;
31115a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
31125a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
31135a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
3114b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
31155a18407fSRichard Henderson 
31165a18407fSRichard Henderson         if (opc == INDEX_op_call) {
3117cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
3118cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
3119efee3746SRichard Henderson             call_flags = op->args[nb_oargs + nb_iargs + 1];
31205a18407fSRichard Henderson         } else {
31215a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
31225a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
31235a18407fSRichard Henderson 
31245a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
3125b4cb76e6SRichard Henderson             if (def->flags & TCG_OPF_COND_BRANCH) {
3126b4cb76e6SRichard Henderson                 /* Like reading globals: sync_globals */
3127b4cb76e6SRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
3128b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
31295a18407fSRichard Henderson                 /* Like writing globals: save_globals */
31305a18407fSRichard Henderson                 call_flags = 0;
31315a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
31325a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
31335a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
31345a18407fSRichard Henderson             } else {
31355a18407fSRichard Henderson                 /* No effect on globals.  */
31365a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
31375a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
31385a18407fSRichard Henderson             }
31395a18407fSRichard Henderson         }
31405a18407fSRichard Henderson 
31415a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
31425a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3143b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3144b83eabeaSRichard Henderson             if (arg_ts) {
3145b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3146b83eabeaSRichard Henderson                 if (dir_ts && arg_ts->state == TS_DEAD) {
3147b83eabeaSRichard Henderson                     TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
31485a18407fSRichard Henderson                                       ? INDEX_op_ld_i32
31495a18407fSRichard Henderson                                       : INDEX_op_ld_i64);
3150ac1043f6SEmilio G. Cota                     TCGOp *lop = tcg_op_insert_before(s, op, lopc);
31515a18407fSRichard Henderson 
3152b83eabeaSRichard Henderson                     lop->args[0] = temp_arg(dir_ts);
3153b83eabeaSRichard Henderson                     lop->args[1] = temp_arg(arg_ts->mem_base);
3154b83eabeaSRichard Henderson                     lop->args[2] = arg_ts->mem_offset;
31555a18407fSRichard Henderson 
31565a18407fSRichard Henderson                     /* Loaded, but synced with memory.  */
3157b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
31585a18407fSRichard Henderson                 }
31595a18407fSRichard Henderson             }
31605a18407fSRichard Henderson         }
31615a18407fSRichard Henderson 
31625a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
31635a18407fSRichard Henderson            No action is required except keeping temp_state up to date
31645a18407fSRichard Henderson            so that we reload when needed.  */
31655a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3166b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3167b83eabeaSRichard Henderson             if (arg_ts) {
3168b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3169b83eabeaSRichard Henderson                 if (dir_ts) {
3170b83eabeaSRichard Henderson                     op->args[i] = temp_arg(dir_ts);
31715a18407fSRichard Henderson                     changes = true;
31725a18407fSRichard Henderson                     if (IS_DEAD_ARG(i)) {
3173b83eabeaSRichard Henderson                         arg_ts->state = TS_DEAD;
31745a18407fSRichard Henderson                     }
31755a18407fSRichard Henderson                 }
31765a18407fSRichard Henderson             }
31775a18407fSRichard Henderson         }
31785a18407fSRichard Henderson 
31795a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
31805a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
31815a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
31825a18407fSRichard Henderson             /* Nothing to do */
31835a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
31845a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
31855a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
31865a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
3187b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3188b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3189b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
31905a18407fSRichard Henderson             }
31915a18407fSRichard Henderson         } else {
31925a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
31935a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
31945a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
3195b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3196b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3197b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
31985a18407fSRichard Henderson             }
31995a18407fSRichard Henderson         }
32005a18407fSRichard Henderson 
32015a18407fSRichard Henderson         /* Outputs become available.  */
320261f15c48SRichard Henderson         if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) {
320361f15c48SRichard Henderson             arg_ts = arg_temp(op->args[0]);
320461f15c48SRichard Henderson             dir_ts = arg_ts->state_ptr;
320561f15c48SRichard Henderson             if (dir_ts) {
320661f15c48SRichard Henderson                 op->args[0] = temp_arg(dir_ts);
320761f15c48SRichard Henderson                 changes = true;
320861f15c48SRichard Henderson 
320961f15c48SRichard Henderson                 /* The output is now live and modified.  */
321061f15c48SRichard Henderson                 arg_ts->state = 0;
321161f15c48SRichard Henderson 
321261f15c48SRichard Henderson                 if (NEED_SYNC_ARG(0)) {
321361f15c48SRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
321461f15c48SRichard Henderson                                       ? INDEX_op_st_i32
321561f15c48SRichard Henderson                                       : INDEX_op_st_i64);
321661f15c48SRichard Henderson                     TCGOp *sop = tcg_op_insert_after(s, op, sopc);
321761f15c48SRichard Henderson                     TCGTemp *out_ts = dir_ts;
321861f15c48SRichard Henderson 
321961f15c48SRichard Henderson                     if (IS_DEAD_ARG(0)) {
322061f15c48SRichard Henderson                         out_ts = arg_temp(op->args[1]);
322161f15c48SRichard Henderson                         arg_ts->state = TS_DEAD;
322261f15c48SRichard Henderson                         tcg_op_remove(s, op);
322361f15c48SRichard Henderson                     } else {
322461f15c48SRichard Henderson                         arg_ts->state = TS_MEM;
322561f15c48SRichard Henderson                     }
322661f15c48SRichard Henderson 
322761f15c48SRichard Henderson                     sop->args[0] = temp_arg(out_ts);
322861f15c48SRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
322961f15c48SRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
323061f15c48SRichard Henderson                 } else {
323161f15c48SRichard Henderson                     tcg_debug_assert(!IS_DEAD_ARG(0));
323261f15c48SRichard Henderson                 }
323361f15c48SRichard Henderson             }
323461f15c48SRichard Henderson         } else {
32355a18407fSRichard Henderson             for (i = 0; i < nb_oargs; i++) {
3236b83eabeaSRichard Henderson                 arg_ts = arg_temp(op->args[i]);
3237b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3238b83eabeaSRichard Henderson                 if (!dir_ts) {
32395a18407fSRichard Henderson                     continue;
32405a18407fSRichard Henderson                 }
3241b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
32425a18407fSRichard Henderson                 changes = true;
32435a18407fSRichard Henderson 
32445a18407fSRichard Henderson                 /* The output is now live and modified.  */
3245b83eabeaSRichard Henderson                 arg_ts->state = 0;
32465a18407fSRichard Henderson 
32475a18407fSRichard Henderson                 /* Sync outputs upon their last write.  */
32485a18407fSRichard Henderson                 if (NEED_SYNC_ARG(i)) {
3249b83eabeaSRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
32505a18407fSRichard Henderson                                       ? INDEX_op_st_i32
32515a18407fSRichard Henderson                                       : INDEX_op_st_i64);
3252ac1043f6SEmilio G. Cota                     TCGOp *sop = tcg_op_insert_after(s, op, sopc);
32535a18407fSRichard Henderson 
3254b83eabeaSRichard Henderson                     sop->args[0] = temp_arg(dir_ts);
3255b83eabeaSRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
3256b83eabeaSRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
32575a18407fSRichard Henderson 
3258b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
32595a18407fSRichard Henderson                 }
32605a18407fSRichard Henderson                 /* Drop outputs that are dead.  */
32615a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3262b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
32635a18407fSRichard Henderson                 }
32645a18407fSRichard Henderson             }
32655a18407fSRichard Henderson         }
326661f15c48SRichard Henderson     }
32675a18407fSRichard Henderson 
32685a18407fSRichard Henderson     return changes;
32695a18407fSRichard Henderson }
32705a18407fSRichard Henderson 
32718d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
3272c896fe29Sbellard static void dump_regs(TCGContext *s)
3273c896fe29Sbellard {
3274c896fe29Sbellard     TCGTemp *ts;
3275c896fe29Sbellard     int i;
3276c896fe29Sbellard     char buf[64];
3277c896fe29Sbellard 
3278c896fe29Sbellard     for(i = 0; i < s->nb_temps; i++) {
3279c896fe29Sbellard         ts = &s->temps[i];
328043439139SRichard Henderson         printf("  %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3281c896fe29Sbellard         switch(ts->val_type) {
3282c896fe29Sbellard         case TEMP_VAL_REG:
3283c896fe29Sbellard             printf("%s", tcg_target_reg_names[ts->reg]);
3284c896fe29Sbellard             break;
3285c896fe29Sbellard         case TEMP_VAL_MEM:
3286b3a62939SRichard Henderson             printf("%d(%s)", (int)ts->mem_offset,
3287b3a62939SRichard Henderson                    tcg_target_reg_names[ts->mem_base->reg]);
3288c896fe29Sbellard             break;
3289c896fe29Sbellard         case TEMP_VAL_CONST:
3290bdb38b95SRichard Henderson             printf("$0x%" PRIx64, ts->val);
3291c896fe29Sbellard             break;
3292c896fe29Sbellard         case TEMP_VAL_DEAD:
3293c896fe29Sbellard             printf("D");
3294c896fe29Sbellard             break;
3295c896fe29Sbellard         default:
3296c896fe29Sbellard             printf("???");
3297c896fe29Sbellard             break;
3298c896fe29Sbellard         }
3299c896fe29Sbellard         printf("\n");
3300c896fe29Sbellard     }
3301c896fe29Sbellard 
3302c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
3303f8b2f202SRichard Henderson         if (s->reg_to_temp[i] != NULL) {
3304c896fe29Sbellard             printf("%s: %s\n",
3305c896fe29Sbellard                    tcg_target_reg_names[i],
3306f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i]));
3307c896fe29Sbellard         }
3308c896fe29Sbellard     }
3309c896fe29Sbellard }
3310c896fe29Sbellard 
3311c896fe29Sbellard static void check_regs(TCGContext *s)
3312c896fe29Sbellard {
3313869938aeSRichard Henderson     int reg;
3314b6638662SRichard Henderson     int k;
3315c896fe29Sbellard     TCGTemp *ts;
3316c896fe29Sbellard     char buf[64];
3317c896fe29Sbellard 
3318c896fe29Sbellard     for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
3319f8b2f202SRichard Henderson         ts = s->reg_to_temp[reg];
3320f8b2f202SRichard Henderson         if (ts != NULL) {
3321f8b2f202SRichard Henderson             if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) {
3322c896fe29Sbellard                 printf("Inconsistency for register %s:\n",
3323c896fe29Sbellard                        tcg_target_reg_names[reg]);
3324b03cce8eSbellard                 goto fail;
3325c896fe29Sbellard             }
3326c896fe29Sbellard         }
3327c896fe29Sbellard     }
3328c896fe29Sbellard     for (k = 0; k < s->nb_temps; k++) {
3329c896fe29Sbellard         ts = &s->temps[k];
3330ee17db83SRichard Henderson         if (ts->val_type == TEMP_VAL_REG
3331ee17db83SRichard Henderson             && ts->kind != TEMP_FIXED
3332f8b2f202SRichard Henderson             && s->reg_to_temp[ts->reg] != ts) {
3333c896fe29Sbellard             printf("Inconsistency for temp %s:\n",
3334f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3335b03cce8eSbellard         fail:
3336c896fe29Sbellard             printf("reg state:\n");
3337c896fe29Sbellard             dump_regs(s);
3338c896fe29Sbellard             tcg_abort();
3339c896fe29Sbellard         }
3340c896fe29Sbellard     }
3341c896fe29Sbellard }
3342c896fe29Sbellard #endif
3343c896fe29Sbellard 
33442272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
3345c896fe29Sbellard {
33469b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64)
33479b9c37c3SRichard Henderson     /* Sparc64 stack is accessed with offset of 2047 */
3348b591dc59SBlue Swirl     s->current_frame_offset = (s->current_frame_offset +
3349b591dc59SBlue Swirl                                (tcg_target_long)sizeof(tcg_target_long) - 1) &
3350b591dc59SBlue Swirl         ~(sizeof(tcg_target_long) - 1);
3351f44c9960SBlue Swirl #endif
3352b591dc59SBlue Swirl     if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
3353b591dc59SBlue Swirl         s->frame_end) {
33545ff9d6a4Sbellard         tcg_abort();
3355b591dc59SBlue Swirl     }
3356c896fe29Sbellard     ts->mem_offset = s->current_frame_offset;
3357b3a62939SRichard Henderson     ts->mem_base = s->frame_temp;
3358c896fe29Sbellard     ts->mem_allocated = 1;
3359e2c6d1b4SRichard Henderson     s->current_frame_offset += sizeof(tcg_target_long);
3360c896fe29Sbellard }
3361c896fe29Sbellard 
3362b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
3363b3915dbbSRichard Henderson 
336459d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
336559d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
336659d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
3367c896fe29Sbellard {
3368c0522136SRichard Henderson     TCGTempVal new_type;
3369c0522136SRichard Henderson 
3370c0522136SRichard Henderson     switch (ts->kind) {
3371c0522136SRichard Henderson     case TEMP_FIXED:
337259d7c14eSRichard Henderson         return;
3373c0522136SRichard Henderson     case TEMP_GLOBAL:
3374c0522136SRichard Henderson     case TEMP_LOCAL:
3375c0522136SRichard Henderson         new_type = TEMP_VAL_MEM;
3376c0522136SRichard Henderson         break;
3377c0522136SRichard Henderson     case TEMP_NORMAL:
3378c0522136SRichard Henderson         new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD;
3379c0522136SRichard Henderson         break;
3380c0522136SRichard Henderson     case TEMP_CONST:
3381c0522136SRichard Henderson         new_type = TEMP_VAL_CONST;
3382c0522136SRichard Henderson         break;
3383c0522136SRichard Henderson     default:
3384c0522136SRichard Henderson         g_assert_not_reached();
338559d7c14eSRichard Henderson     }
338659d7c14eSRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
338759d7c14eSRichard Henderson         s->reg_to_temp[ts->reg] = NULL;
338859d7c14eSRichard Henderson     }
3389c0522136SRichard Henderson     ts->val_type = new_type;
339059d7c14eSRichard Henderson }
3391c896fe29Sbellard 
339259d7c14eSRichard Henderson /* Mark a temporary as dead.  */
339359d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
339459d7c14eSRichard Henderson {
339559d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
339659d7c14eSRichard Henderson }
339759d7c14eSRichard Henderson 
339859d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
339959d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
340059d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
340159d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
340298b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
340398b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
340459d7c14eSRichard Henderson {
3405c0522136SRichard Henderson     if (!temp_readonly(ts) && !ts->mem_coherent) {
34067f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
34072272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
340859d7c14eSRichard Henderson         }
340959d7c14eSRichard Henderson         switch (ts->val_type) {
341059d7c14eSRichard Henderson         case TEMP_VAL_CONST:
341159d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
341259d7c14eSRichard Henderson                require it later in a register, so attempt to store the
341359d7c14eSRichard Henderson                constant to memory directly.  */
341459d7c14eSRichard Henderson             if (free_or_dead
341559d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
341659d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
341759d7c14eSRichard Henderson                 break;
341859d7c14eSRichard Henderson             }
341959d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
342098b4e186SRichard Henderson                       allocated_regs, preferred_regs);
342159d7c14eSRichard Henderson             /* fallthrough */
342259d7c14eSRichard Henderson 
342359d7c14eSRichard Henderson         case TEMP_VAL_REG:
342459d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
342559d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
342659d7c14eSRichard Henderson             break;
342759d7c14eSRichard Henderson 
342859d7c14eSRichard Henderson         case TEMP_VAL_MEM:
342959d7c14eSRichard Henderson             break;
343059d7c14eSRichard Henderson 
343159d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
343259d7c14eSRichard Henderson         default:
343359d7c14eSRichard Henderson             tcg_abort();
3434c896fe29Sbellard         }
34357f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
34367f6ceedfSAurelien Jarno     }
343759d7c14eSRichard Henderson     if (free_or_dead) {
343859d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
343959d7c14eSRichard Henderson     }
344059d7c14eSRichard Henderson }
34417f6ceedfSAurelien Jarno 
34427f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
3443b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
34447f6ceedfSAurelien Jarno {
3445f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
3446f8b2f202SRichard Henderson     if (ts != NULL) {
344798b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
3448c896fe29Sbellard     }
3449c896fe29Sbellard }
3450c896fe29Sbellard 
3451b016486eSRichard Henderson /**
3452b016486eSRichard Henderson  * tcg_reg_alloc:
3453b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
3454b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
3455b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
3456b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
3457b016486eSRichard Henderson  *
3458b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
3459b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
3460b016486eSRichard Henderson  */
3461b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
3462b016486eSRichard Henderson                             TCGRegSet allocated_regs,
3463b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
3464c896fe29Sbellard {
3465b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
3466b016486eSRichard Henderson     TCGRegSet reg_ct[2];
346791478cefSRichard Henderson     const int *order;
3468c896fe29Sbellard 
3469b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
3470b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
3471b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
3472b016486eSRichard Henderson 
3473b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
3474b016486eSRichard Henderson        or if the preference made no difference.  */
3475b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
3476b016486eSRichard Henderson 
347791478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
3478c896fe29Sbellard 
3479b016486eSRichard Henderson     /* Try free registers, preferences first.  */
3480b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3481b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3482b016486eSRichard Henderson 
3483b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3484b016486eSRichard Henderson             /* One register in the set.  */
3485b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3486b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
3487c896fe29Sbellard                 return reg;
3488c896fe29Sbellard             }
3489b016486eSRichard Henderson         } else {
349091478cefSRichard Henderson             for (i = 0; i < n; i++) {
3491b016486eSRichard Henderson                 TCGReg reg = order[i];
3492b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
3493b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
3494b016486eSRichard Henderson                     return reg;
3495b016486eSRichard Henderson                 }
3496b016486eSRichard Henderson             }
3497b016486eSRichard Henderson         }
3498b016486eSRichard Henderson     }
3499b016486eSRichard Henderson 
3500b016486eSRichard Henderson     /* We must spill something.  */
3501b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3502b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3503b016486eSRichard Henderson 
3504b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3505b016486eSRichard Henderson             /* One register in the set.  */
3506b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3507b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
3508c896fe29Sbellard             return reg;
3509b016486eSRichard Henderson         } else {
3510b016486eSRichard Henderson             for (i = 0; i < n; i++) {
3511b016486eSRichard Henderson                 TCGReg reg = order[i];
3512b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
3513b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
3514b016486eSRichard Henderson                     return reg;
3515b016486eSRichard Henderson                 }
3516b016486eSRichard Henderson             }
3517c896fe29Sbellard         }
3518c896fe29Sbellard     }
3519c896fe29Sbellard 
3520c896fe29Sbellard     tcg_abort();
3521c896fe29Sbellard }
3522c896fe29Sbellard 
352340ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
352440ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
352540ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
3526b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
352740ae5c62SRichard Henderson {
352840ae5c62SRichard Henderson     TCGReg reg;
352940ae5c62SRichard Henderson 
353040ae5c62SRichard Henderson     switch (ts->val_type) {
353140ae5c62SRichard Henderson     case TEMP_VAL_REG:
353240ae5c62SRichard Henderson         return;
353340ae5c62SRichard Henderson     case TEMP_VAL_CONST:
3534b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3535b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
35360a6a8bc8SRichard Henderson         if (ts->type <= TCG_TYPE_I64) {
353740ae5c62SRichard Henderson             tcg_out_movi(s, ts->type, reg, ts->val);
35380a6a8bc8SRichard Henderson         } else {
35394e186175SRichard Henderson             uint64_t val = ts->val;
35404e186175SRichard Henderson             MemOp vece = MO_64;
35414e186175SRichard Henderson 
35424e186175SRichard Henderson             /*
35434e186175SRichard Henderson              * Find the minimal vector element that matches the constant.
35444e186175SRichard Henderson              * The targets will, in general, have to do this search anyway,
35454e186175SRichard Henderson              * do this generically.
35464e186175SRichard Henderson              */
35474e186175SRichard Henderson             if (val == dup_const(MO_8, val)) {
35484e186175SRichard Henderson                 vece = MO_8;
35494e186175SRichard Henderson             } else if (val == dup_const(MO_16, val)) {
35504e186175SRichard Henderson                 vece = MO_16;
35510b4286ddSRichard Henderson             } else if (val == dup_const(MO_32, val)) {
35524e186175SRichard Henderson                 vece = MO_32;
35534e186175SRichard Henderson             }
35544e186175SRichard Henderson 
35554e186175SRichard Henderson             tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val);
35560a6a8bc8SRichard Henderson         }
355740ae5c62SRichard Henderson         ts->mem_coherent = 0;
355840ae5c62SRichard Henderson         break;
355940ae5c62SRichard Henderson     case TEMP_VAL_MEM:
3560b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3561b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
356240ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
356340ae5c62SRichard Henderson         ts->mem_coherent = 1;
356440ae5c62SRichard Henderson         break;
356540ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
356640ae5c62SRichard Henderson     default:
356740ae5c62SRichard Henderson         tcg_abort();
356840ae5c62SRichard Henderson     }
356940ae5c62SRichard Henderson     ts->reg = reg;
357040ae5c62SRichard Henderson     ts->val_type = TEMP_VAL_REG;
357140ae5c62SRichard Henderson     s->reg_to_temp[reg] = ts;
357240ae5c62SRichard Henderson }
357340ae5c62SRichard Henderson 
357459d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
3575e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
357659d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
35771ad80729SAurelien Jarno {
35782c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
3579eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
3580e01fa97dSRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts));
35811ad80729SAurelien Jarno }
35821ad80729SAurelien Jarno 
35839814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
3584641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
3585641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
3586641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
3587641d5fbeSbellard {
3588ac3b8891SRichard Henderson     int i, n;
3589641d5fbeSbellard 
3590ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
3591b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
3592641d5fbeSbellard     }
3593e5097dc8Sbellard }
3594e5097dc8Sbellard 
35953d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
35963d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
35973d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
35983d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
35993d5c5f87SAurelien Jarno {
3600ac3b8891SRichard Henderson     int i, n;
36013d5c5f87SAurelien Jarno 
3602ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
360312b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
360412b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
3605ee17db83SRichard Henderson                          || ts->kind == TEMP_FIXED
360612b9b11aSRichard Henderson                          || ts->mem_coherent);
36073d5c5f87SAurelien Jarno     }
36083d5c5f87SAurelien Jarno }
36093d5c5f87SAurelien Jarno 
3610e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
3611e8996ee0Sbellard    all globals are stored at their canonical location. */
3612e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
3613e5097dc8Sbellard {
3614e5097dc8Sbellard     int i;
3615e5097dc8Sbellard 
3616c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
3617b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
3618c0522136SRichard Henderson 
3619c0522136SRichard Henderson         switch (ts->kind) {
3620c0522136SRichard Henderson         case TEMP_LOCAL:
3621b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
3622c0522136SRichard Henderson             break;
3623c0522136SRichard Henderson         case TEMP_NORMAL:
36242c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
3625eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
3626eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3627c0522136SRichard Henderson             break;
3628c0522136SRichard Henderson         case TEMP_CONST:
3629c0522136SRichard Henderson             /* Similarly, we should have freed any allocated register. */
3630c0522136SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_CONST);
3631c0522136SRichard Henderson             break;
3632c0522136SRichard Henderson         default:
3633c0522136SRichard Henderson             g_assert_not_reached();
3634c896fe29Sbellard         }
3635641d5fbeSbellard     }
3636e8996ee0Sbellard 
3637e8996ee0Sbellard     save_globals(s, allocated_regs);
3638c896fe29Sbellard }
3639c896fe29Sbellard 
3640bab1671fSRichard Henderson /*
3641b4cb76e6SRichard Henderson  * At a conditional branch, we assume all temporaries are dead and
3642b4cb76e6SRichard Henderson  * all globals and local temps are synced to their location.
3643b4cb76e6SRichard Henderson  */
3644b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
3645b4cb76e6SRichard Henderson {
3646b4cb76e6SRichard Henderson     sync_globals(s, allocated_regs);
3647b4cb76e6SRichard Henderson 
3648b4cb76e6SRichard Henderson     for (int i = s->nb_globals; i < s->nb_temps; i++) {
3649b4cb76e6SRichard Henderson         TCGTemp *ts = &s->temps[i];
3650b4cb76e6SRichard Henderson         /*
3651b4cb76e6SRichard Henderson          * The liveness analysis already ensures that temps are dead.
3652b4cb76e6SRichard Henderson          * Keep tcg_debug_asserts for safety.
3653b4cb76e6SRichard Henderson          */
3654c0522136SRichard Henderson         switch (ts->kind) {
3655c0522136SRichard Henderson         case TEMP_LOCAL:
3656b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
3657c0522136SRichard Henderson             break;
3658c0522136SRichard Henderson         case TEMP_NORMAL:
3659b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3660c0522136SRichard Henderson             break;
3661c0522136SRichard Henderson         case TEMP_CONST:
3662c0522136SRichard Henderson             break;
3663c0522136SRichard Henderson         default:
3664c0522136SRichard Henderson             g_assert_not_reached();
3665b4cb76e6SRichard Henderson         }
3666b4cb76e6SRichard Henderson     }
3667b4cb76e6SRichard Henderson }
3668b4cb76e6SRichard Henderson 
3669b4cb76e6SRichard Henderson /*
3670c58f4c97SRichard Henderson  * Specialized code generation for INDEX_op_mov_* with a constant.
3671bab1671fSRichard Henderson  */
36720fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
3673ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
3674ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
3675e8996ee0Sbellard {
3676d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3677e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
367859d7c14eSRichard Henderson 
367959d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
3680f8b2f202SRichard Henderson     if (ots->val_type == TEMP_VAL_REG) {
3681f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = NULL;
3682f8b2f202SRichard Henderson     }
3683e8996ee0Sbellard     ots->val_type = TEMP_VAL_CONST;
3684e8996ee0Sbellard     ots->val = val;
368559d7c14eSRichard Henderson     ots->mem_coherent = 0;
3686ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
3687ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
368859d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
3689f8bf00f1SRichard Henderson         temp_dead(s, ots);
36904c4e1ab2SAurelien Jarno     }
3691e8996ee0Sbellard }
3692e8996ee0Sbellard 
3693bab1671fSRichard Henderson /*
3694bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
3695bab1671fSRichard Henderson  */
3696dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
3697c896fe29Sbellard {
3698dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
369969e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
3700c896fe29Sbellard     TCGTemp *ts, *ots;
3701450445d5SRichard Henderson     TCGType otype, itype;
3702c896fe29Sbellard 
3703d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
370469e3706dSRichard Henderson     preferred_regs = op->output_pref[0];
370543439139SRichard Henderson     ots = arg_temp(op->args[0]);
370643439139SRichard Henderson     ts = arg_temp(op->args[1]);
3707450445d5SRichard Henderson 
3708d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3709e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
3710d63e3b6eSRichard Henderson 
3711450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
3712450445d5SRichard Henderson     otype = ots->type;
3713450445d5SRichard Henderson     itype = ts->type;
3714c896fe29Sbellard 
37150fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
37160fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
37170fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
37180fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
37190fe4fca4SPaolo Bonzini             temp_dead(s, ts);
37200fe4fca4SPaolo Bonzini         }
372169e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
37220fe4fca4SPaolo Bonzini         return;
37230fe4fca4SPaolo Bonzini     }
37240fe4fca4SPaolo Bonzini 
37250fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
37260fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
37270fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
37280fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
37290fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
373069e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
373169e3706dSRichard Henderson                   allocated_regs, preferred_regs);
3732c29c1d7eSAurelien Jarno     }
3733c29c1d7eSAurelien Jarno 
37340fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
3735d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
3736c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
3737c29c1d7eSAurelien Jarno            liveness analysis disabled). */
3738eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
3739c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
37402272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
3741c29c1d7eSAurelien Jarno         }
3742b3a62939SRichard Henderson         tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset);
3743c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
3744f8bf00f1SRichard Henderson             temp_dead(s, ts);
3745c29c1d7eSAurelien Jarno         }
3746f8bf00f1SRichard Henderson         temp_dead(s, ots);
3747e8996ee0Sbellard     } else {
3748ee17db83SRichard Henderson         if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) {
3749c29c1d7eSAurelien Jarno             /* the mov can be suppressed */
3750c29c1d7eSAurelien Jarno             if (ots->val_type == TEMP_VAL_REG) {
3751f8b2f202SRichard Henderson                 s->reg_to_temp[ots->reg] = NULL;
3752c896fe29Sbellard             }
3753c29c1d7eSAurelien Jarno             ots->reg = ts->reg;
3754f8bf00f1SRichard Henderson             temp_dead(s, ts);
3755c29c1d7eSAurelien Jarno         } else {
3756c29c1d7eSAurelien Jarno             if (ots->val_type != TEMP_VAL_REG) {
3757c29c1d7eSAurelien Jarno                 /* When allocating a new register, make sure to not spill the
3758c29c1d7eSAurelien Jarno                    input one. */
3759c29c1d7eSAurelien Jarno                 tcg_regset_set_reg(allocated_regs, ts->reg);
3760450445d5SRichard Henderson                 ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
376169e3706dSRichard Henderson                                          allocated_regs, preferred_regs,
3762b016486eSRichard Henderson                                          ots->indirect_base);
3763c29c1d7eSAurelien Jarno             }
376478113e83SRichard Henderson             if (!tcg_out_mov(s, otype, ots->reg, ts->reg)) {
3765240c08d0SRichard Henderson                 /*
3766240c08d0SRichard Henderson                  * Cross register class move not supported.
3767240c08d0SRichard Henderson                  * Store the source register into the destination slot
3768240c08d0SRichard Henderson                  * and leave the destination temp as TEMP_VAL_MEM.
3769240c08d0SRichard Henderson                  */
3770e01fa97dSRichard Henderson                 assert(!temp_readonly(ots));
3771240c08d0SRichard Henderson                 if (!ts->mem_allocated) {
3772240c08d0SRichard Henderson                     temp_allocate_frame(s, ots);
3773240c08d0SRichard Henderson                 }
3774240c08d0SRichard Henderson                 tcg_out_st(s, ts->type, ts->reg,
3775240c08d0SRichard Henderson                            ots->mem_base->reg, ots->mem_offset);
3776240c08d0SRichard Henderson                 ots->mem_coherent = 1;
3777240c08d0SRichard Henderson                 temp_free_or_dead(s, ots, -1);
3778240c08d0SRichard Henderson                 return;
377978113e83SRichard Henderson             }
3780c29c1d7eSAurelien Jarno         }
3781c896fe29Sbellard         ots->val_type = TEMP_VAL_REG;
3782c896fe29Sbellard         ots->mem_coherent = 0;
3783f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3784ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(0)) {
378598b4e186SRichard Henderson             temp_sync(s, ots, allocated_regs, 0, 0);
3786c29c1d7eSAurelien Jarno         }
3787ec7a869dSAurelien Jarno     }
3788c896fe29Sbellard }
3789c896fe29Sbellard 
3790bab1671fSRichard Henderson /*
3791bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
3792bab1671fSRichard Henderson  */
3793bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
3794bab1671fSRichard Henderson {
3795bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
3796bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
3797bab1671fSRichard Henderson     TCGTemp *its, *ots;
3798bab1671fSRichard Henderson     TCGType itype, vtype;
3799d6ecb4a9SRichard Henderson     intptr_t endian_fixup;
3800bab1671fSRichard Henderson     unsigned vece;
3801bab1671fSRichard Henderson     bool ok;
3802bab1671fSRichard Henderson 
3803bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
3804bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
3805bab1671fSRichard Henderson 
3806bab1671fSRichard Henderson     /* ENV should not be modified.  */
3807e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
3808bab1671fSRichard Henderson 
3809bab1671fSRichard Henderson     itype = its->type;
3810bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
3811bab1671fSRichard Henderson     vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
3812bab1671fSRichard Henderson 
3813bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
3814bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
3815bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
3816bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
3817bab1671fSRichard Henderson             temp_dead(s, its);
3818bab1671fSRichard Henderson         }
3819bab1671fSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, op->output_pref[0]);
3820bab1671fSRichard Henderson         return;
3821bab1671fSRichard Henderson     }
3822bab1671fSRichard Henderson 
38239be0d080SRichard Henderson     dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
38249be0d080SRichard Henderson     dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs;
3825bab1671fSRichard Henderson 
3826bab1671fSRichard Henderson     /* Allocate the output register now.  */
3827bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
3828bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
3829bab1671fSRichard Henderson 
3830bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
3831bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
3832bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
3833bab1671fSRichard Henderson         }
3834bab1671fSRichard Henderson         ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
3835bab1671fSRichard Henderson                                  op->output_pref[0], ots->indirect_base);
3836bab1671fSRichard Henderson         ots->val_type = TEMP_VAL_REG;
3837bab1671fSRichard Henderson         ots->mem_coherent = 0;
3838bab1671fSRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3839bab1671fSRichard Henderson     }
3840bab1671fSRichard Henderson 
3841bab1671fSRichard Henderson     switch (its->val_type) {
3842bab1671fSRichard Henderson     case TEMP_VAL_REG:
3843bab1671fSRichard Henderson         /*
3844bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
3845bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
3846bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
3847bab1671fSRichard Henderson          */
3848bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
3849bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
3850bab1671fSRichard Henderson                 goto done;
3851bab1671fSRichard Henderson             }
3852bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
3853bab1671fSRichard Henderson         }
3854bab1671fSRichard Henderson         if (!its->mem_coherent) {
3855bab1671fSRichard Henderson             /*
3856bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
3857bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
3858bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
3859bab1671fSRichard Henderson              */
3860bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
3861bab1671fSRichard Henderson                 break;
3862bab1671fSRichard Henderson             }
3863bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
3864bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
3865bab1671fSRichard Henderson         }
3866bab1671fSRichard Henderson         /* fall through */
3867bab1671fSRichard Henderson 
3868bab1671fSRichard Henderson     case TEMP_VAL_MEM:
3869d6ecb4a9SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
3870d6ecb4a9SRichard Henderson         endian_fixup = itype == TCG_TYPE_I32 ? 4 : 8;
3871d6ecb4a9SRichard Henderson         endian_fixup -= 1 << vece;
3872d6ecb4a9SRichard Henderson #else
3873d6ecb4a9SRichard Henderson         endian_fixup = 0;
3874d6ecb4a9SRichard Henderson #endif
3875d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
3876d6ecb4a9SRichard Henderson                              its->mem_offset + endian_fixup)) {
3877d6ecb4a9SRichard Henderson             goto done;
3878d6ecb4a9SRichard Henderson         }
3879bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
3880bab1671fSRichard Henderson         break;
3881bab1671fSRichard Henderson 
3882bab1671fSRichard Henderson     default:
3883bab1671fSRichard Henderson         g_assert_not_reached();
3884bab1671fSRichard Henderson     }
3885bab1671fSRichard Henderson 
3886bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
3887bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
3888bab1671fSRichard Henderson     tcg_debug_assert(ok);
3889bab1671fSRichard Henderson 
3890bab1671fSRichard Henderson  done:
3891bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
3892bab1671fSRichard Henderson         temp_dead(s, its);
3893bab1671fSRichard Henderson     }
3894bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
3895bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
3896bab1671fSRichard Henderson     }
3897bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
3898bab1671fSRichard Henderson         temp_dead(s, ots);
3899bab1671fSRichard Henderson     }
3900bab1671fSRichard Henderson }
3901bab1671fSRichard Henderson 
3902dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
3903c896fe29Sbellard {
3904dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3905dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
390682790a87SRichard Henderson     TCGRegSet i_allocated_regs;
390782790a87SRichard Henderson     TCGRegSet o_allocated_regs;
3908b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
3909b6638662SRichard Henderson     TCGReg reg;
3910c896fe29Sbellard     TCGArg arg;
3911c896fe29Sbellard     const TCGArgConstraint *arg_ct;
3912c896fe29Sbellard     TCGTemp *ts;
3913c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
3914c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
3915c896fe29Sbellard 
3916c896fe29Sbellard     nb_oargs = def->nb_oargs;
3917c896fe29Sbellard     nb_iargs = def->nb_iargs;
3918c896fe29Sbellard 
3919c896fe29Sbellard     /* copy constants */
3920c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
3921dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
3922c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
3923c896fe29Sbellard 
3924d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
3925d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
392682790a87SRichard Henderson 
3927c896fe29Sbellard     /* satisfy input constraints */
3928c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
3929d62816f2SRichard Henderson         TCGRegSet i_preferred_regs, o_preferred_regs;
3930d62816f2SRichard Henderson 
393166792f90SRichard Henderson         i = def->args_ct[nb_oargs + k].sort_index;
3932dd186292SRichard Henderson         arg = op->args[i];
3933c896fe29Sbellard         arg_ct = &def->args_ct[i];
393443439139SRichard Henderson         ts = arg_temp(arg);
393540ae5c62SRichard Henderson 
393640ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
393740ae5c62SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct)) {
3938c896fe29Sbellard             /* constant is OK for instruction */
3939c896fe29Sbellard             const_args[i] = 1;
3940c896fe29Sbellard             new_args[i] = ts->val;
3941d62816f2SRichard Henderson             continue;
3942c896fe29Sbellard         }
394340ae5c62SRichard Henderson 
3944d62816f2SRichard Henderson         i_preferred_regs = o_preferred_regs = 0;
3945bc2b17e6SRichard Henderson         if (arg_ct->ialias) {
3946d62816f2SRichard Henderson             o_preferred_regs = op->output_pref[arg_ct->alias_index];
3947c0522136SRichard Henderson 
3948c0522136SRichard Henderson             /*
3949c0522136SRichard Henderson              * If the input is readonly, then it cannot also be an
3950c0522136SRichard Henderson              * output and aliased to itself.  If the input is not
3951c0522136SRichard Henderson              * dead after the instruction, we must allocate a new
3952c0522136SRichard Henderson              * register and move it.
3953c0522136SRichard Henderson              */
3954c0522136SRichard Henderson             if (temp_readonly(ts) || !IS_DEAD_ARG(i)) {
3955c896fe29Sbellard                 goto allocate_in_reg;
3956c896fe29Sbellard             }
3957d62816f2SRichard Henderson 
3958c0522136SRichard Henderson             /*
3959c0522136SRichard Henderson              * Check if the current register has already been allocated
3960c0522136SRichard Henderson              * for another input aliased to an output.
3961c0522136SRichard Henderson              */
3962d62816f2SRichard Henderson             if (ts->val_type == TEMP_VAL_REG) {
3963d62816f2SRichard Henderson                 reg = ts->reg;
3964c0522136SRichard Henderson                 for (int k2 = 0; k2 < k; k2++) {
3965c0522136SRichard Henderson                     int i2 = def->args_ct[nb_oargs + k2].sort_index;
3966bc2b17e6SRichard Henderson                     if (def->args_ct[i2].ialias && reg == new_args[i2]) {
39677e1df267SAurelien Jarno                         goto allocate_in_reg;
39687e1df267SAurelien Jarno                     }
39697e1df267SAurelien Jarno                 }
39705ff9d6a4Sbellard             }
3971d62816f2SRichard Henderson             i_preferred_regs = o_preferred_regs;
3972866cb6cbSAurelien Jarno         }
3973d62816f2SRichard Henderson 
39749be0d080SRichard Henderson         temp_load(s, ts, arg_ct->regs, i_allocated_regs, i_preferred_regs);
3975c896fe29Sbellard         reg = ts->reg;
3976d62816f2SRichard Henderson 
3977c0522136SRichard Henderson         if (!tcg_regset_test_reg(arg_ct->regs, reg)) {
3978c896fe29Sbellard  allocate_in_reg:
3979c0522136SRichard Henderson             /*
3980c0522136SRichard Henderson              * Allocate a new register matching the constraint
3981c0522136SRichard Henderson              * and move the temporary register into it.
3982c0522136SRichard Henderson              */
3983d62816f2SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
3984d62816f2SRichard Henderson                       i_allocated_regs, 0);
39859be0d080SRichard Henderson             reg = tcg_reg_alloc(s, arg_ct->regs, i_allocated_regs,
3986d62816f2SRichard Henderson                                 o_preferred_regs, ts->indirect_base);
398778113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
3988240c08d0SRichard Henderson                 /*
3989240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
3990240c08d0SRichard Henderson                  * temp back to its slot and load from there.
3991240c08d0SRichard Henderson                  */
3992240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
3993240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
3994240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
399578113e83SRichard Henderson             }
3996c896fe29Sbellard         }
3997c896fe29Sbellard         new_args[i] = reg;
3998c896fe29Sbellard         const_args[i] = 0;
399982790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
4000c896fe29Sbellard     }
4001c896fe29Sbellard 
4002c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
4003866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
4004866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
400543439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4006c896fe29Sbellard         }
4007c896fe29Sbellard     }
4008c896fe29Sbellard 
4009b4cb76e6SRichard Henderson     if (def->flags & TCG_OPF_COND_BRANCH) {
4010b4cb76e6SRichard Henderson         tcg_reg_alloc_cbranch(s, i_allocated_regs);
4011b4cb76e6SRichard Henderson     } else if (def->flags & TCG_OPF_BB_END) {
401282790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
4013a52ad07eSAurelien Jarno     } else {
4014c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
4015b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
4016c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4017c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
401882790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
4019c896fe29Sbellard                 }
4020c896fe29Sbellard             }
40213d5c5f87SAurelien Jarno         }
40223d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
40233d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
40243d5c5f87SAurelien Jarno                an exception. */
402582790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
4026c896fe29Sbellard         }
4027c896fe29Sbellard 
4028c896fe29Sbellard         /* satisfy the output constraints */
4029c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
403066792f90SRichard Henderson             i = def->args_ct[k].sort_index;
4031dd186292SRichard Henderson             arg = op->args[i];
4032c896fe29Sbellard             arg_ct = &def->args_ct[i];
403343439139SRichard Henderson             ts = arg_temp(arg);
4034d63e3b6eSRichard Henderson 
4035d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
4036e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
4037d63e3b6eSRichard Henderson 
4038bc2b17e6SRichard Henderson             if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
40395ff9d6a4Sbellard                 reg = new_args[arg_ct->alias_index];
4040bc2b17e6SRichard Henderson             } else if (arg_ct->newreg) {
40419be0d080SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->regs,
404282790a87SRichard Henderson                                     i_allocated_regs | o_allocated_regs,
404369e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
4044c896fe29Sbellard             } else {
40459be0d080SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
404669e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
4047c896fe29Sbellard             }
404882790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
4049639368ddSAurelien Jarno             if (ts->val_type == TEMP_VAL_REG) {
4050f8b2f202SRichard Henderson                 s->reg_to_temp[ts->reg] = NULL;
4051639368ddSAurelien Jarno             }
4052c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
4053c896fe29Sbellard             ts->reg = reg;
4054d63e3b6eSRichard Henderson             /*
4055d63e3b6eSRichard Henderson              * Temp value is modified, so the value kept in memory is
4056d63e3b6eSRichard Henderson              * potentially not the same.
4057d63e3b6eSRichard Henderson              */
4058c896fe29Sbellard             ts->mem_coherent = 0;
4059f8b2f202SRichard Henderson             s->reg_to_temp[reg] = ts;
4060c896fe29Sbellard             new_args[i] = reg;
4061c896fe29Sbellard         }
4062e8996ee0Sbellard     }
4063c896fe29Sbellard 
4064c896fe29Sbellard     /* emit instruction */
4065d2fd745fSRichard Henderson     if (def->flags & TCG_OPF_VECTOR) {
4066d2fd745fSRichard Henderson         tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
4067d2fd745fSRichard Henderson                        new_args, const_args);
4068d2fd745fSRichard Henderson     } else {
4069dd186292SRichard Henderson         tcg_out_op(s, op->opc, new_args, const_args);
4070d2fd745fSRichard Henderson     }
4071c896fe29Sbellard 
4072c896fe29Sbellard     /* move the outputs in the correct register if needed */
4073c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
407443439139SRichard Henderson         ts = arg_temp(op->args[i]);
4075d63e3b6eSRichard Henderson 
4076d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
4077e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
4078d63e3b6eSRichard Henderson 
4079ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
408098b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
408159d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4082f8bf00f1SRichard Henderson             temp_dead(s, ts);
4083ec7a869dSAurelien Jarno         }
4084c896fe29Sbellard     }
4085c896fe29Sbellard }
4086c896fe29Sbellard 
4087*efe86b21SRichard Henderson static bool tcg_reg_alloc_dup2(TCGContext *s, const TCGOp *op)
4088*efe86b21SRichard Henderson {
4089*efe86b21SRichard Henderson     const TCGLifeData arg_life = op->life;
4090*efe86b21SRichard Henderson     TCGTemp *ots, *itsl, *itsh;
4091*efe86b21SRichard Henderson     TCGType vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
4092*efe86b21SRichard Henderson 
4093*efe86b21SRichard Henderson     /* This opcode is only valid for 32-bit hosts, for 64-bit elements. */
4094*efe86b21SRichard Henderson     tcg_debug_assert(TCG_TARGET_REG_BITS == 32);
4095*efe86b21SRichard Henderson     tcg_debug_assert(TCGOP_VECE(op) == MO_64);
4096*efe86b21SRichard Henderson 
4097*efe86b21SRichard Henderson     ots = arg_temp(op->args[0]);
4098*efe86b21SRichard Henderson     itsl = arg_temp(op->args[1]);
4099*efe86b21SRichard Henderson     itsh = arg_temp(op->args[2]);
4100*efe86b21SRichard Henderson 
4101*efe86b21SRichard Henderson     /* ENV should not be modified.  */
4102*efe86b21SRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
4103*efe86b21SRichard Henderson 
4104*efe86b21SRichard Henderson     /* Allocate the output register now.  */
4105*efe86b21SRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
4106*efe86b21SRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
4107*efe86b21SRichard Henderson         TCGRegSet dup_out_regs =
4108*efe86b21SRichard Henderson             tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
4109*efe86b21SRichard Henderson 
4110*efe86b21SRichard Henderson         /* Make sure to not spill the input registers. */
4111*efe86b21SRichard Henderson         if (!IS_DEAD_ARG(1) && itsl->val_type == TEMP_VAL_REG) {
4112*efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsl->reg);
4113*efe86b21SRichard Henderson         }
4114*efe86b21SRichard Henderson         if (!IS_DEAD_ARG(2) && itsh->val_type == TEMP_VAL_REG) {
4115*efe86b21SRichard Henderson             tcg_regset_set_reg(allocated_regs, itsh->reg);
4116*efe86b21SRichard Henderson         }
4117*efe86b21SRichard Henderson 
4118*efe86b21SRichard Henderson         ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
4119*efe86b21SRichard Henderson                                  op->output_pref[0], ots->indirect_base);
4120*efe86b21SRichard Henderson         ots->val_type = TEMP_VAL_REG;
4121*efe86b21SRichard Henderson         ots->mem_coherent = 0;
4122*efe86b21SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
4123*efe86b21SRichard Henderson     }
4124*efe86b21SRichard Henderson 
4125*efe86b21SRichard Henderson     /* Promote dup2 of immediates to dupi_vec. */
4126*efe86b21SRichard Henderson     if (itsl->val_type == TEMP_VAL_CONST && itsh->val_type == TEMP_VAL_CONST) {
4127*efe86b21SRichard Henderson         uint64_t val = deposit64(itsl->val, 32, 32, itsh->val);
4128*efe86b21SRichard Henderson         MemOp vece = MO_64;
4129*efe86b21SRichard Henderson 
4130*efe86b21SRichard Henderson         if (val == dup_const(MO_8, val)) {
4131*efe86b21SRichard Henderson             vece = MO_8;
4132*efe86b21SRichard Henderson         } else if (val == dup_const(MO_16, val)) {
4133*efe86b21SRichard Henderson             vece = MO_16;
4134*efe86b21SRichard Henderson         } else if (val == dup_const(MO_32, val)) {
4135*efe86b21SRichard Henderson             vece = MO_32;
4136*efe86b21SRichard Henderson         }
4137*efe86b21SRichard Henderson 
4138*efe86b21SRichard Henderson         tcg_out_dupi_vec(s, vtype, vece, ots->reg, val);
4139*efe86b21SRichard Henderson         goto done;
4140*efe86b21SRichard Henderson     }
4141*efe86b21SRichard Henderson 
4142*efe86b21SRichard Henderson     /* If the two inputs form one 64-bit value, try dupm_vec. */
4143*efe86b21SRichard Henderson     if (itsl + 1 == itsh && itsl->base_type == TCG_TYPE_I64) {
4144*efe86b21SRichard Henderson         if (!itsl->mem_coherent) {
4145*efe86b21SRichard Henderson             temp_sync(s, itsl, s->reserved_regs, 0, 0);
4146*efe86b21SRichard Henderson         }
4147*efe86b21SRichard Henderson         if (!itsh->mem_coherent) {
4148*efe86b21SRichard Henderson             temp_sync(s, itsh, s->reserved_regs, 0, 0);
4149*efe86b21SRichard Henderson         }
4150*efe86b21SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
4151*efe86b21SRichard Henderson         TCGTemp *its = itsh;
4152*efe86b21SRichard Henderson #else
4153*efe86b21SRichard Henderson         TCGTemp *its = itsl;
4154*efe86b21SRichard Henderson #endif
4155*efe86b21SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, MO_64, ots->reg,
4156*efe86b21SRichard Henderson                              its->mem_base->reg, its->mem_offset)) {
4157*efe86b21SRichard Henderson             goto done;
4158*efe86b21SRichard Henderson         }
4159*efe86b21SRichard Henderson     }
4160*efe86b21SRichard Henderson 
4161*efe86b21SRichard Henderson     /* Fall back to generic expansion. */
4162*efe86b21SRichard Henderson     return false;
4163*efe86b21SRichard Henderson 
4164*efe86b21SRichard Henderson  done:
4165*efe86b21SRichard Henderson     if (IS_DEAD_ARG(1)) {
4166*efe86b21SRichard Henderson         temp_dead(s, itsl);
4167*efe86b21SRichard Henderson     }
4168*efe86b21SRichard Henderson     if (IS_DEAD_ARG(2)) {
4169*efe86b21SRichard Henderson         temp_dead(s, itsh);
4170*efe86b21SRichard Henderson     }
4171*efe86b21SRichard Henderson     if (NEED_SYNC_ARG(0)) {
4172*efe86b21SRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, IS_DEAD_ARG(0));
4173*efe86b21SRichard Henderson     } else if (IS_DEAD_ARG(0)) {
4174*efe86b21SRichard Henderson         temp_dead(s, ots);
4175*efe86b21SRichard Henderson     }
4176*efe86b21SRichard Henderson     return true;
4177*efe86b21SRichard Henderson }
4178*efe86b21SRichard Henderson 
4179b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP
4180b03cce8eSbellard #define STACK_DIR(x) (-(x))
4181b03cce8eSbellard #else
4182b03cce8eSbellard #define STACK_DIR(x) (x)
4183b03cce8eSbellard #endif
4184b03cce8eSbellard 
4185dd186292SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
4186c896fe29Sbellard {
4187cd9090aaSRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
4188cd9090aaSRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
4189dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
4190b6638662SRichard Henderson     int flags, nb_regs, i;
4191b6638662SRichard Henderson     TCGReg reg;
4192cf066674SRichard Henderson     TCGArg arg;
4193c896fe29Sbellard     TCGTemp *ts;
4194d3452f1fSRichard Henderson     intptr_t stack_offset;
4195d3452f1fSRichard Henderson     size_t call_stack_size;
4196cf066674SRichard Henderson     tcg_insn_unit *func_addr;
4197cf066674SRichard Henderson     int allocate_args;
4198c896fe29Sbellard     TCGRegSet allocated_regs;
4199c896fe29Sbellard 
4200dd186292SRichard Henderson     func_addr = (tcg_insn_unit *)(intptr_t)op->args[nb_oargs + nb_iargs];
4201dd186292SRichard Henderson     flags = op->args[nb_oargs + nb_iargs + 1];
4202c896fe29Sbellard 
42036e17d0c5SStefan Weil     nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
4204c45cb8bbSRichard Henderson     if (nb_regs > nb_iargs) {
4205c45cb8bbSRichard Henderson         nb_regs = nb_iargs;
4206cf066674SRichard Henderson     }
4207c896fe29Sbellard 
4208c896fe29Sbellard     /* assign stack slots first */
4209c45cb8bbSRichard Henderson     call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long);
4210c896fe29Sbellard     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
4211c896fe29Sbellard         ~(TCG_TARGET_STACK_ALIGN - 1);
4212b03cce8eSbellard     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
4213b03cce8eSbellard     if (allocate_args) {
4214345649c0SBlue Swirl         /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
4215345649c0SBlue Swirl            preallocate call stack */
4216345649c0SBlue Swirl         tcg_abort();
4217b03cce8eSbellard     }
421839cf05d3Sbellard 
421939cf05d3Sbellard     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
4220c45cb8bbSRichard Henderson     for (i = nb_regs; i < nb_iargs; i++) {
4221dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
422239cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP
422339cf05d3Sbellard         stack_offset -= sizeof(tcg_target_long);
422439cf05d3Sbellard #endif
422539cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
422643439139SRichard Henderson             ts = arg_temp(arg);
422740ae5c62SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
4228b722452aSRichard Henderson                       s->reserved_regs, 0);
4229e4d5434cSblueswir1             tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
423039cf05d3Sbellard         }
423139cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP
423239cf05d3Sbellard         stack_offset += sizeof(tcg_target_long);
423339cf05d3Sbellard #endif
4234c896fe29Sbellard     }
4235c896fe29Sbellard 
4236c896fe29Sbellard     /* assign input registers */
4237d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
4238c896fe29Sbellard     for (i = 0; i < nb_regs; i++) {
4239dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
424039cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
424143439139SRichard Henderson             ts = arg_temp(arg);
4242c896fe29Sbellard             reg = tcg_target_call_iarg_regs[i];
424340ae5c62SRichard Henderson 
4244c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
4245c896fe29Sbellard                 if (ts->reg != reg) {
42464250da10SRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
424778113e83SRichard Henderson                     if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4248240c08d0SRichard Henderson                         /*
4249240c08d0SRichard Henderson                          * Cross register class move not supported.  Sync the
4250240c08d0SRichard Henderson                          * temp back to its slot and load from there.
4251240c08d0SRichard Henderson                          */
4252240c08d0SRichard Henderson                         temp_sync(s, ts, allocated_regs, 0, 0);
4253240c08d0SRichard Henderson                         tcg_out_ld(s, ts->type, reg,
4254240c08d0SRichard Henderson                                    ts->mem_base->reg, ts->mem_offset);
425578113e83SRichard Henderson                     }
4256c896fe29Sbellard                 }
4257c896fe29Sbellard             } else {
4258ccb1bb66SRichard Henderson                 TCGRegSet arg_set = 0;
425940ae5c62SRichard Henderson 
42604250da10SRichard Henderson                 tcg_reg_free(s, reg, allocated_regs);
426140ae5c62SRichard Henderson                 tcg_regset_set_reg(arg_set, reg);
4262b722452aSRichard Henderson                 temp_load(s, ts, arg_set, allocated_regs, 0);
4263c896fe29Sbellard             }
426440ae5c62SRichard Henderson 
4265c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
4266c896fe29Sbellard         }
426739cf05d3Sbellard     }
4268c896fe29Sbellard 
4269c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
4270866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4271866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
427243439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4273c896fe29Sbellard         }
4274c896fe29Sbellard     }
4275c896fe29Sbellard 
4276c896fe29Sbellard     /* clobber call registers */
4277c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4278c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
4279b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
4280c896fe29Sbellard         }
4281c896fe29Sbellard     }
4282c896fe29Sbellard 
428378505279SAurelien Jarno     /* Save globals if they might be written by the helper, sync them if
428478505279SAurelien Jarno        they might be read. */
428578505279SAurelien Jarno     if (flags & TCG_CALL_NO_READ_GLOBALS) {
428678505279SAurelien Jarno         /* Nothing to do */
428778505279SAurelien Jarno     } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) {
428878505279SAurelien Jarno         sync_globals(s, allocated_regs);
428978505279SAurelien Jarno     } else {
4290e8996ee0Sbellard         save_globals(s, allocated_regs);
4291b9c18f56Saurel32     }
4292c896fe29Sbellard 
4293cf066674SRichard Henderson     tcg_out_call(s, func_addr);
4294c896fe29Sbellard 
4295c896fe29Sbellard     /* assign output registers and emit moves if needed */
4296c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
4297dd186292SRichard Henderson         arg = op->args[i];
429843439139SRichard Henderson         ts = arg_temp(arg);
4299d63e3b6eSRichard Henderson 
4300d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
4301e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
4302d63e3b6eSRichard Henderson 
4303c896fe29Sbellard         reg = tcg_target_call_oarg_regs[i];
4304eabb7b91SAurelien Jarno         tcg_debug_assert(s->reg_to_temp[reg] == NULL);
4305639368ddSAurelien Jarno         if (ts->val_type == TEMP_VAL_REG) {
4306f8b2f202SRichard Henderson             s->reg_to_temp[ts->reg] = NULL;
4307639368ddSAurelien Jarno         }
4308c896fe29Sbellard         ts->val_type = TEMP_VAL_REG;
4309c896fe29Sbellard         ts->reg = reg;
4310c896fe29Sbellard         ts->mem_coherent = 0;
4311f8b2f202SRichard Henderson         s->reg_to_temp[reg] = ts;
4312ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
431398b4e186SRichard Henderson             temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i));
431459d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4315f8bf00f1SRichard Henderson             temp_dead(s, ts);
4316c896fe29Sbellard         }
4317c896fe29Sbellard     }
43188c11ad25SAurelien Jarno }
4319c896fe29Sbellard 
4320c896fe29Sbellard #ifdef CONFIG_PROFILER
4321c896fe29Sbellard 
4322c3fac113SEmilio G. Cota /* avoid copy/paste errors */
4323c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field)                       \
4324c3fac113SEmilio G. Cota     do {                                                \
4325d73415a3SStefan Hajnoczi         (to)->field += qatomic_read(&((from)->field));  \
4326c3fac113SEmilio G. Cota     } while (0)
4327c896fe29Sbellard 
4328c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field)                                       \
4329c3fac113SEmilio G. Cota     do {                                                                \
4330d73415a3SStefan Hajnoczi         typeof((from)->field) val__ = qatomic_read(&((from)->field));   \
4331c3fac113SEmilio G. Cota         if (val__ > (to)->field) {                                      \
4332c3fac113SEmilio G. Cota             (to)->field = val__;                                        \
4333c3fac113SEmilio G. Cota         }                                                               \
4334c3fac113SEmilio G. Cota     } while (0)
4335c3fac113SEmilio G. Cota 
4336c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */
4337c3fac113SEmilio G. Cota static inline
4338c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
4339c896fe29Sbellard {
4340d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
4341c3fac113SEmilio G. Cota     unsigned int i;
4342c3fac113SEmilio G. Cota 
43433468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4344d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
43453468b59eSEmilio G. Cota         const TCGProfile *orig = &s->prof;
4346c3fac113SEmilio G. Cota 
4347c3fac113SEmilio G. Cota         if (counters) {
434872fd2efbSEmilio G. Cota             PROF_ADD(prof, orig, cpu_exec_time);
4349c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count1);
4350c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count);
4351c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, op_count);
4352c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, op_count_max);
4353c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, temp_count);
4354c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, temp_count_max);
4355c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, del_op_count);
4356c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_in_len);
4357c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_out_len);
4358c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, search_out_len);
4359c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, interm_time);
4360c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_time);
4361c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, la_time);
4362c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, opt_time);
4363c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_count);
4364c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_time);
4365c3fac113SEmilio G. Cota         }
4366c3fac113SEmilio G. Cota         if (table) {
4367c896fe29Sbellard             int i;
4368d70724ceSzhanghailiang 
436915fc7daaSRichard Henderson             for (i = 0; i < NB_OPS; i++) {
4370c3fac113SEmilio G. Cota                 PROF_ADD(prof, orig, table_op_count[i]);
4371c3fac113SEmilio G. Cota             }
4372c3fac113SEmilio G. Cota         }
4373c3fac113SEmilio G. Cota     }
4374c3fac113SEmilio G. Cota }
4375c3fac113SEmilio G. Cota 
4376c3fac113SEmilio G. Cota #undef PROF_ADD
4377c3fac113SEmilio G. Cota #undef PROF_MAX
4378c3fac113SEmilio G. Cota 
4379c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof)
4380c3fac113SEmilio G. Cota {
4381c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, true, false);
4382c3fac113SEmilio G. Cota }
4383c3fac113SEmilio G. Cota 
4384c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof)
4385c3fac113SEmilio G. Cota {
4386c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, false, true);
4387c3fac113SEmilio G. Cota }
4388c3fac113SEmilio G. Cota 
4389d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
4390c3fac113SEmilio G. Cota {
4391c3fac113SEmilio G. Cota     TCGProfile prof = {};
4392c3fac113SEmilio G. Cota     int i;
4393c3fac113SEmilio G. Cota 
4394c3fac113SEmilio G. Cota     tcg_profile_snapshot_table(&prof);
4395c3fac113SEmilio G. Cota     for (i = 0; i < NB_OPS; i++) {
4396d4c51a0aSMarkus Armbruster         qemu_printf("%s %" PRId64 "\n", tcg_op_defs[i].name,
4397c3fac113SEmilio G. Cota                     prof.table_op_count[i]);
4398c896fe29Sbellard     }
4399c896fe29Sbellard }
440072fd2efbSEmilio G. Cota 
440172fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
440272fd2efbSEmilio G. Cota {
4403d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
440472fd2efbSEmilio G. Cota     unsigned int i;
440572fd2efbSEmilio G. Cota     int64_t ret = 0;
440672fd2efbSEmilio G. Cota 
440772fd2efbSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4408d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
440972fd2efbSEmilio G. Cota         const TCGProfile *prof = &s->prof;
441072fd2efbSEmilio G. Cota 
4411d73415a3SStefan Hajnoczi         ret += qatomic_read(&prof->cpu_exec_time);
441272fd2efbSEmilio G. Cota     }
441372fd2efbSEmilio G. Cota     return ret;
441472fd2efbSEmilio G. Cota }
4415246ae24dSMax Filippov #else
4416d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
4417246ae24dSMax Filippov {
4418d4c51a0aSMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4419246ae24dSMax Filippov }
442072fd2efbSEmilio G. Cota 
442172fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
442272fd2efbSEmilio G. Cota {
442372fd2efbSEmilio G. Cota     error_report("%s: TCG profiler not compiled", __func__);
442472fd2efbSEmilio G. Cota     exit(EXIT_FAILURE);
442572fd2efbSEmilio G. Cota }
4426c896fe29Sbellard #endif
4427c896fe29Sbellard 
4428c896fe29Sbellard 
44295bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
4430c896fe29Sbellard {
4431c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER
4432c3fac113SEmilio G. Cota     TCGProfile *prof = &s->prof;
4433c3fac113SEmilio G. Cota #endif
443415fa08f8SRichard Henderson     int i, num_insns;
443515fa08f8SRichard Henderson     TCGOp *op;
4436c896fe29Sbellard 
443704fe6400SRichard Henderson #ifdef CONFIG_PROFILER
443804fe6400SRichard Henderson     {
4439c1f543b7SEmilio G. Cota         int n = 0;
444004fe6400SRichard Henderson 
444115fa08f8SRichard Henderson         QTAILQ_FOREACH(op, &s->ops, link) {
444215fa08f8SRichard Henderson             n++;
444315fa08f8SRichard Henderson         }
4444d73415a3SStefan Hajnoczi         qatomic_set(&prof->op_count, prof->op_count + n);
4445c3fac113SEmilio G. Cota         if (n > prof->op_count_max) {
4446d73415a3SStefan Hajnoczi             qatomic_set(&prof->op_count_max, n);
444704fe6400SRichard Henderson         }
444804fe6400SRichard Henderson 
444904fe6400SRichard Henderson         n = s->nb_temps;
4450d73415a3SStefan Hajnoczi         qatomic_set(&prof->temp_count, prof->temp_count + n);
4451c3fac113SEmilio G. Cota         if (n > prof->temp_count_max) {
4452d73415a3SStefan Hajnoczi             qatomic_set(&prof->temp_count_max, n);
445304fe6400SRichard Henderson         }
445404fe6400SRichard Henderson     }
445504fe6400SRichard Henderson #endif
445604fe6400SRichard Henderson 
4457c896fe29Sbellard #ifdef DEBUG_DISAS
4458d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
4459d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
4460fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
446193fcfe39Saliguori         qemu_log("OP:\n");
44621894f69aSRichard Henderson         tcg_dump_ops(s, false);
446393fcfe39Saliguori         qemu_log("\n");
4464fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
4465c896fe29Sbellard     }
4466c896fe29Sbellard #endif
4467c896fe29Sbellard 
4468bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
4469bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
4470bef16ab4SRichard Henderson     {
4471bef16ab4SRichard Henderson         TCGLabel *l;
4472bef16ab4SRichard Henderson         bool error = false;
4473bef16ab4SRichard Henderson 
4474bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
4475bef16ab4SRichard Henderson             if (unlikely(!l->present) && l->refs) {
4476bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
4477bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
4478bef16ab4SRichard Henderson                 error = true;
4479bef16ab4SRichard Henderson             }
4480bef16ab4SRichard Henderson         }
4481bef16ab4SRichard Henderson         assert(!error);
4482bef16ab4SRichard Henderson     }
4483bef16ab4SRichard Henderson #endif
4484bef16ab4SRichard Henderson 
4485c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
4486d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
4487c5cc28ffSAurelien Jarno #endif
4488c5cc28ffSAurelien Jarno 
44898f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
4490c45cb8bbSRichard Henderson     tcg_optimize(s);
44918f2e8c07SKirill Batuzov #endif
44928f2e8c07SKirill Batuzov 
4493a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4494d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
4495d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time - profile_getclock());
4496a23a9ec6Sbellard #endif
4497c5cc28ffSAurelien Jarno 
4498b4fc67c7SRichard Henderson     reachable_code_pass(s);
4499b83eabeaSRichard Henderson     liveness_pass_1(s);
45005a18407fSRichard Henderson 
45015a18407fSRichard Henderson     if (s->nb_indirects > 0) {
45025a18407fSRichard Henderson #ifdef DEBUG_DISAS
45035a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
45045a18407fSRichard Henderson                      && qemu_log_in_addr_range(tb->pc))) {
4505fc59d2d8SRobert Foley             FILE *logfile = qemu_log_lock();
45065a18407fSRichard Henderson             qemu_log("OP before indirect lowering:\n");
45071894f69aSRichard Henderson             tcg_dump_ops(s, false);
45085a18407fSRichard Henderson             qemu_log("\n");
4509fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
45105a18407fSRichard Henderson         }
45115a18407fSRichard Henderson #endif
45125a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
4513b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
45145a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
4515b83eabeaSRichard Henderson             liveness_pass_1(s);
45165a18407fSRichard Henderson         }
45175a18407fSRichard Henderson     }
4518c5cc28ffSAurelien Jarno 
4519a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4520d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time + profile_getclock());
4521a23a9ec6Sbellard #endif
4522c896fe29Sbellard 
4523c896fe29Sbellard #ifdef DEBUG_DISAS
4524d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
4525d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
4526fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
4527c5cc28ffSAurelien Jarno         qemu_log("OP after optimization and liveness analysis:\n");
45281894f69aSRichard Henderson         tcg_dump_ops(s, true);
452993fcfe39Saliguori         qemu_log("\n");
4530fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
4531c896fe29Sbellard     }
4532c896fe29Sbellard #endif
4533c896fe29Sbellard 
4534c896fe29Sbellard     tcg_reg_alloc_start(s);
4535c896fe29Sbellard 
4536db0c51a3SRichard Henderson     /*
4537db0c51a3SRichard Henderson      * Reset the buffer pointers when restarting after overflow.
4538db0c51a3SRichard Henderson      * TODO: Move this into translate-all.c with the rest of the
4539db0c51a3SRichard Henderson      * buffer management.  Having only this done here is confusing.
4540db0c51a3SRichard Henderson      */
4541db0c51a3SRichard Henderson     s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr);
4542db0c51a3SRichard Henderson     s->code_ptr = s->code_buf;
4543c896fe29Sbellard 
4544659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
45456001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
4546659ef5cbSRichard Henderson #endif
454757a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
454857a26946SRichard Henderson     s->pool_labels = NULL;
454957a26946SRichard Henderson #endif
45509ecefc84SRichard Henderson 
4551fca8a500SRichard Henderson     num_insns = -1;
455215fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
4553c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
4554b3db8758Sblueswir1 
4555c896fe29Sbellard #ifdef CONFIG_PROFILER
4556d73415a3SStefan Hajnoczi         qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
4557c896fe29Sbellard #endif
4558c45cb8bbSRichard Henderson 
4559c896fe29Sbellard         switch (opc) {
4560c896fe29Sbellard         case INDEX_op_mov_i32:
4561c896fe29Sbellard         case INDEX_op_mov_i64:
4562d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
4563dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
4564c896fe29Sbellard             break;
4565bab1671fSRichard Henderson         case INDEX_op_dup_vec:
4566bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
4567bab1671fSRichard Henderson             break;
4568765b842aSRichard Henderson         case INDEX_op_insn_start:
4569fca8a500SRichard Henderson             if (num_insns >= 0) {
45709f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
45719f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
45729f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
45739f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
4574fca8a500SRichard Henderson             }
4575fca8a500SRichard Henderson             num_insns++;
4576bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
4577bad729e2SRichard Henderson                 target_ulong a;
4578bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
4579efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
4580bad729e2SRichard Henderson #else
4581efee3746SRichard Henderson                 a = op->args[i];
4582bad729e2SRichard Henderson #endif
4583fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
4584bad729e2SRichard Henderson             }
4585c896fe29Sbellard             break;
45865ff9d6a4Sbellard         case INDEX_op_discard:
458743439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
45885ff9d6a4Sbellard             break;
4589c896fe29Sbellard         case INDEX_op_set_label:
4590e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
459192ab8e7dSRichard Henderson             tcg_out_label(s, arg_label(op->args[0]));
4592c896fe29Sbellard             break;
4593c896fe29Sbellard         case INDEX_op_call:
4594dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
4595c45cb8bbSRichard Henderson             break;
4596*efe86b21SRichard Henderson         case INDEX_op_dup2_vec:
4597*efe86b21SRichard Henderson             if (tcg_reg_alloc_dup2(s, op)) {
4598*efe86b21SRichard Henderson                 break;
4599*efe86b21SRichard Henderson             }
4600*efe86b21SRichard Henderson             /* fall through */
4601c896fe29Sbellard         default:
460225c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
4603be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
4604c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
4605c896fe29Sbellard                faster to have specialized register allocator functions for
4606c896fe29Sbellard                some common argument patterns */
4607dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
4608c896fe29Sbellard             break;
4609c896fe29Sbellard         }
46108d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
4611c896fe29Sbellard         check_regs(s);
4612c896fe29Sbellard #endif
4613b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
4614b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
4615b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
4616b125f9dcSRichard Henderson            generating code without having to check during generation.  */
4617644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
4618b125f9dcSRichard Henderson             return -1;
4619b125f9dcSRichard Henderson         }
46206e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
46216e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
46226e6c4efeSRichard Henderson             return -2;
46236e6c4efeSRichard Henderson         }
4624c896fe29Sbellard     }
4625fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
4626fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
4627c45cb8bbSRichard Henderson 
4628b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
4629659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
4630aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
4631aeee05f5SRichard Henderson     if (i < 0) {
4632aeee05f5SRichard Henderson         return i;
463323dceda6SRichard Henderson     }
4634659ef5cbSRichard Henderson #endif
463557a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
46361768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
46371768987bSRichard Henderson     if (i < 0) {
46381768987bSRichard Henderson         return i;
463957a26946SRichard Henderson     }
464057a26946SRichard Henderson #endif
46417ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
46427ecd02a0SRichard Henderson         return -2;
46437ecd02a0SRichard Henderson     }
4644c896fe29Sbellard 
4645df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
4646c896fe29Sbellard     /* flush instruction cache */
4647db0c51a3SRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
4648db0c51a3SRichard Henderson                         (uintptr_t)s->code_buf,
46491da8de39SRichard Henderson                         tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
4650df5d2b16SRichard Henderson #endif
46512aeabc08SStefan Weil 
46521813e175SRichard Henderson     return tcg_current_code_size(s);
4653c896fe29Sbellard }
4654c896fe29Sbellard 
4655a23a9ec6Sbellard #ifdef CONFIG_PROFILER
46563de2faa9SMarkus Armbruster void tcg_dump_info(void)
4657a23a9ec6Sbellard {
4658c3fac113SEmilio G. Cota     TCGProfile prof = {};
4659c3fac113SEmilio G. Cota     const TCGProfile *s;
4660c3fac113SEmilio G. Cota     int64_t tb_count;
4661c3fac113SEmilio G. Cota     int64_t tb_div_count;
4662c3fac113SEmilio G. Cota     int64_t tot;
4663c3fac113SEmilio G. Cota 
4664c3fac113SEmilio G. Cota     tcg_profile_snapshot_counters(&prof);
4665c3fac113SEmilio G. Cota     s = &prof;
4666c3fac113SEmilio G. Cota     tb_count = s->tb_count;
4667c3fac113SEmilio G. Cota     tb_div_count = tb_count ? tb_count : 1;
4668c3fac113SEmilio G. Cota     tot = s->interm_time + s->code_time;
4669a23a9ec6Sbellard 
46703de2faa9SMarkus Armbruster     qemu_printf("JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
4671a23a9ec6Sbellard                 tot, tot / 2.4e9);
46723de2faa9SMarkus Armbruster     qemu_printf("translated TBs      %" PRId64 " (aborted=%" PRId64
46733de2faa9SMarkus Armbruster                 " %0.1f%%)\n",
4674fca8a500SRichard Henderson                 tb_count, s->tb_count1 - tb_count,
4675fca8a500SRichard Henderson                 (double)(s->tb_count1 - s->tb_count)
4676fca8a500SRichard Henderson                 / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
46773de2faa9SMarkus Armbruster     qemu_printf("avg ops/TB          %0.1f max=%d\n",
4678fca8a500SRichard Henderson                 (double)s->op_count / tb_div_count, s->op_count_max);
46793de2faa9SMarkus Armbruster     qemu_printf("deleted ops/TB      %0.2f\n",
4680fca8a500SRichard Henderson                 (double)s->del_op_count / tb_div_count);
46813de2faa9SMarkus Armbruster     qemu_printf("avg temps/TB        %0.2f max=%d\n",
4682fca8a500SRichard Henderson                 (double)s->temp_count / tb_div_count, s->temp_count_max);
46833de2faa9SMarkus Armbruster     qemu_printf("avg host code/TB    %0.1f\n",
4684fca8a500SRichard Henderson                 (double)s->code_out_len / tb_div_count);
46853de2faa9SMarkus Armbruster     qemu_printf("avg search data/TB  %0.1f\n",
4686fca8a500SRichard Henderson                 (double)s->search_out_len / tb_div_count);
4687a23a9ec6Sbellard 
46883de2faa9SMarkus Armbruster     qemu_printf("cycles/op           %0.1f\n",
4689a23a9ec6Sbellard                 s->op_count ? (double)tot / s->op_count : 0);
46903de2faa9SMarkus Armbruster     qemu_printf("cycles/in byte      %0.1f\n",
4691a23a9ec6Sbellard                 s->code_in_len ? (double)tot / s->code_in_len : 0);
46923de2faa9SMarkus Armbruster     qemu_printf("cycles/out byte     %0.1f\n",
4693a23a9ec6Sbellard                 s->code_out_len ? (double)tot / s->code_out_len : 0);
46943de2faa9SMarkus Armbruster     qemu_printf("cycles/search byte     %0.1f\n",
4695fca8a500SRichard Henderson                 s->search_out_len ? (double)tot / s->search_out_len : 0);
4696fca8a500SRichard Henderson     if (tot == 0) {
4697a23a9ec6Sbellard         tot = 1;
4698fca8a500SRichard Henderson     }
46993de2faa9SMarkus Armbruster     qemu_printf("  gen_interm time   %0.1f%%\n",
4700a23a9ec6Sbellard                 (double)s->interm_time / tot * 100.0);
47013de2faa9SMarkus Armbruster     qemu_printf("  gen_code time     %0.1f%%\n",
4702a23a9ec6Sbellard                 (double)s->code_time / tot * 100.0);
47033de2faa9SMarkus Armbruster     qemu_printf("optim./code time    %0.1f%%\n",
4704c5cc28ffSAurelien Jarno                 (double)s->opt_time / (s->code_time ? s->code_time : 1)
4705c5cc28ffSAurelien Jarno                 * 100.0);
47063de2faa9SMarkus Armbruster     qemu_printf("liveness/code time  %0.1f%%\n",
4707a23a9ec6Sbellard                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
47083de2faa9SMarkus Armbruster     qemu_printf("cpu_restore count   %" PRId64 "\n",
4709a23a9ec6Sbellard                 s->restore_count);
47103de2faa9SMarkus Armbruster     qemu_printf("  avg cycles        %0.1f\n",
4711a23a9ec6Sbellard                 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
4712a23a9ec6Sbellard }
4713a23a9ec6Sbellard #else
47143de2faa9SMarkus Armbruster void tcg_dump_info(void)
4715a23a9ec6Sbellard {
47163de2faa9SMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4717a23a9ec6Sbellard }
4718a23a9ec6Sbellard #endif
4719813da627SRichard Henderson 
4720813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
47215872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
47225872bbf2SRichard Henderson 
47235872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
47245872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
47255872bbf2SRichard Henderson 
47265872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
47275872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
47285872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
47295872bbf2SRichard Henderson 
47305872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
47315872bbf2SRichard Henderson */
4732813da627SRichard Henderson 
4733813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
4734813da627SRichard Henderson typedef enum {
4735813da627SRichard Henderson     JIT_NOACTION = 0,
4736813da627SRichard Henderson     JIT_REGISTER_FN,
4737813da627SRichard Henderson     JIT_UNREGISTER_FN
4738813da627SRichard Henderson } jit_actions_t;
4739813da627SRichard Henderson 
4740813da627SRichard Henderson struct jit_code_entry {
4741813da627SRichard Henderson     struct jit_code_entry *next_entry;
4742813da627SRichard Henderson     struct jit_code_entry *prev_entry;
4743813da627SRichard Henderson     const void *symfile_addr;
4744813da627SRichard Henderson     uint64_t symfile_size;
4745813da627SRichard Henderson };
4746813da627SRichard Henderson 
4747813da627SRichard Henderson struct jit_descriptor {
4748813da627SRichard Henderson     uint32_t version;
4749813da627SRichard Henderson     uint32_t action_flag;
4750813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
4751813da627SRichard Henderson     struct jit_code_entry *first_entry;
4752813da627SRichard Henderson };
4753813da627SRichard Henderson 
4754813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
4755813da627SRichard Henderson void __jit_debug_register_code(void)
4756813da627SRichard Henderson {
4757813da627SRichard Henderson     asm("");
4758813da627SRichard Henderson }
4759813da627SRichard Henderson 
4760813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
4761813da627SRichard Henderson    the version before we can set it.  */
4762813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
4763813da627SRichard Henderson 
4764813da627SRichard Henderson /* End GDB interface.  */
4765813da627SRichard Henderson 
4766813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
4767813da627SRichard Henderson {
4768813da627SRichard Henderson     const char *p = strtab + 1;
4769813da627SRichard Henderson 
4770813da627SRichard Henderson     while (1) {
4771813da627SRichard Henderson         if (strcmp(p, str) == 0) {
4772813da627SRichard Henderson             return p - strtab;
4773813da627SRichard Henderson         }
4774813da627SRichard Henderson         p += strlen(p) + 1;
4775813da627SRichard Henderson     }
4776813da627SRichard Henderson }
4777813da627SRichard Henderson 
4778755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size,
47792c90784aSRichard Henderson                                  const void *debug_frame,
47802c90784aSRichard Henderson                                  size_t debug_frame_size)
4781813da627SRichard Henderson {
47825872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
47835872bbf2SRichard Henderson         uint32_t  len;
47845872bbf2SRichard Henderson         uint16_t  version;
47855872bbf2SRichard Henderson         uint32_t  abbrev;
47865872bbf2SRichard Henderson         uint8_t   ptr_size;
47875872bbf2SRichard Henderson         uint8_t   cu_die;
47885872bbf2SRichard Henderson         uint16_t  cu_lang;
47895872bbf2SRichard Henderson         uintptr_t cu_low_pc;
47905872bbf2SRichard Henderson         uintptr_t cu_high_pc;
47915872bbf2SRichard Henderson         uint8_t   fn_die;
47925872bbf2SRichard Henderson         char      fn_name[16];
47935872bbf2SRichard Henderson         uintptr_t fn_low_pc;
47945872bbf2SRichard Henderson         uintptr_t fn_high_pc;
47955872bbf2SRichard Henderson         uint8_t   cu_eoc;
47965872bbf2SRichard Henderson     };
4797813da627SRichard Henderson 
4798813da627SRichard Henderson     struct ElfImage {
4799813da627SRichard Henderson         ElfW(Ehdr) ehdr;
4800813da627SRichard Henderson         ElfW(Phdr) phdr;
48015872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
48025872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
48035872bbf2SRichard Henderson         struct DebugInfo di;
48045872bbf2SRichard Henderson         uint8_t    da[24];
48055872bbf2SRichard Henderson         char       str[80];
48065872bbf2SRichard Henderson     };
48075872bbf2SRichard Henderson 
48085872bbf2SRichard Henderson     struct ElfImage *img;
48095872bbf2SRichard Henderson 
48105872bbf2SRichard Henderson     static const struct ElfImage img_template = {
48115872bbf2SRichard Henderson         .ehdr = {
48125872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
48135872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
48145872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
48155872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
48165872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
48175872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
48185872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
48195872bbf2SRichard Henderson             .e_type = ET_EXEC,
48205872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
48215872bbf2SRichard Henderson             .e_version = EV_CURRENT,
48225872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
48235872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
48245872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
48255872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
48265872bbf2SRichard Henderson             .e_phnum = 1,
48275872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
48285872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
48295872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
4830abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
4831abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
4832abbb3eaeSRichard Henderson #endif
4833abbb3eaeSRichard Henderson #ifdef ELF_OSABI
4834abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
4835abbb3eaeSRichard Henderson #endif
48365872bbf2SRichard Henderson         },
48375872bbf2SRichard Henderson         .phdr = {
48385872bbf2SRichard Henderson             .p_type = PT_LOAD,
48395872bbf2SRichard Henderson             .p_flags = PF_X,
48405872bbf2SRichard Henderson         },
48415872bbf2SRichard Henderson         .shdr = {
48425872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
48435872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
48445872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
48455872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
48465872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
48475872bbf2SRichard Henderson             [1] = { /* .text */
48485872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
48495872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
48505872bbf2SRichard Henderson             },
48515872bbf2SRichard Henderson             [2] = { /* .debug_info */
48525872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
48535872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
48545872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
48555872bbf2SRichard Henderson             },
48565872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
48575872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
48585872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
48595872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
48605872bbf2SRichard Henderson             },
48615872bbf2SRichard Henderson             [4] = { /* .debug_frame */
48625872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
48635872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
48645872bbf2SRichard Henderson             },
48655872bbf2SRichard Henderson             [5] = { /* .symtab */
48665872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
48675872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
48685872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
48695872bbf2SRichard Henderson                 .sh_info = 1,
48705872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
48715872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
48725872bbf2SRichard Henderson             },
48735872bbf2SRichard Henderson             [6] = { /* .strtab */
48745872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
48755872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
48765872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
48775872bbf2SRichard Henderson             }
48785872bbf2SRichard Henderson         },
48795872bbf2SRichard Henderson         .sym = {
48805872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
48815872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
48825872bbf2SRichard Henderson                 .st_shndx = 1,
48835872bbf2SRichard Henderson             }
48845872bbf2SRichard Henderson         },
48855872bbf2SRichard Henderson         .di = {
48865872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
48875872bbf2SRichard Henderson             .version = 2,
48885872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
48895872bbf2SRichard Henderson             .cu_die = 1,
48905872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
48915872bbf2SRichard Henderson             .fn_die = 2,
48925872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
48935872bbf2SRichard Henderson         },
48945872bbf2SRichard Henderson         .da = {
48955872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
48965872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
48975872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
48985872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
48995872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
49005872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
49015872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
49025872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
49035872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
49045872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
49055872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
49065872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
49075872bbf2SRichard Henderson             0           /* no more abbrev */
49085872bbf2SRichard Henderson         },
49095872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
49105872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
4911813da627SRichard Henderson     };
4912813da627SRichard Henderson 
4913813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
4914813da627SRichard Henderson     static struct jit_code_entry one_entry;
4915813da627SRichard Henderson 
49165872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
4917813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
49182c90784aSRichard Henderson     DebugFrameHeader *dfh;
4919813da627SRichard Henderson 
49205872bbf2SRichard Henderson     img = g_malloc(img_size);
49215872bbf2SRichard Henderson     *img = img_template;
4922813da627SRichard Henderson 
49235872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
49245872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
49255872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
4926813da627SRichard Henderson 
49275872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
49285872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
49295872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
4930813da627SRichard Henderson 
49315872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
49325872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
49335872bbf2SRichard Henderson 
49345872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
49355872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
49365872bbf2SRichard Henderson 
49375872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
49385872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
49395872bbf2SRichard Henderson 
49405872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
49415872bbf2SRichard Henderson     img->sym[1].st_value = buf;
49425872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
49435872bbf2SRichard Henderson 
49445872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
494545aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
49465872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
494745aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
4948813da627SRichard Henderson 
49492c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
49502c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
49512c90784aSRichard Henderson     dfh->fde.func_start = buf;
49522c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
49532c90784aSRichard Henderson 
4954813da627SRichard Henderson #ifdef DEBUG_JIT
4955813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
4956813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
4957813da627SRichard Henderson     {
4958813da627SRichard Henderson         FILE *f = fopen("/tmp/qemu.jit", "w+b");
4959813da627SRichard Henderson         if (f) {
49605872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
4961813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
4962813da627SRichard Henderson             }
4963813da627SRichard Henderson             fclose(f);
4964813da627SRichard Henderson         }
4965813da627SRichard Henderson     }
4966813da627SRichard Henderson #endif
4967813da627SRichard Henderson 
4968813da627SRichard Henderson     one_entry.symfile_addr = img;
4969813da627SRichard Henderson     one_entry.symfile_size = img_size;
4970813da627SRichard Henderson 
4971813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
4972813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
4973813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
4974813da627SRichard Henderson     __jit_debug_register_code();
4975813da627SRichard Henderson }
4976813da627SRichard Henderson #else
49775872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
49785872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
4979813da627SRichard Henderson 
4980755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
49812c90784aSRichard Henderson                                  const void *debug_frame,
49822c90784aSRichard Henderson                                  size_t debug_frame_size)
4983813da627SRichard Henderson {
4984813da627SRichard Henderson }
4985813da627SRichard Henderson 
4986755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size)
4987813da627SRichard Henderson {
4988813da627SRichard Henderson }
4989813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
4990db432672SRichard Henderson 
4991db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
4992db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
4993db432672SRichard Henderson {
4994db432672SRichard Henderson     g_assert_not_reached();
4995db432672SRichard Henderson }
4996db432672SRichard Henderson #endif
4997