xref: /qemu/tcg/tcg.c (revision 8b5c2b6260c0bb1233f605663bec9582b55d80c9)
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 
100813da627SRichard Henderson static void tcg_register_jit_int(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);
120e7632cfaSRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type,
121e7632cfaSRichard Henderson                              TCGReg dst, tcg_target_long 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 }
136e7632cfaSRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type,
137e7632cfaSRichard Henderson                                     TCGReg dst, tcg_target_long 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);
152cf066674SRichard Henderson static void tcg_out_call(TCGContext *s, 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;
164*8b5c2b62SRichard Henderson void *tcg_code_gen_epilogue;
165df2cce29SEmilio G. Cota 
166b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
167b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec;
168b91ccb31SRichard Henderson #endif
169b91ccb31SRichard Henderson 
170be2cdc5eSEmilio G. Cota struct tcg_region_tree {
171be2cdc5eSEmilio G. Cota     QemuMutex lock;
172be2cdc5eSEmilio G. Cota     GTree *tree;
173be2cdc5eSEmilio G. Cota     /* padding to avoid false sharing is computed at run-time */
174be2cdc5eSEmilio G. Cota };
175be2cdc5eSEmilio G. Cota 
176e8feb96fSEmilio G. Cota /*
177e8feb96fSEmilio G. Cota  * We divide code_gen_buffer into equally-sized "regions" that TCG threads
178e8feb96fSEmilio G. Cota  * dynamically allocate from as demand dictates. Given appropriate region
179e8feb96fSEmilio G. Cota  * sizing, this minimizes flushes even when some TCG threads generate a lot
180e8feb96fSEmilio G. Cota  * more code than others.
181e8feb96fSEmilio G. Cota  */
182e8feb96fSEmilio G. Cota struct tcg_region_state {
183e8feb96fSEmilio G. Cota     QemuMutex lock;
184e8feb96fSEmilio G. Cota 
185e8feb96fSEmilio G. Cota     /* fields set at init time */
186e8feb96fSEmilio G. Cota     void *start;
187e8feb96fSEmilio G. Cota     void *start_aligned;
188e8feb96fSEmilio G. Cota     void *end;
189e8feb96fSEmilio G. Cota     size_t n;
190e8feb96fSEmilio G. Cota     size_t size; /* size of one region */
191e8feb96fSEmilio G. Cota     size_t stride; /* .size + guard size */
192e8feb96fSEmilio G. Cota 
193e8feb96fSEmilio G. Cota     /* fields protected by the lock */
194e8feb96fSEmilio G. Cota     size_t current; /* current region index */
195e8feb96fSEmilio G. Cota     size_t agg_size_full; /* aggregate size of full regions */
196e8feb96fSEmilio G. Cota };
197e8feb96fSEmilio G. Cota 
198e8feb96fSEmilio G. Cota static struct tcg_region_state region;
199be2cdc5eSEmilio G. Cota /*
200be2cdc5eSEmilio G. Cota  * This is an array of struct tcg_region_tree's, with padding.
201be2cdc5eSEmilio G. Cota  * We use void * to simplify the computation of region_trees[i]; each
202be2cdc5eSEmilio G. Cota  * struct is found every tree_size bytes.
203be2cdc5eSEmilio G. Cota  */
204be2cdc5eSEmilio G. Cota static void *region_trees;
205be2cdc5eSEmilio G. Cota static size_t tree_size;
206d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
207b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
208c896fe29Sbellard 
2091813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
2104196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
211c896fe29Sbellard {
212c896fe29Sbellard     *s->code_ptr++ = v;
213c896fe29Sbellard }
214c896fe29Sbellard 
2154196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
2164196dca6SPeter Maydell                                                       uint8_t v)
2175c53bb81SPeter Maydell {
2181813e175SRichard Henderson     *p = v;
2195c53bb81SPeter Maydell }
2201813e175SRichard Henderson #endif
2215c53bb81SPeter Maydell 
2221813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
2234196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
224c896fe29Sbellard {
2251813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2261813e175SRichard Henderson         *s->code_ptr++ = v;
2271813e175SRichard Henderson     } else {
2281813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2294387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2301813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
2311813e175SRichard Henderson     }
232c896fe29Sbellard }
233c896fe29Sbellard 
2344196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2354196dca6SPeter Maydell                                                        uint16_t v)
2365c53bb81SPeter Maydell {
2371813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2381813e175SRichard Henderson         *p = v;
2391813e175SRichard Henderson     } else {
2405c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2415c53bb81SPeter Maydell     }
2421813e175SRichard Henderson }
2431813e175SRichard Henderson #endif
2445c53bb81SPeter Maydell 
2451813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
2464196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
247c896fe29Sbellard {
2481813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2491813e175SRichard Henderson         *s->code_ptr++ = v;
2501813e175SRichard Henderson     } else {
2511813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2524387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2531813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
2541813e175SRichard Henderson     }
255c896fe29Sbellard }
256c896fe29Sbellard 
2574196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
2584196dca6SPeter Maydell                                                        uint32_t v)
2595c53bb81SPeter Maydell {
2601813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2611813e175SRichard Henderson         *p = v;
2621813e175SRichard Henderson     } else {
2635c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2645c53bb81SPeter Maydell     }
2651813e175SRichard Henderson }
2661813e175SRichard Henderson #endif
2675c53bb81SPeter Maydell 
2681813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
2694196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
270ac26eb69SRichard Henderson {
2711813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2721813e175SRichard Henderson         *s->code_ptr++ = v;
2731813e175SRichard Henderson     } else {
2741813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2754387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2761813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
2771813e175SRichard Henderson     }
278ac26eb69SRichard Henderson }
279ac26eb69SRichard Henderson 
2804196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
2814196dca6SPeter Maydell                                                        uint64_t v)
2825c53bb81SPeter Maydell {
2831813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2841813e175SRichard Henderson         *p = v;
2851813e175SRichard Henderson     } else {
2865c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2875c53bb81SPeter Maydell     }
2881813e175SRichard Henderson }
2891813e175SRichard Henderson #endif
2905c53bb81SPeter Maydell 
291c896fe29Sbellard /* label relocation processing */
292c896fe29Sbellard 
2931813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
294bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
295c896fe29Sbellard {
2967ecd02a0SRichard Henderson     TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation));
297c896fe29Sbellard 
298c896fe29Sbellard     r->type = type;
299c896fe29Sbellard     r->ptr = code_ptr;
300c896fe29Sbellard     r->addend = addend;
3017ecd02a0SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
302c896fe29Sbellard }
303c896fe29Sbellard 
304bec16311SRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr)
305c896fe29Sbellard {
306eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
307c896fe29Sbellard     l->has_value = 1;
3081813e175SRichard Henderson     l->u.value_ptr = ptr;
309c896fe29Sbellard }
310c896fe29Sbellard 
31142a268c2SRichard Henderson TCGLabel *gen_new_label(void)
312c896fe29Sbellard {
313b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
31451e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
315c896fe29Sbellard 
3167ecd02a0SRichard Henderson     memset(l, 0, sizeof(TCGLabel));
3177ecd02a0SRichard Henderson     l->id = s->nb_labels++;
3187ecd02a0SRichard Henderson     QSIMPLEQ_INIT(&l->relocs);
3197ecd02a0SRichard Henderson 
320bef16ab4SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
32142a268c2SRichard Henderson 
32242a268c2SRichard Henderson     return l;
323c896fe29Sbellard }
324c896fe29Sbellard 
3257ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s)
3267ecd02a0SRichard Henderson {
3277ecd02a0SRichard Henderson     TCGLabel *l;
3287ecd02a0SRichard Henderson 
3297ecd02a0SRichard Henderson     QSIMPLEQ_FOREACH(l, &s->labels, next) {
3307ecd02a0SRichard Henderson         TCGRelocation *r;
3317ecd02a0SRichard Henderson         uintptr_t value = l->u.value;
3327ecd02a0SRichard Henderson 
3337ecd02a0SRichard Henderson         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
3347ecd02a0SRichard Henderson             if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
3357ecd02a0SRichard Henderson                 return false;
3367ecd02a0SRichard Henderson             }
3377ecd02a0SRichard Henderson         }
3387ecd02a0SRichard Henderson     }
3397ecd02a0SRichard Henderson     return true;
3407ecd02a0SRichard Henderson }
3417ecd02a0SRichard Henderson 
3429f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3439f754620SRichard Henderson {
344f14bed3fSRichard Henderson     /*
345f14bed3fSRichard Henderson      * We will check for overflow at the end of the opcode loop in
346f14bed3fSRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
347f14bed3fSRichard Henderson      */
348f14bed3fSRichard Henderson     s->tb_jmp_reset_offset[which] = tcg_current_code_size(s);
3499f754620SRichard Henderson }
3509f754620SRichard Henderson 
351139c1837SPaolo Bonzini #include "tcg-target.c.inc"
352c896fe29Sbellard 
353be2cdc5eSEmilio G. Cota /* compare a pointer @ptr and a tb_tc @s */
354be2cdc5eSEmilio G. Cota static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s)
355be2cdc5eSEmilio G. Cota {
356be2cdc5eSEmilio G. Cota     if (ptr >= s->ptr + s->size) {
357be2cdc5eSEmilio G. Cota         return 1;
358be2cdc5eSEmilio G. Cota     } else if (ptr < s->ptr) {
359be2cdc5eSEmilio G. Cota         return -1;
360be2cdc5eSEmilio G. Cota     }
361be2cdc5eSEmilio G. Cota     return 0;
362be2cdc5eSEmilio G. Cota }
363be2cdc5eSEmilio G. Cota 
364be2cdc5eSEmilio G. Cota static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp)
365be2cdc5eSEmilio G. Cota {
366be2cdc5eSEmilio G. Cota     const struct tb_tc *a = ap;
367be2cdc5eSEmilio G. Cota     const struct tb_tc *b = bp;
368be2cdc5eSEmilio G. Cota 
369be2cdc5eSEmilio G. Cota     /*
370be2cdc5eSEmilio G. Cota      * When both sizes are set, we know this isn't a lookup.
371be2cdc5eSEmilio G. Cota      * This is the most likely case: every TB must be inserted; lookups
372be2cdc5eSEmilio G. Cota      * are a lot less frequent.
373be2cdc5eSEmilio G. Cota      */
374be2cdc5eSEmilio G. Cota     if (likely(a->size && b->size)) {
375be2cdc5eSEmilio G. Cota         if (a->ptr > b->ptr) {
376be2cdc5eSEmilio G. Cota             return 1;
377be2cdc5eSEmilio G. Cota         } else if (a->ptr < b->ptr) {
378be2cdc5eSEmilio G. Cota             return -1;
379be2cdc5eSEmilio G. Cota         }
380be2cdc5eSEmilio G. Cota         /* a->ptr == b->ptr should happen only on deletions */
381be2cdc5eSEmilio G. Cota         g_assert(a->size == b->size);
382be2cdc5eSEmilio G. Cota         return 0;
383be2cdc5eSEmilio G. Cota     }
384be2cdc5eSEmilio G. Cota     /*
385be2cdc5eSEmilio G. Cota      * All lookups have either .size field set to 0.
386be2cdc5eSEmilio G. Cota      * From the glib sources we see that @ap is always the lookup key. However
387be2cdc5eSEmilio G. Cota      * the docs provide no guarantee, so we just mark this case as likely.
388be2cdc5eSEmilio G. Cota      */
389be2cdc5eSEmilio G. Cota     if (likely(a->size == 0)) {
390be2cdc5eSEmilio G. Cota         return ptr_cmp_tb_tc(a->ptr, b);
391be2cdc5eSEmilio G. Cota     }
392be2cdc5eSEmilio G. Cota     return ptr_cmp_tb_tc(b->ptr, a);
393be2cdc5eSEmilio G. Cota }
394be2cdc5eSEmilio G. Cota 
395be2cdc5eSEmilio G. Cota static void tcg_region_trees_init(void)
396be2cdc5eSEmilio G. Cota {
397be2cdc5eSEmilio G. Cota     size_t i;
398be2cdc5eSEmilio G. Cota 
399be2cdc5eSEmilio G. Cota     tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize);
400be2cdc5eSEmilio G. Cota     region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size);
401be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
402be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
403be2cdc5eSEmilio G. Cota 
404be2cdc5eSEmilio G. Cota         qemu_mutex_init(&rt->lock);
405be2cdc5eSEmilio G. Cota         rt->tree = g_tree_new(tb_tc_cmp);
406be2cdc5eSEmilio G. Cota     }
407be2cdc5eSEmilio G. Cota }
408be2cdc5eSEmilio G. Cota 
409be2cdc5eSEmilio G. Cota static struct tcg_region_tree *tc_ptr_to_region_tree(void *p)
410be2cdc5eSEmilio G. Cota {
411be2cdc5eSEmilio G. Cota     size_t region_idx;
412be2cdc5eSEmilio G. Cota 
413be2cdc5eSEmilio G. Cota     if (p < region.start_aligned) {
414be2cdc5eSEmilio G. Cota         region_idx = 0;
415be2cdc5eSEmilio G. Cota     } else {
416be2cdc5eSEmilio G. Cota         ptrdiff_t offset = p - region.start_aligned;
417be2cdc5eSEmilio G. Cota 
418be2cdc5eSEmilio G. Cota         if (offset > region.stride * (region.n - 1)) {
419be2cdc5eSEmilio G. Cota             region_idx = region.n - 1;
420be2cdc5eSEmilio G. Cota         } else {
421be2cdc5eSEmilio G. Cota             region_idx = offset / region.stride;
422be2cdc5eSEmilio G. Cota         }
423be2cdc5eSEmilio G. Cota     }
424be2cdc5eSEmilio G. Cota     return region_trees + region_idx * tree_size;
425be2cdc5eSEmilio G. Cota }
426be2cdc5eSEmilio G. Cota 
427be2cdc5eSEmilio G. Cota void tcg_tb_insert(TranslationBlock *tb)
428be2cdc5eSEmilio G. Cota {
429be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
430be2cdc5eSEmilio G. Cota 
431be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
432be2cdc5eSEmilio G. Cota     g_tree_insert(rt->tree, &tb->tc, tb);
433be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
434be2cdc5eSEmilio G. Cota }
435be2cdc5eSEmilio G. Cota 
436be2cdc5eSEmilio G. Cota void tcg_tb_remove(TranslationBlock *tb)
437be2cdc5eSEmilio G. Cota {
438be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
439be2cdc5eSEmilio G. Cota 
440be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
441be2cdc5eSEmilio G. Cota     g_tree_remove(rt->tree, &tb->tc);
442be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
443be2cdc5eSEmilio G. Cota }
444be2cdc5eSEmilio G. Cota 
445be2cdc5eSEmilio G. Cota /*
446be2cdc5eSEmilio G. Cota  * Find the TB 'tb' such that
447be2cdc5eSEmilio G. Cota  * tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size
448be2cdc5eSEmilio G. Cota  * Return NULL if not found.
449be2cdc5eSEmilio G. Cota  */
450be2cdc5eSEmilio G. Cota TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr)
451be2cdc5eSEmilio G. Cota {
452be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr);
453be2cdc5eSEmilio G. Cota     TranslationBlock *tb;
454be2cdc5eSEmilio G. Cota     struct tb_tc s = { .ptr = (void *)tc_ptr };
455be2cdc5eSEmilio G. Cota 
456be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
457be2cdc5eSEmilio G. Cota     tb = g_tree_lookup(rt->tree, &s);
458be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
459be2cdc5eSEmilio G. Cota     return tb;
460be2cdc5eSEmilio G. Cota }
461be2cdc5eSEmilio G. Cota 
462be2cdc5eSEmilio G. Cota static void tcg_region_tree_lock_all(void)
463be2cdc5eSEmilio G. Cota {
464be2cdc5eSEmilio G. Cota     size_t i;
465be2cdc5eSEmilio G. Cota 
466be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
467be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
468be2cdc5eSEmilio G. Cota 
469be2cdc5eSEmilio G. Cota         qemu_mutex_lock(&rt->lock);
470be2cdc5eSEmilio G. Cota     }
471be2cdc5eSEmilio G. Cota }
472be2cdc5eSEmilio G. Cota 
473be2cdc5eSEmilio G. Cota static void tcg_region_tree_unlock_all(void)
474be2cdc5eSEmilio G. Cota {
475be2cdc5eSEmilio G. Cota     size_t i;
476be2cdc5eSEmilio G. Cota 
477be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
478be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
479be2cdc5eSEmilio G. Cota 
480be2cdc5eSEmilio G. Cota         qemu_mutex_unlock(&rt->lock);
481be2cdc5eSEmilio G. Cota     }
482be2cdc5eSEmilio G. Cota }
483be2cdc5eSEmilio G. Cota 
484be2cdc5eSEmilio G. Cota void tcg_tb_foreach(GTraverseFunc func, gpointer user_data)
485be2cdc5eSEmilio G. Cota {
486be2cdc5eSEmilio G. Cota     size_t i;
487be2cdc5eSEmilio G. Cota 
488be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
489be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
490be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
491be2cdc5eSEmilio G. Cota 
492be2cdc5eSEmilio G. Cota         g_tree_foreach(rt->tree, func, user_data);
493be2cdc5eSEmilio G. Cota     }
494be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
495be2cdc5eSEmilio G. Cota }
496be2cdc5eSEmilio G. Cota 
497be2cdc5eSEmilio G. Cota size_t tcg_nb_tbs(void)
498be2cdc5eSEmilio G. Cota {
499be2cdc5eSEmilio G. Cota     size_t nb_tbs = 0;
500be2cdc5eSEmilio G. Cota     size_t i;
501be2cdc5eSEmilio G. Cota 
502be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
503be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
504be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
505be2cdc5eSEmilio G. Cota 
506be2cdc5eSEmilio G. Cota         nb_tbs += g_tree_nnodes(rt->tree);
507be2cdc5eSEmilio G. Cota     }
508be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
509be2cdc5eSEmilio G. Cota     return nb_tbs;
510be2cdc5eSEmilio G. Cota }
511be2cdc5eSEmilio G. Cota 
512938e897aSEmilio G. Cota static gboolean tcg_region_tree_traverse(gpointer k, gpointer v, gpointer data)
513938e897aSEmilio G. Cota {
514938e897aSEmilio G. Cota     TranslationBlock *tb = v;
515938e897aSEmilio G. Cota 
516938e897aSEmilio G. Cota     tb_destroy(tb);
517938e897aSEmilio G. Cota     return FALSE;
518938e897aSEmilio G. Cota }
519938e897aSEmilio G. Cota 
520be2cdc5eSEmilio G. Cota static void tcg_region_tree_reset_all(void)
521be2cdc5eSEmilio G. Cota {
522be2cdc5eSEmilio G. Cota     size_t i;
523be2cdc5eSEmilio G. Cota 
524be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
525be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
526be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
527be2cdc5eSEmilio G. Cota 
528938e897aSEmilio G. Cota         g_tree_foreach(rt->tree, tcg_region_tree_traverse, NULL);
529be2cdc5eSEmilio G. Cota         /* Increment the refcount first so that destroy acts as a reset */
530be2cdc5eSEmilio G. Cota         g_tree_ref(rt->tree);
531be2cdc5eSEmilio G. Cota         g_tree_destroy(rt->tree);
532be2cdc5eSEmilio G. Cota     }
533be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
534be2cdc5eSEmilio G. Cota }
535be2cdc5eSEmilio G. Cota 
536e8feb96fSEmilio G. Cota static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend)
537e8feb96fSEmilio G. Cota {
538e8feb96fSEmilio G. Cota     void *start, *end;
539e8feb96fSEmilio G. Cota 
540e8feb96fSEmilio G. Cota     start = region.start_aligned + curr_region * region.stride;
541e8feb96fSEmilio G. Cota     end = start + region.size;
542e8feb96fSEmilio G. Cota 
543e8feb96fSEmilio G. Cota     if (curr_region == 0) {
544e8feb96fSEmilio G. Cota         start = region.start;
545e8feb96fSEmilio G. Cota     }
546e8feb96fSEmilio G. Cota     if (curr_region == region.n - 1) {
547e8feb96fSEmilio G. Cota         end = region.end;
548e8feb96fSEmilio G. Cota     }
549e8feb96fSEmilio G. Cota 
550e8feb96fSEmilio G. Cota     *pstart = start;
551e8feb96fSEmilio G. Cota     *pend = end;
552e8feb96fSEmilio G. Cota }
553e8feb96fSEmilio G. Cota 
554e8feb96fSEmilio G. Cota static void tcg_region_assign(TCGContext *s, size_t curr_region)
555e8feb96fSEmilio G. Cota {
556e8feb96fSEmilio G. Cota     void *start, *end;
557e8feb96fSEmilio G. Cota 
558e8feb96fSEmilio G. Cota     tcg_region_bounds(curr_region, &start, &end);
559e8feb96fSEmilio G. Cota 
560e8feb96fSEmilio G. Cota     s->code_gen_buffer = start;
561e8feb96fSEmilio G. Cota     s->code_gen_ptr = start;
562e8feb96fSEmilio G. Cota     s->code_gen_buffer_size = end - start;
563e8feb96fSEmilio G. Cota     s->code_gen_highwater = end - TCG_HIGHWATER;
564e8feb96fSEmilio G. Cota }
565e8feb96fSEmilio G. Cota 
566e8feb96fSEmilio G. Cota static bool tcg_region_alloc__locked(TCGContext *s)
567e8feb96fSEmilio G. Cota {
568e8feb96fSEmilio G. Cota     if (region.current == region.n) {
569e8feb96fSEmilio G. Cota         return true;
570e8feb96fSEmilio G. Cota     }
571e8feb96fSEmilio G. Cota     tcg_region_assign(s, region.current);
572e8feb96fSEmilio G. Cota     region.current++;
573e8feb96fSEmilio G. Cota     return false;
574e8feb96fSEmilio G. Cota }
575e8feb96fSEmilio G. Cota 
576e8feb96fSEmilio G. Cota /*
577e8feb96fSEmilio G. Cota  * Request a new region once the one in use has filled up.
578e8feb96fSEmilio G. Cota  * Returns true on error.
579e8feb96fSEmilio G. Cota  */
580e8feb96fSEmilio G. Cota static bool tcg_region_alloc(TCGContext *s)
581e8feb96fSEmilio G. Cota {
582e8feb96fSEmilio G. Cota     bool err;
583e8feb96fSEmilio G. Cota     /* read the region size now; alloc__locked will overwrite it on success */
584e8feb96fSEmilio G. Cota     size_t size_full = s->code_gen_buffer_size;
585e8feb96fSEmilio G. Cota 
586e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
587e8feb96fSEmilio G. Cota     err = tcg_region_alloc__locked(s);
588e8feb96fSEmilio G. Cota     if (!err) {
589e8feb96fSEmilio G. Cota         region.agg_size_full += size_full - TCG_HIGHWATER;
590e8feb96fSEmilio G. Cota     }
591e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
592e8feb96fSEmilio G. Cota     return err;
593e8feb96fSEmilio G. Cota }
594e8feb96fSEmilio G. Cota 
595e8feb96fSEmilio G. Cota /*
596e8feb96fSEmilio G. Cota  * Perform a context's first region allocation.
597e8feb96fSEmilio G. Cota  * This function does _not_ increment region.agg_size_full.
598e8feb96fSEmilio G. Cota  */
599e8feb96fSEmilio G. Cota static inline bool tcg_region_initial_alloc__locked(TCGContext *s)
600e8feb96fSEmilio G. Cota {
601e8feb96fSEmilio G. Cota     return tcg_region_alloc__locked(s);
602e8feb96fSEmilio G. Cota }
603e8feb96fSEmilio G. Cota 
604e8feb96fSEmilio G. Cota /* Call from a safe-work context */
605e8feb96fSEmilio G. Cota void tcg_region_reset_all(void)
606e8feb96fSEmilio G. Cota {
607d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
608e8feb96fSEmilio G. Cota     unsigned int i;
609e8feb96fSEmilio G. Cota 
610e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
611e8feb96fSEmilio G. Cota     region.current = 0;
612e8feb96fSEmilio G. Cota     region.agg_size_full = 0;
613e8feb96fSEmilio G. Cota 
6143468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
615d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
6163468b59eSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(s);
617e8feb96fSEmilio G. Cota 
618e8feb96fSEmilio G. Cota         g_assert(!err);
619e8feb96fSEmilio G. Cota     }
620e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
621be2cdc5eSEmilio G. Cota 
622be2cdc5eSEmilio G. Cota     tcg_region_tree_reset_all();
623e8feb96fSEmilio G. Cota }
624e8feb96fSEmilio G. Cota 
6253468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
6263468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
6273468b59eSEmilio G. Cota {
6283468b59eSEmilio G. Cota     return 1;
6293468b59eSEmilio G. Cota }
6303468b59eSEmilio G. Cota #else
6313468b59eSEmilio G. Cota /*
6323468b59eSEmilio G. Cota  * It is likely that some vCPUs will translate more code than others, so we
6333468b59eSEmilio G. Cota  * first try to set more regions than max_cpus, with those regions being of
6343468b59eSEmilio G. Cota  * reasonable size. If that's not possible we make do by evenly dividing
6353468b59eSEmilio G. Cota  * the code_gen_buffer among the vCPUs.
6363468b59eSEmilio G. Cota  */
6373468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
6383468b59eSEmilio G. Cota {
6393468b59eSEmilio G. Cota     size_t i;
6403468b59eSEmilio G. Cota 
6413468b59eSEmilio G. Cota     /* Use a single region if all we have is one vCPU thread */
6425cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY)
6435cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
6445cc8767dSLike Xu     unsigned int max_cpus = ms->smp.max_cpus;
6455cc8767dSLike Xu #endif
6463468b59eSEmilio G. Cota     if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) {
6473468b59eSEmilio G. Cota         return 1;
6483468b59eSEmilio G. Cota     }
6493468b59eSEmilio G. Cota 
6503468b59eSEmilio G. Cota     /* Try to have more regions than max_cpus, with each region being >= 2 MB */
6513468b59eSEmilio G. Cota     for (i = 8; i > 0; i--) {
6523468b59eSEmilio G. Cota         size_t regions_per_thread = i;
6533468b59eSEmilio G. Cota         size_t region_size;
6543468b59eSEmilio G. Cota 
6553468b59eSEmilio G. Cota         region_size = tcg_init_ctx.code_gen_buffer_size;
6563468b59eSEmilio G. Cota         region_size /= max_cpus * regions_per_thread;
6573468b59eSEmilio G. Cota 
6583468b59eSEmilio G. Cota         if (region_size >= 2 * 1024u * 1024) {
6593468b59eSEmilio G. Cota             return max_cpus * regions_per_thread;
6603468b59eSEmilio G. Cota         }
6613468b59eSEmilio G. Cota     }
6623468b59eSEmilio G. Cota     /* If we can't, then just allocate one region per vCPU thread */
6633468b59eSEmilio G. Cota     return max_cpus;
6643468b59eSEmilio G. Cota }
6653468b59eSEmilio G. Cota #endif
6663468b59eSEmilio G. Cota 
667e8feb96fSEmilio G. Cota /*
668e8feb96fSEmilio G. Cota  * Initializes region partitioning.
669e8feb96fSEmilio G. Cota  *
670e8feb96fSEmilio G. Cota  * Called at init time from the parent thread (i.e. the one calling
671e8feb96fSEmilio G. Cota  * tcg_context_init), after the target's TCG globals have been set.
6723468b59eSEmilio G. Cota  *
6733468b59eSEmilio G. Cota  * Region partitioning works by splitting code_gen_buffer into separate regions,
6743468b59eSEmilio G. Cota  * and then assigning regions to TCG threads so that the threads can translate
6753468b59eSEmilio G. Cota  * code in parallel without synchronization.
6763468b59eSEmilio G. Cota  *
6773468b59eSEmilio G. Cota  * In softmmu the number of TCG threads is bounded by max_cpus, so we use at
6783468b59eSEmilio G. Cota  * least max_cpus regions in MTTCG. In !MTTCG we use a single region.
6793468b59eSEmilio G. Cota  * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...])
6803468b59eSEmilio G. Cota  * must have been parsed before calling this function, since it calls
6813468b59eSEmilio G. Cota  * qemu_tcg_mttcg_enabled().
6823468b59eSEmilio G. Cota  *
6833468b59eSEmilio G. Cota  * In user-mode we use a single region.  Having multiple regions in user-mode
6843468b59eSEmilio G. Cota  * is not supported, because the number of vCPU threads (recall that each thread
6853468b59eSEmilio G. Cota  * spawned by the guest corresponds to a vCPU thread) is only bounded by the
6863468b59eSEmilio G. Cota  * OS, and usually this number is huge (tens of thousands is not uncommon).
6873468b59eSEmilio G. Cota  * Thus, given this large bound on the number of vCPU threads and the fact
6883468b59eSEmilio G. Cota  * that code_gen_buffer is allocated at compile-time, we cannot guarantee
6893468b59eSEmilio G. Cota  * that the availability of at least one region per vCPU thread.
6903468b59eSEmilio G. Cota  *
6913468b59eSEmilio G. Cota  * However, this user-mode limitation is unlikely to be a significant problem
6923468b59eSEmilio G. Cota  * in practice. Multi-threaded guests share most if not all of their translated
6933468b59eSEmilio G. Cota  * code, which makes parallel code generation less appealing than in softmmu.
694e8feb96fSEmilio G. Cota  */
695e8feb96fSEmilio G. Cota void tcg_region_init(void)
696e8feb96fSEmilio G. Cota {
697e8feb96fSEmilio G. Cota     void *buf = tcg_init_ctx.code_gen_buffer;
698e8feb96fSEmilio G. Cota     void *aligned;
699e8feb96fSEmilio G. Cota     size_t size = tcg_init_ctx.code_gen_buffer_size;
700e8feb96fSEmilio G. Cota     size_t page_size = qemu_real_host_page_size;
701e8feb96fSEmilio G. Cota     size_t region_size;
702e8feb96fSEmilio G. Cota     size_t n_regions;
703e8feb96fSEmilio G. Cota     size_t i;
704e8feb96fSEmilio G. Cota 
7053468b59eSEmilio G. Cota     n_regions = tcg_n_regions();
706e8feb96fSEmilio G. Cota 
707e8feb96fSEmilio G. Cota     /* The first region will be 'aligned - buf' bytes larger than the others */
708e8feb96fSEmilio G. Cota     aligned = QEMU_ALIGN_PTR_UP(buf, page_size);
709e8feb96fSEmilio G. Cota     g_assert(aligned < tcg_init_ctx.code_gen_buffer + size);
710e8feb96fSEmilio G. Cota     /*
711e8feb96fSEmilio G. Cota      * Make region_size a multiple of page_size, using aligned as the start.
712e8feb96fSEmilio G. Cota      * As a result of this we might end up with a few extra pages at the end of
713e8feb96fSEmilio G. Cota      * the buffer; we will assign those to the last region.
714e8feb96fSEmilio G. Cota      */
715e8feb96fSEmilio G. Cota     region_size = (size - (aligned - buf)) / n_regions;
716e8feb96fSEmilio G. Cota     region_size = QEMU_ALIGN_DOWN(region_size, page_size);
717e8feb96fSEmilio G. Cota 
718e8feb96fSEmilio G. Cota     /* A region must have at least 2 pages; one code, one guard */
719e8feb96fSEmilio G. Cota     g_assert(region_size >= 2 * page_size);
720e8feb96fSEmilio G. Cota 
721e8feb96fSEmilio G. Cota     /* init the region struct */
722e8feb96fSEmilio G. Cota     qemu_mutex_init(&region.lock);
723e8feb96fSEmilio G. Cota     region.n = n_regions;
724e8feb96fSEmilio G. Cota     region.size = region_size - page_size;
725e8feb96fSEmilio G. Cota     region.stride = region_size;
726e8feb96fSEmilio G. Cota     region.start = buf;
727e8feb96fSEmilio G. Cota     region.start_aligned = aligned;
728e8feb96fSEmilio G. Cota     /* page-align the end, since its last page will be a guard page */
729e8feb96fSEmilio G. Cota     region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size);
730e8feb96fSEmilio G. Cota     /* account for that last guard page */
731e8feb96fSEmilio G. Cota     region.end -= page_size;
732e8feb96fSEmilio G. Cota 
733e8feb96fSEmilio G. Cota     /* set guard pages */
734e8feb96fSEmilio G. Cota     for (i = 0; i < region.n; i++) {
735e8feb96fSEmilio G. Cota         void *start, *end;
736e8feb96fSEmilio G. Cota         int rc;
737e8feb96fSEmilio G. Cota 
738e8feb96fSEmilio G. Cota         tcg_region_bounds(i, &start, &end);
739e8feb96fSEmilio G. Cota         rc = qemu_mprotect_none(end, page_size);
740e8feb96fSEmilio G. Cota         g_assert(!rc);
741e8feb96fSEmilio G. Cota     }
742e8feb96fSEmilio G. Cota 
743be2cdc5eSEmilio G. Cota     tcg_region_trees_init();
744be2cdc5eSEmilio G. Cota 
7453468b59eSEmilio G. Cota     /* In user-mode we support only one ctx, so do the initial allocation now */
7463468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
747e8feb96fSEmilio G. Cota     {
748e8feb96fSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(tcg_ctx);
749e8feb96fSEmilio G. Cota 
750e8feb96fSEmilio G. Cota         g_assert(!err);
751e8feb96fSEmilio G. Cota     }
7523468b59eSEmilio G. Cota #endif
753e8feb96fSEmilio G. Cota }
754e8feb96fSEmilio G. Cota 
75538b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s)
75638b47b19SEmilio G. Cota {
75738b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
75838b47b19SEmilio G. Cota     s->plugin_tb = g_new0(struct qemu_plugin_tb, 1);
75938b47b19SEmilio G. Cota     s->plugin_tb->insns =
76038b47b19SEmilio G. Cota         g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn);
76138b47b19SEmilio G. Cota #endif
76238b47b19SEmilio G. Cota }
76338b47b19SEmilio G. Cota 
764e8feb96fSEmilio G. Cota /*
7653468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
7663468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
7673468b59eSEmilio G. Cota  * before initiating translation.
7683468b59eSEmilio G. Cota  *
7693468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
7703468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
7713468b59eSEmilio G. Cota  *
7723468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
7733468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
7743468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
7753468b59eSEmilio G. Cota  *
7763468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
7773468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
7783468b59eSEmilio G. Cota  */
7793468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
7803468b59eSEmilio G. Cota void tcg_register_thread(void)
7813468b59eSEmilio G. Cota {
7823468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
7833468b59eSEmilio G. Cota }
7843468b59eSEmilio G. Cota #else
7853468b59eSEmilio G. Cota void tcg_register_thread(void)
7863468b59eSEmilio G. Cota {
7875cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
7883468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
7893468b59eSEmilio G. Cota     unsigned int i, n;
7903468b59eSEmilio G. Cota     bool err;
7913468b59eSEmilio G. Cota 
7923468b59eSEmilio G. Cota     *s = tcg_init_ctx;
7933468b59eSEmilio G. Cota 
7943468b59eSEmilio G. Cota     /* Relink mem_base.  */
7953468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
7963468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
7973468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
7983468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
7993468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
8003468b59eSEmilio G. Cota         }
8013468b59eSEmilio G. Cota     }
8023468b59eSEmilio G. Cota 
8033468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
804d73415a3SStefan Hajnoczi     n = qatomic_fetch_inc(&n_tcg_ctxs);
8055cc8767dSLike Xu     g_assert(n < ms->smp.max_cpus);
806d73415a3SStefan Hajnoczi     qatomic_set(&tcg_ctxs[n], s);
8073468b59eSEmilio G. Cota 
80838b47b19SEmilio G. Cota     if (n > 0) {
80938b47b19SEmilio G. Cota         alloc_tcg_plugin_context(s);
81038b47b19SEmilio G. Cota     }
81138b47b19SEmilio G. Cota 
8123468b59eSEmilio G. Cota     tcg_ctx = s;
8133468b59eSEmilio G. Cota     qemu_mutex_lock(&region.lock);
8143468b59eSEmilio G. Cota     err = tcg_region_initial_alloc__locked(tcg_ctx);
8153468b59eSEmilio G. Cota     g_assert(!err);
8163468b59eSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
8173468b59eSEmilio G. Cota }
8183468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
8193468b59eSEmilio G. Cota 
8203468b59eSEmilio G. Cota /*
821e8feb96fSEmilio G. Cota  * Returns the size (in bytes) of all translated code (i.e. from all regions)
822e8feb96fSEmilio G. Cota  * currently in the cache.
823e8feb96fSEmilio G. Cota  * See also: tcg_code_capacity()
824e8feb96fSEmilio G. Cota  * Do not confuse with tcg_current_code_size(); that one applies to a single
825e8feb96fSEmilio G. Cota  * TCG context.
826e8feb96fSEmilio G. Cota  */
827e8feb96fSEmilio G. Cota size_t tcg_code_size(void)
828e8feb96fSEmilio G. Cota {
829d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
830e8feb96fSEmilio G. Cota     unsigned int i;
831e8feb96fSEmilio G. Cota     size_t total;
832e8feb96fSEmilio G. Cota 
833e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
834e8feb96fSEmilio G. Cota     total = region.agg_size_full;
8353468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
836d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
837e8feb96fSEmilio G. Cota         size_t size;
838e8feb96fSEmilio G. Cota 
839d73415a3SStefan Hajnoczi         size = qatomic_read(&s->code_gen_ptr) - s->code_gen_buffer;
840e8feb96fSEmilio G. Cota         g_assert(size <= s->code_gen_buffer_size);
841e8feb96fSEmilio G. Cota         total += size;
842e8feb96fSEmilio G. Cota     }
843e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
844e8feb96fSEmilio G. Cota     return total;
845e8feb96fSEmilio G. Cota }
846e8feb96fSEmilio G. Cota 
847e8feb96fSEmilio G. Cota /*
848e8feb96fSEmilio G. Cota  * Returns the code capacity (in bytes) of the entire cache, i.e. including all
849e8feb96fSEmilio G. Cota  * regions.
850e8feb96fSEmilio G. Cota  * See also: tcg_code_size()
851e8feb96fSEmilio G. Cota  */
852e8feb96fSEmilio G. Cota size_t tcg_code_capacity(void)
853e8feb96fSEmilio G. Cota {
854e8feb96fSEmilio G. Cota     size_t guard_size, capacity;
855e8feb96fSEmilio G. Cota 
856e8feb96fSEmilio G. Cota     /* no need for synchronization; these variables are set at init time */
857e8feb96fSEmilio G. Cota     guard_size = region.stride - region.size;
858e8feb96fSEmilio G. Cota     capacity = region.end + guard_size - region.start;
859e8feb96fSEmilio G. Cota     capacity -= region.n * (guard_size + TCG_HIGHWATER);
860e8feb96fSEmilio G. Cota     return capacity;
861e8feb96fSEmilio G. Cota }
862e8feb96fSEmilio G. Cota 
863128ed227SEmilio G. Cota size_t tcg_tb_phys_invalidate_count(void)
864128ed227SEmilio G. Cota {
865d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
866128ed227SEmilio G. Cota     unsigned int i;
867128ed227SEmilio G. Cota     size_t total = 0;
868128ed227SEmilio G. Cota 
869128ed227SEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
870d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
871128ed227SEmilio G. Cota 
872d73415a3SStefan Hajnoczi         total += qatomic_read(&s->tb_phys_invalidate_count);
873128ed227SEmilio G. Cota     }
874128ed227SEmilio G. Cota     return total;
875128ed227SEmilio G. Cota }
876128ed227SEmilio G. Cota 
877c896fe29Sbellard /* pool based memory allocation */
878c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
879c896fe29Sbellard {
880c896fe29Sbellard     TCGPool *p;
881c896fe29Sbellard     int pool_size;
882c896fe29Sbellard 
883c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
884c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
8857267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
886c896fe29Sbellard         p->size = size;
8874055299eSKirill Batuzov         p->next = s->pool_first_large;
8884055299eSKirill Batuzov         s->pool_first_large = p;
8894055299eSKirill Batuzov         return p->data;
890c896fe29Sbellard     } else {
891c896fe29Sbellard         p = s->pool_current;
892c896fe29Sbellard         if (!p) {
893c896fe29Sbellard             p = s->pool_first;
894c896fe29Sbellard             if (!p)
895c896fe29Sbellard                 goto new_pool;
896c896fe29Sbellard         } else {
897c896fe29Sbellard             if (!p->next) {
898c896fe29Sbellard             new_pool:
899c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
9007267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
901c896fe29Sbellard                 p->size = pool_size;
902c896fe29Sbellard                 p->next = NULL;
903c896fe29Sbellard                 if (s->pool_current)
904c896fe29Sbellard                     s->pool_current->next = p;
905c896fe29Sbellard                 else
906c896fe29Sbellard                     s->pool_first = p;
907c896fe29Sbellard             } else {
908c896fe29Sbellard                 p = p->next;
909c896fe29Sbellard             }
910c896fe29Sbellard         }
911c896fe29Sbellard     }
912c896fe29Sbellard     s->pool_current = p;
913c896fe29Sbellard     s->pool_cur = p->data + size;
914c896fe29Sbellard     s->pool_end = p->data + p->size;
915c896fe29Sbellard     return p->data;
916c896fe29Sbellard }
917c896fe29Sbellard 
918c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
919c896fe29Sbellard {
9204055299eSKirill Batuzov     TCGPool *p, *t;
9214055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
9224055299eSKirill Batuzov         t = p->next;
9234055299eSKirill Batuzov         g_free(p);
9244055299eSKirill Batuzov     }
9254055299eSKirill Batuzov     s->pool_first_large = NULL;
926c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
927c896fe29Sbellard     s->pool_current = NULL;
928c896fe29Sbellard }
929c896fe29Sbellard 
930100b5e01SRichard Henderson typedef struct TCGHelperInfo {
931100b5e01SRichard Henderson     void *func;
932100b5e01SRichard Henderson     const char *name;
933afb49896SRichard Henderson     unsigned flags;
934afb49896SRichard Henderson     unsigned sizemask;
935100b5e01SRichard Henderson } TCGHelperInfo;
936100b5e01SRichard Henderson 
9372ef6175aSRichard Henderson #include "exec/helper-proto.h"
9382ef6175aSRichard Henderson 
939100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = {
9402ef6175aSRichard Henderson #include "exec/helper-tcg.h"
941100b5e01SRichard Henderson };
942619205fdSEmilio G. Cota static GHashTable *helper_table;
943100b5e01SRichard Henderson 
94491478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
945f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
9461c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
9471c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
94891478cefSRichard Henderson 
949c896fe29Sbellard void tcg_context_init(TCGContext *s)
950c896fe29Sbellard {
951100b5e01SRichard Henderson     int op, total_args, n, i;
952c896fe29Sbellard     TCGOpDef *def;
953c896fe29Sbellard     TCGArgConstraint *args_ct;
9541c2adb95SRichard Henderson     TCGTemp *ts;
955c896fe29Sbellard 
956c896fe29Sbellard     memset(s, 0, sizeof(*s));
957c896fe29Sbellard     s->nb_globals = 0;
958c896fe29Sbellard 
959c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
960c896fe29Sbellard        space */
961c896fe29Sbellard     total_args = 0;
962c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
963c896fe29Sbellard         def = &tcg_op_defs[op];
964c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
965c896fe29Sbellard         total_args += n;
966c896fe29Sbellard     }
967c896fe29Sbellard 
968bc2b17e6SRichard Henderson     args_ct = g_new0(TCGArgConstraint, total_args);
969c896fe29Sbellard 
970c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
971c896fe29Sbellard         def = &tcg_op_defs[op];
972c896fe29Sbellard         def->args_ct = args_ct;
973c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
974c896fe29Sbellard         args_ct += n;
975c896fe29Sbellard     }
976c896fe29Sbellard 
9775cd8f621SRichard Henderson     /* Register helpers.  */
97884fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
979619205fdSEmilio G. Cota     helper_table = g_hash_table_new(NULL, NULL);
98084fd9dd3SRichard Henderson 
981100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
98284fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
98372866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
984100b5e01SRichard Henderson     }
9855cd8f621SRichard Henderson 
986c896fe29Sbellard     tcg_target_init(s);
987f69d277eSRichard Henderson     process_op_defs(s);
98891478cefSRichard Henderson 
98991478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
99091478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
99191478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
99291478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
99391478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
99491478cefSRichard Henderson             break;
99591478cefSRichard Henderson         }
99691478cefSRichard Henderson     }
99791478cefSRichard Henderson     for (i = 0; i < n; ++i) {
99891478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
99991478cefSRichard Henderson     }
100091478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
100191478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
100291478cefSRichard Henderson     }
1003b1311c4aSEmilio G. Cota 
100438b47b19SEmilio G. Cota     alloc_tcg_plugin_context(s);
100538b47b19SEmilio G. Cota 
1006b1311c4aSEmilio G. Cota     tcg_ctx = s;
10073468b59eSEmilio G. Cota     /*
10083468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
10093468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
10103468b59eSEmilio G. Cota      * reasoning behind this.
10113468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
10123468b59eSEmilio G. Cota      */
10133468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
1014df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
1015df2cce29SEmilio G. Cota     n_tcg_ctxs = 1;
10163468b59eSEmilio G. Cota #else
10175cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
10185cc8767dSLike Xu     unsigned int max_cpus = ms->smp.max_cpus;
10193468b59eSEmilio G. Cota     tcg_ctxs = g_new(TCGContext *, max_cpus);
10203468b59eSEmilio G. Cota #endif
10211c2adb95SRichard Henderson 
10221c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
10231c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
10241c2adb95SRichard Henderson     cpu_env = temp_tcgv_ptr(ts);
10259002ec79SRichard Henderson }
1026b03cce8eSbellard 
10276e3b2bfdSEmilio G. Cota /*
10286e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
10296e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
10306e3b2bfdSEmilio G. Cota  */
10316e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
10326e3b2bfdSEmilio G. Cota {
10336e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
10346e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
10356e3b2bfdSEmilio G. Cota     void *next;
10366e3b2bfdSEmilio G. Cota 
1037e8feb96fSEmilio G. Cota  retry:
10386e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
10396e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
10406e3b2bfdSEmilio G. Cota 
10416e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
1042e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
10436e3b2bfdSEmilio G. Cota             return NULL;
10446e3b2bfdSEmilio G. Cota         }
1045e8feb96fSEmilio G. Cota         goto retry;
1046e8feb96fSEmilio G. Cota     }
1047d73415a3SStefan Hajnoczi     qatomic_set(&s->code_gen_ptr, next);
104857a26946SRichard Henderson     s->data_gen_ptr = NULL;
10496e3b2bfdSEmilio G. Cota     return tb;
10506e3b2bfdSEmilio G. Cota }
10516e3b2bfdSEmilio G. Cota 
10529002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
10539002ec79SRichard Henderson {
10548163b749SRichard Henderson     size_t prologue_size, total_size;
10558163b749SRichard Henderson     void *buf0, *buf1;
10568163b749SRichard Henderson 
10578163b749SRichard Henderson     /* Put the prologue at the beginning of code_gen_buffer.  */
10588163b749SRichard Henderson     buf0 = s->code_gen_buffer;
10595b38ee31SRichard Henderson     total_size = s->code_gen_buffer_size;
10608163b749SRichard Henderson     s->code_ptr = buf0;
10618163b749SRichard Henderson     s->code_buf = buf0;
10625b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
1063b91ccb31SRichard Henderson 
1064b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1065b91ccb31SRichard Henderson     tcg_qemu_tb_exec = (tcg_prologue_fn *)buf0;
1066b91ccb31SRichard Henderson #endif
10678163b749SRichard Henderson 
10685b38ee31SRichard Henderson     /* Compute a high-water mark, at which we voluntarily flush the buffer
10695b38ee31SRichard Henderson        and start over.  The size here is arbitrary, significantly larger
10705b38ee31SRichard Henderson        than we expect the code generation for any one opcode to require.  */
10715b38ee31SRichard Henderson     s->code_gen_highwater = s->code_gen_buffer + (total_size - TCG_HIGHWATER);
10725b38ee31SRichard Henderson 
10735b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
10745b38ee31SRichard Henderson     s->pool_labels = NULL;
10755b38ee31SRichard Henderson #endif
10765b38ee31SRichard Henderson 
10778163b749SRichard Henderson     /* Generate the prologue.  */
1078b03cce8eSbellard     tcg_target_qemu_prologue(s);
10795b38ee31SRichard Henderson 
10805b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
10815b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
10825b38ee31SRichard Henderson     {
10831768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
10841768987bSRichard Henderson         tcg_debug_assert(result == 0);
10855b38ee31SRichard Henderson     }
10865b38ee31SRichard Henderson #endif
10875b38ee31SRichard Henderson 
10888163b749SRichard Henderson     buf1 = s->code_ptr;
1089df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
10901da8de39SRichard Henderson     flush_idcache_range((uintptr_t)buf0, (uintptr_t)buf0,
10911da8de39SRichard Henderson                         tcg_ptr_byte_diff(buf1, buf0));
1092df5d2b16SRichard Henderson #endif
10938163b749SRichard Henderson 
10948163b749SRichard Henderson     /* Deduct the prologue from the buffer.  */
10958163b749SRichard Henderson     prologue_size = tcg_current_code_size(s);
10968163b749SRichard Henderson     s->code_gen_ptr = buf1;
10978163b749SRichard Henderson     s->code_gen_buffer = buf1;
10988163b749SRichard Henderson     s->code_buf = buf1;
10995b38ee31SRichard Henderson     total_size -= prologue_size;
11008163b749SRichard Henderson     s->code_gen_buffer_size = total_size;
11018163b749SRichard Henderson 
11028163b749SRichard Henderson     tcg_register_jit(s->code_gen_buffer, total_size);
1103d6b64b2bSRichard Henderson 
1104d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
1105d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
1106fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
11078163b749SRichard Henderson         qemu_log("PROLOGUE: [size=%zu]\n", prologue_size);
11085b38ee31SRichard Henderson         if (s->data_gen_ptr) {
11095b38ee31SRichard Henderson             size_t code_size = s->data_gen_ptr - buf0;
11105b38ee31SRichard Henderson             size_t data_size = prologue_size - code_size;
11115b38ee31SRichard Henderson             size_t i;
11125b38ee31SRichard Henderson 
11134c389f6eSRichard Henderson             log_disas(buf0, code_size);
11145b38ee31SRichard Henderson 
11155b38ee31SRichard Henderson             for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
11165b38ee31SRichard Henderson                 if (sizeof(tcg_target_ulong) == 8) {
11175b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
11185b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
11195b38ee31SRichard Henderson                              *(uint64_t *)(s->data_gen_ptr + i));
11205b38ee31SRichard Henderson                 } else {
11215b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .long  0x%08x\n",
11225b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
11235b38ee31SRichard Henderson                              *(uint32_t *)(s->data_gen_ptr + i));
11245b38ee31SRichard Henderson                 }
11255b38ee31SRichard Henderson             }
11265b38ee31SRichard Henderson         } else {
11274c389f6eSRichard Henderson             log_disas(buf0, prologue_size);
11285b38ee31SRichard Henderson         }
1129d6b64b2bSRichard Henderson         qemu_log("\n");
1130d6b64b2bSRichard Henderson         qemu_log_flush();
1131fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
1132d6b64b2bSRichard Henderson     }
1133d6b64b2bSRichard Henderson #endif
1134cedbcb01SEmilio G. Cota 
1135cedbcb01SEmilio G. Cota     /* Assert that goto_ptr is implemented completely.  */
1136cedbcb01SEmilio G. Cota     if (TCG_TARGET_HAS_goto_ptr) {
1137*8b5c2b62SRichard Henderson         tcg_debug_assert(tcg_code_gen_epilogue != NULL);
1138cedbcb01SEmilio G. Cota     }
1139c896fe29Sbellard }
1140c896fe29Sbellard 
1141c896fe29Sbellard void tcg_func_start(TCGContext *s)
1142c896fe29Sbellard {
1143c896fe29Sbellard     tcg_pool_reset(s);
1144c896fe29Sbellard     s->nb_temps = s->nb_globals;
11450ec9eabcSRichard Henderson 
11460ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
11470ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
11480ec9eabcSRichard Henderson 
1149abebf925SRichard Henderson     s->nb_ops = 0;
1150c896fe29Sbellard     s->nb_labels = 0;
1151c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1152c896fe29Sbellard 
11530a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
11540a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
11550a209d4bSRichard Henderson #endif
11560a209d4bSRichard Henderson 
115715fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
115815fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
1159bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
1160c896fe29Sbellard }
1161c896fe29Sbellard 
11627ca4b752SRichard Henderson static inline TCGTemp *tcg_temp_alloc(TCGContext *s)
11637ca4b752SRichard Henderson {
11647ca4b752SRichard Henderson     int n = s->nb_temps++;
11657ca4b752SRichard Henderson     tcg_debug_assert(n < TCG_MAX_TEMPS);
11667ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
11677ca4b752SRichard Henderson }
11687ca4b752SRichard Henderson 
11697ca4b752SRichard Henderson static inline TCGTemp *tcg_global_alloc(TCGContext *s)
11707ca4b752SRichard Henderson {
1171fa477d25SRichard Henderson     TCGTemp *ts;
1172fa477d25SRichard Henderson 
11737ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
11747ca4b752SRichard Henderson     s->nb_globals++;
1175fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1176fa477d25SRichard Henderson     ts->temp_global = 1;
1177fa477d25SRichard Henderson 
1178fa477d25SRichard Henderson     return ts;
1179c896fe29Sbellard }
1180c896fe29Sbellard 
1181085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1182b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1183c896fe29Sbellard {
1184c896fe29Sbellard     TCGTemp *ts;
1185c896fe29Sbellard 
1186b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
1187c896fe29Sbellard         tcg_abort();
1188b3a62939SRichard Henderson     }
11897ca4b752SRichard Henderson 
11907ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1191c896fe29Sbellard     ts->base_type = type;
1192c896fe29Sbellard     ts->type = type;
1193c896fe29Sbellard     ts->fixed_reg = 1;
1194c896fe29Sbellard     ts->reg = reg;
1195c896fe29Sbellard     ts->name = name;
1196c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
11977ca4b752SRichard Henderson 
1198085272b3SRichard Henderson     return ts;
1199a7812ae4Spbrook }
1200a7812ae4Spbrook 
1201b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1202a7812ae4Spbrook {
1203b3a62939SRichard Henderson     s->frame_start = start;
1204b3a62939SRichard Henderson     s->frame_end = start + size;
1205085272b3SRichard Henderson     s->frame_temp
1206085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1207b3a62939SRichard Henderson }
1208a7812ae4Spbrook 
1209085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
1210e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
1211c896fe29Sbellard {
1212b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1213dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
12147ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1215b3915dbbSRichard Henderson     int indirect_reg = 0, bigendian = 0;
12167ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
12177ca4b752SRichard Henderson     bigendian = 1;
12187ca4b752SRichard Henderson #endif
1219c896fe29Sbellard 
1220b3915dbbSRichard Henderson     if (!base_ts->fixed_reg) {
12215a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
12225a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1223b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
12245a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
12255a18407fSRichard Henderson                             ? 2 : 1);
12265a18407fSRichard Henderson         indirect_reg = 1;
1227b3915dbbSRichard Henderson     }
1228b3915dbbSRichard Henderson 
12297ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
12307ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1231c896fe29Sbellard         char buf[64];
12327ca4b752SRichard Henderson 
12337ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1234c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1235b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1236c896fe29Sbellard         ts->mem_allocated = 1;
1237b3a62939SRichard Henderson         ts->mem_base = base_ts;
12387ca4b752SRichard Henderson         ts->mem_offset = offset + bigendian * 4;
1239c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1240c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1241c896fe29Sbellard         ts->name = strdup(buf);
1242c896fe29Sbellard 
12437ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
12447ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
12457ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1246b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
12477ca4b752SRichard Henderson         ts2->mem_allocated = 1;
12487ca4b752SRichard Henderson         ts2->mem_base = base_ts;
12497ca4b752SRichard Henderson         ts2->mem_offset = offset + (1 - bigendian) * 4;
1250c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1251c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1252120c1084SRichard Henderson         ts2->name = strdup(buf);
12537ca4b752SRichard Henderson     } else {
1254c896fe29Sbellard         ts->base_type = type;
1255c896fe29Sbellard         ts->type = type;
1256b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1257c896fe29Sbellard         ts->mem_allocated = 1;
1258b3a62939SRichard Henderson         ts->mem_base = base_ts;
1259c896fe29Sbellard         ts->mem_offset = offset;
1260c896fe29Sbellard         ts->name = name;
1261c896fe29Sbellard     }
1262085272b3SRichard Henderson     return ts;
1263c896fe29Sbellard }
1264c896fe29Sbellard 
12655bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local)
1266c896fe29Sbellard {
1267b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1268c896fe29Sbellard     TCGTemp *ts;
1269641d5fbeSbellard     int idx, k;
1270c896fe29Sbellard 
12710ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
12720ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
12730ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
12740ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
12750ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
12760ec9eabcSRichard Henderson 
1277e8996ee0Sbellard         ts = &s->temps[idx];
1278e8996ee0Sbellard         ts->temp_allocated = 1;
12797ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
12807ca4b752SRichard Henderson         tcg_debug_assert(ts->temp_local == temp_local);
1281e8996ee0Sbellard     } else {
12827ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
12837ca4b752SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
12847ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
12857ca4b752SRichard Henderson 
1286c896fe29Sbellard             ts->base_type = type;
1287c896fe29Sbellard             ts->type = TCG_TYPE_I32;
1288e8996ee0Sbellard             ts->temp_allocated = 1;
1289641d5fbeSbellard             ts->temp_local = temp_local;
12907ca4b752SRichard Henderson 
12917ca4b752SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
12927ca4b752SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
12937ca4b752SRichard Henderson             ts2->type = TCG_TYPE_I32;
12947ca4b752SRichard Henderson             ts2->temp_allocated = 1;
12957ca4b752SRichard Henderson             ts2->temp_local = temp_local;
12967ca4b752SRichard Henderson         } else {
1297c896fe29Sbellard             ts->base_type = type;
1298c896fe29Sbellard             ts->type = type;
1299e8996ee0Sbellard             ts->temp_allocated = 1;
1300641d5fbeSbellard             ts->temp_local = temp_local;
1301c896fe29Sbellard         }
1302e8996ee0Sbellard     }
130327bfd83cSPeter Maydell 
130427bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
130527bfd83cSPeter Maydell     s->temps_in_use++;
130627bfd83cSPeter Maydell #endif
1307085272b3SRichard Henderson     return ts;
1308c896fe29Sbellard }
1309c896fe29Sbellard 
1310d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1311d2fd745fSRichard Henderson {
1312d2fd745fSRichard Henderson     TCGTemp *t;
1313d2fd745fSRichard Henderson 
1314d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1315d2fd745fSRichard Henderson     switch (type) {
1316d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1317d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1318d2fd745fSRichard Henderson         break;
1319d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1320d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1321d2fd745fSRichard Henderson         break;
1322d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1323d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1324d2fd745fSRichard Henderson         break;
1325d2fd745fSRichard Henderson     default:
1326d2fd745fSRichard Henderson         g_assert_not_reached();
1327d2fd745fSRichard Henderson     }
1328d2fd745fSRichard Henderson #endif
1329d2fd745fSRichard Henderson 
1330d2fd745fSRichard Henderson     t = tcg_temp_new_internal(type, 0);
1331d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1332d2fd745fSRichard Henderson }
1333d2fd745fSRichard Henderson 
1334d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1335d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1336d2fd745fSRichard Henderson {
1337d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1338d2fd745fSRichard Henderson 
1339d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1340d2fd745fSRichard Henderson 
1341d2fd745fSRichard Henderson     t = tcg_temp_new_internal(t->base_type, 0);
1342d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1343d2fd745fSRichard Henderson }
1344d2fd745fSRichard Henderson 
13455bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1346c896fe29Sbellard {
1347b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1348085272b3SRichard Henderson     int k, idx;
1349c896fe29Sbellard 
135027bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
135127bfd83cSPeter Maydell     s->temps_in_use--;
135227bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
135327bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
135427bfd83cSPeter Maydell     }
135527bfd83cSPeter Maydell #endif
135627bfd83cSPeter Maydell 
1357085272b3SRichard Henderson     tcg_debug_assert(ts->temp_global == 0);
1358eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
1359e8996ee0Sbellard     ts->temp_allocated = 0;
13600ec9eabcSRichard Henderson 
1361085272b3SRichard Henderson     idx = temp_idx(ts);
136218d13fa2SAlexander Graf     k = ts->base_type + (ts->temp_local ? TCG_TYPE_COUNT : 0);
13630ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
1364e8996ee0Sbellard }
1365e8996ee0Sbellard 
1366a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
1367a7812ae4Spbrook {
1368a7812ae4Spbrook     TCGv_i32 t0;
1369a7812ae4Spbrook     t0 = tcg_temp_new_i32();
1370e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
1371e8996ee0Sbellard     return t0;
1372c896fe29Sbellard }
1373c896fe29Sbellard 
1374a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
1375c896fe29Sbellard {
1376a7812ae4Spbrook     TCGv_i64 t0;
1377a7812ae4Spbrook     t0 = tcg_temp_new_i64();
1378e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
1379e8996ee0Sbellard     return t0;
1380c896fe29Sbellard }
1381c896fe29Sbellard 
1382a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
1383bdffd4a9Saurel32 {
1384a7812ae4Spbrook     TCGv_i32 t0;
1385a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
1386bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
1387bdffd4a9Saurel32     return t0;
1388bdffd4a9Saurel32 }
1389bdffd4a9Saurel32 
1390a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
1391bdffd4a9Saurel32 {
1392a7812ae4Spbrook     TCGv_i64 t0;
1393a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
1394bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
1395bdffd4a9Saurel32     return t0;
1396bdffd4a9Saurel32 }
1397bdffd4a9Saurel32 
139827bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
139927bfd83cSPeter Maydell void tcg_clear_temp_count(void)
140027bfd83cSPeter Maydell {
1401b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
140227bfd83cSPeter Maydell     s->temps_in_use = 0;
140327bfd83cSPeter Maydell }
140427bfd83cSPeter Maydell 
140527bfd83cSPeter Maydell int tcg_check_temp_count(void)
140627bfd83cSPeter Maydell {
1407b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
140827bfd83cSPeter Maydell     if (s->temps_in_use) {
140927bfd83cSPeter Maydell         /* Clear the count so that we don't give another
141027bfd83cSPeter Maydell          * warning immediately next time around.
141127bfd83cSPeter Maydell          */
141227bfd83cSPeter Maydell         s->temps_in_use = 0;
141327bfd83cSPeter Maydell         return 1;
141427bfd83cSPeter Maydell     }
141527bfd83cSPeter Maydell     return 0;
141627bfd83cSPeter Maydell }
141727bfd83cSPeter Maydell #endif
141827bfd83cSPeter Maydell 
1419be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1420be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1421be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1422be0f34b5SRichard Henderson {
1423d2fd745fSRichard Henderson     const bool have_vec
1424d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1425d2fd745fSRichard Henderson 
1426be0f34b5SRichard Henderson     switch (op) {
1427be0f34b5SRichard Henderson     case INDEX_op_discard:
1428be0f34b5SRichard Henderson     case INDEX_op_set_label:
1429be0f34b5SRichard Henderson     case INDEX_op_call:
1430be0f34b5SRichard Henderson     case INDEX_op_br:
1431be0f34b5SRichard Henderson     case INDEX_op_mb:
1432be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1433be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1434be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1435be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i32:
1436be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i32:
1437be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i64:
1438be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i64:
1439be0f34b5SRichard Henderson         return true;
1440be0f34b5SRichard Henderson 
144107ce0b05SRichard Henderson     case INDEX_op_qemu_st8_i32:
144207ce0b05SRichard Henderson         return TCG_TARGET_HAS_qemu_st8_i32;
144307ce0b05SRichard Henderson 
1444be0f34b5SRichard Henderson     case INDEX_op_goto_ptr:
1445be0f34b5SRichard Henderson         return TCG_TARGET_HAS_goto_ptr;
1446be0f34b5SRichard Henderson 
1447be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1448be0f34b5SRichard Henderson     case INDEX_op_movi_i32:
1449be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1450be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1451be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1452be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1453be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1454be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1455be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1456be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1457be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1458be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1459be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1460be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1461be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1462be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1463be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1464be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1465be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1466be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1467be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1468be0f34b5SRichard Henderson         return true;
1469be0f34b5SRichard Henderson 
1470be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1471be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1472be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1473be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1474be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1475be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1476be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1477be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1478be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1479be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1480be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1481be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1482be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1483be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1484be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1485be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1486be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1487be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1488be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1489be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1490fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
1491fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
1492be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1493be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1494be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1495be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1496be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1497be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1498be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1499be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1500be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1501be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1502be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1503be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1504be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1505be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1506be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1507be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1508be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1509be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1510be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1511be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1512be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1513be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1514be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1515be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1516be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1517be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1518be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1519be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1520be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1521be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1522be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1523be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1524be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1525be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1526be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1527be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1528be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1529be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1530be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1531be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1532be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1533be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1534be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1535be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1536be0f34b5SRichard Henderson 
1537be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1538be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1539be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1540be0f34b5SRichard Henderson 
1541be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1542be0f34b5SRichard Henderson     case INDEX_op_movi_i64:
1543be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1544be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1545be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1546be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1547be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1548be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1549be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1550be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1551be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1552be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1553be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1554be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1555be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1556be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1557be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1558be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1559be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1560be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1561be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1562be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1563be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1564be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1565be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1566be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1567be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1568be0f34b5SRichard Henderson 
1569be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1570be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1571be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1572be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1573be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1574be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1575be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1576be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1577be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1578be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
1579be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
1580be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
1581be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
1582be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
1583be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
1584be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
1585be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
1586be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
1587be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
1588be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
1589fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
1590fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
1591be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
1592be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrl_i64_i32;
1593be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
1594be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrh_i64_i32;
1595be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
1596be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
1597be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
1598be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
1599be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
1600be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
1601be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
1602be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
1603be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
1604be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
1605be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
1606be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
1607be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
1608be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
1609be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
1610be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
1611be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
1612be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
1613be0f34b5SRichard Henderson     case INDEX_op_not_i64:
1614be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
1615be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
1616be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
1617be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
1618be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
1619be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
1620be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
1621be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
1622be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
1623be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
1624be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
1625be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
1626be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
1627be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
1628be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
1629be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
1630be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
1631be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
1632be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
1633be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
1634be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
1635be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
1636be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
1637be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
1638be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
1639be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
1640be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
1641be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
1642be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
1643be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
1644be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
1645be0f34b5SRichard Henderson 
1646d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
1647d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
1648d2fd745fSRichard Henderson     case INDEX_op_dupi_vec:
164937ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
1650d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
1651d2fd745fSRichard Henderson     case INDEX_op_st_vec:
1652d2fd745fSRichard Henderson     case INDEX_op_add_vec:
1653d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
1654d2fd745fSRichard Henderson     case INDEX_op_and_vec:
1655d2fd745fSRichard Henderson     case INDEX_op_or_vec:
1656d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
1657212be173SRichard Henderson     case INDEX_op_cmp_vec:
1658d2fd745fSRichard Henderson         return have_vec;
1659d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
1660d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
1661d2fd745fSRichard Henderson     case INDEX_op_not_vec:
1662d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
1663d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
1664d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
1665bcefc902SRichard Henderson     case INDEX_op_abs_vec:
1666bcefc902SRichard Henderson         return have_vec && TCG_TARGET_HAS_abs_vec;
1667d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
1668d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
1669d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
1670d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
16713774030aSRichard Henderson     case INDEX_op_mul_vec:
16723774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
1673d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
1674d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
1675d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
1676d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
1677d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
1678d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
1679d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
1680d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
1681d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
1682d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
1683d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
1684d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
1685b0f7e744SRichard Henderson     case INDEX_op_rotli_vec:
1686b0f7e744SRichard Henderson         return have_vec && TCG_TARGET_HAS_roti_vec;
168723850a74SRichard Henderson     case INDEX_op_rotls_vec:
168823850a74SRichard Henderson         return have_vec && TCG_TARGET_HAS_rots_vec;
16895d0ceda9SRichard Henderson     case INDEX_op_rotlv_vec:
16905d0ceda9SRichard Henderson     case INDEX_op_rotrv_vec:
16915d0ceda9SRichard Henderson         return have_vec && TCG_TARGET_HAS_rotv_vec;
16928afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
16938afaf050SRichard Henderson     case INDEX_op_usadd_vec:
16948afaf050SRichard Henderson     case INDEX_op_sssub_vec:
16958afaf050SRichard Henderson     case INDEX_op_ussub_vec:
16968afaf050SRichard Henderson         return have_vec && TCG_TARGET_HAS_sat_vec;
1697dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
1698dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
1699dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
1700dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
1701dd0a0fcdSRichard Henderson         return have_vec && TCG_TARGET_HAS_minmax_vec;
170238dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
170338dc1294SRichard Henderson         return have_vec && TCG_TARGET_HAS_bitsel_vec;
1704f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
1705f75da298SRichard Henderson         return have_vec && TCG_TARGET_HAS_cmpsel_vec;
1706d2fd745fSRichard Henderson 
1707db432672SRichard Henderson     default:
1708db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
1709db432672SRichard Henderson         return true;
1710be0f34b5SRichard Henderson     }
1711be0f34b5SRichard Henderson }
1712be0f34b5SRichard Henderson 
171339cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment
171439cf05d3Sbellard    and endian swap. Maybe it would be better to do the alignment
171539cf05d3Sbellard    and endian swap in tcg_reg_alloc_call(). */
1716ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
1717c896fe29Sbellard {
171875e8b9b7SRichard Henderson     int i, real_args, nb_rets, pi;
1719bbb8a1b4SRichard Henderson     unsigned sizemask, flags;
1720afb49896SRichard Henderson     TCGHelperInfo *info;
172175e8b9b7SRichard Henderson     TCGOp *op;
1722afb49896SRichard Henderson 
1723619205fdSEmilio G. Cota     info = g_hash_table_lookup(helper_table, (gpointer)func);
1724bbb8a1b4SRichard Henderson     flags = info->flags;
1725bbb8a1b4SRichard Henderson     sizemask = info->sizemask;
17262bece2c8SRichard Henderson 
172738b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
172838b47b19SEmilio G. Cota     /* detect non-plugin helpers */
172938b47b19SEmilio G. Cota     if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) {
173038b47b19SEmilio G. Cota         tcg_ctx->plugin_insn->calls_helpers = true;
173138b47b19SEmilio G. Cota     }
173238b47b19SEmilio G. Cota #endif
173338b47b19SEmilio G. Cota 
173434b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
173534b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
173634b1a49cSRichard Henderson     /* We have 64-bit values in one register, but need to pass as two
173734b1a49cSRichard Henderson        separate parameters.  Split them.  */
173834b1a49cSRichard Henderson     int orig_sizemask = sizemask;
173934b1a49cSRichard Henderson     int orig_nargs = nargs;
174034b1a49cSRichard Henderson     TCGv_i64 retl, reth;
1741ae8b75dcSRichard Henderson     TCGTemp *split_args[MAX_OPC_PARAM];
174234b1a49cSRichard Henderson 
1743f764718dSRichard Henderson     retl = NULL;
1744f764718dSRichard Henderson     reth = NULL;
174534b1a49cSRichard Henderson     if (sizemask != 0) {
174634b1a49cSRichard Henderson         for (i = real_args = 0; i < nargs; ++i) {
174734b1a49cSRichard Henderson             int is_64bit = sizemask & (1 << (i+1)*2);
174834b1a49cSRichard Henderson             if (is_64bit) {
1749085272b3SRichard Henderson                 TCGv_i64 orig = temp_tcgv_i64(args[i]);
175034b1a49cSRichard Henderson                 TCGv_i32 h = tcg_temp_new_i32();
175134b1a49cSRichard Henderson                 TCGv_i32 l = tcg_temp_new_i32();
175234b1a49cSRichard Henderson                 tcg_gen_extr_i64_i32(l, h, orig);
1753ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(h);
1754ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(l);
175534b1a49cSRichard Henderson             } else {
175634b1a49cSRichard Henderson                 split_args[real_args++] = args[i];
175734b1a49cSRichard Henderson             }
175834b1a49cSRichard Henderson         }
175934b1a49cSRichard Henderson         nargs = real_args;
176034b1a49cSRichard Henderson         args = split_args;
176134b1a49cSRichard Henderson         sizemask = 0;
176234b1a49cSRichard Henderson     }
176334b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
17642bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
17652bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
17662bece2c8SRichard Henderson         int is_signed = sizemask & (2 << (i+1)*2);
17672bece2c8SRichard Henderson         if (!is_64bit) {
17682bece2c8SRichard Henderson             TCGv_i64 temp = tcg_temp_new_i64();
1769085272b3SRichard Henderson             TCGv_i64 orig = temp_tcgv_i64(args[i]);
17702bece2c8SRichard Henderson             if (is_signed) {
17712bece2c8SRichard Henderson                 tcg_gen_ext32s_i64(temp, orig);
17722bece2c8SRichard Henderson             } else {
17732bece2c8SRichard Henderson                 tcg_gen_ext32u_i64(temp, orig);
17742bece2c8SRichard Henderson             }
1775ae8b75dcSRichard Henderson             args[i] = tcgv_i64_temp(temp);
17762bece2c8SRichard Henderson         }
17772bece2c8SRichard Henderson     }
17782bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
17792bece2c8SRichard Henderson 
178015fa08f8SRichard Henderson     op = tcg_emit_op(INDEX_op_call);
178175e8b9b7SRichard Henderson 
178275e8b9b7SRichard Henderson     pi = 0;
1783ae8b75dcSRichard Henderson     if (ret != NULL) {
178434b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
178534b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
178634b1a49cSRichard Henderson         if (orig_sizemask & 1) {
178734b1a49cSRichard Henderson             /* The 32-bit ABI is going to return the 64-bit value in
178834b1a49cSRichard Henderson                the %o0/%o1 register pair.  Prepare for this by using
178934b1a49cSRichard Henderson                two return temporaries, and reassemble below.  */
179034b1a49cSRichard Henderson             retl = tcg_temp_new_i64();
179134b1a49cSRichard Henderson             reth = tcg_temp_new_i64();
1792ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(reth);
1793ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(retl);
179434b1a49cSRichard Henderson             nb_rets = 2;
179534b1a49cSRichard Henderson         } else {
1796ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
179734b1a49cSRichard Henderson             nb_rets = 1;
179834b1a49cSRichard Henderson         }
179934b1a49cSRichard Henderson #else
180034b1a49cSRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) {
180102eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
1802ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1803ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1804a7812ae4Spbrook #else
1805ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1806ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1807a7812ae4Spbrook #endif
1808a7812ae4Spbrook             nb_rets = 2;
180934b1a49cSRichard Henderson         } else {
1810ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1811a7812ae4Spbrook             nb_rets = 1;
1812a7812ae4Spbrook         }
181334b1a49cSRichard Henderson #endif
1814a7812ae4Spbrook     } else {
1815a7812ae4Spbrook         nb_rets = 0;
1816a7812ae4Spbrook     }
1817cd9090aaSRichard Henderson     TCGOP_CALLO(op) = nb_rets;
181875e8b9b7SRichard Henderson 
1819a7812ae4Spbrook     real_args = 0;
1820a7812ae4Spbrook     for (i = 0; i < nargs; i++) {
18212bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
1822bbb8a1b4SRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
182339cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS
182439cf05d3Sbellard             /* some targets want aligned 64 bit args */
1825ebd486d5Smalc             if (real_args & 1) {
182675e8b9b7SRichard Henderson                 op->args[pi++] = TCG_CALL_DUMMY_ARG;
1827ebd486d5Smalc                 real_args++;
182839cf05d3Sbellard             }
182939cf05d3Sbellard #endif
18303f90f252SRichard Henderson            /* If stack grows up, then we will be placing successive
18313f90f252SRichard Henderson               arguments at lower addresses, which means we need to
18323f90f252SRichard Henderson               reverse the order compared to how we would normally
18333f90f252SRichard Henderson               treat either big or little-endian.  For those arguments
18343f90f252SRichard Henderson               that will wind up in registers, this still works for
18353f90f252SRichard Henderson               HPPA (the only current STACK_GROWSUP target) since the
18363f90f252SRichard Henderson               argument registers are *also* allocated in decreasing
18373f90f252SRichard Henderson               order.  If another such target is added, this logic may
18383f90f252SRichard Henderson               have to get more complicated to differentiate between
18393f90f252SRichard Henderson               stack arguments and register arguments.  */
184002eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
1841ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1842ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1843c896fe29Sbellard #else
1844ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1845ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1846c896fe29Sbellard #endif
1847a7812ae4Spbrook             real_args += 2;
18482bece2c8SRichard Henderson             continue;
18492bece2c8SRichard Henderson         }
18502bece2c8SRichard Henderson 
1851ae8b75dcSRichard Henderson         op->args[pi++] = temp_arg(args[i]);
1852a7812ae4Spbrook         real_args++;
1853c896fe29Sbellard     }
185475e8b9b7SRichard Henderson     op->args[pi++] = (uintptr_t)func;
185575e8b9b7SRichard Henderson     op->args[pi++] = flags;
1856cd9090aaSRichard Henderson     TCGOP_CALLI(op) = real_args;
1857a7812ae4Spbrook 
185875e8b9b7SRichard Henderson     /* Make sure the fields didn't overflow.  */
1859cd9090aaSRichard Henderson     tcg_debug_assert(TCGOP_CALLI(op) == real_args);
186075e8b9b7SRichard Henderson     tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
18612bece2c8SRichard Henderson 
186234b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
186334b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
186434b1a49cSRichard Henderson     /* Free all of the parts we allocated above.  */
186534b1a49cSRichard Henderson     for (i = real_args = 0; i < orig_nargs; ++i) {
186634b1a49cSRichard Henderson         int is_64bit = orig_sizemask & (1 << (i+1)*2);
186734b1a49cSRichard Henderson         if (is_64bit) {
1868085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
1869085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
187034b1a49cSRichard Henderson         } else {
187134b1a49cSRichard Henderson             real_args++;
187234b1a49cSRichard Henderson         }
187334b1a49cSRichard Henderson     }
187434b1a49cSRichard Henderson     if (orig_sizemask & 1) {
187534b1a49cSRichard Henderson         /* The 32-bit ABI returned two 32-bit pieces.  Re-assemble them.
187634b1a49cSRichard Henderson            Note that describing these as TCGv_i64 eliminates an unnecessary
187734b1a49cSRichard Henderson            zero-extension that tcg_gen_concat_i32_i64 would create.  */
1878085272b3SRichard Henderson         tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth);
187934b1a49cSRichard Henderson         tcg_temp_free_i64(retl);
188034b1a49cSRichard Henderson         tcg_temp_free_i64(reth);
188134b1a49cSRichard Henderson     }
188234b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
18832bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
18842bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
18852bece2c8SRichard Henderson         if (!is_64bit) {
1886085272b3SRichard Henderson             tcg_temp_free_internal(args[i]);
18872bece2c8SRichard Henderson         }
18882bece2c8SRichard Henderson     }
18892bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
1890a7812ae4Spbrook }
1891c896fe29Sbellard 
18928fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
1893c896fe29Sbellard {
1894ac3b8891SRichard Henderson     int i, n;
1895c896fe29Sbellard     TCGTemp *ts;
1896ac3b8891SRichard Henderson 
1897ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
1898c896fe29Sbellard         ts = &s->temps[i];
1899ac3b8891SRichard Henderson         ts->val_type = (ts->fixed_reg ? TEMP_VAL_REG : TEMP_VAL_MEM);
1900c896fe29Sbellard     }
1901ac3b8891SRichard Henderson     for (n = s->nb_temps; i < n; i++) {
1902e8996ee0Sbellard         ts = &s->temps[i];
1903ac3b8891SRichard Henderson         ts->val_type = (ts->temp_local ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
1904e8996ee0Sbellard         ts->mem_allocated = 0;
1905e8996ee0Sbellard         ts->fixed_reg = 0;
1906e8996ee0Sbellard     }
1907f8b2f202SRichard Henderson 
1908f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
1909c896fe29Sbellard }
1910c896fe29Sbellard 
1911f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
1912f8b2f202SRichard Henderson                                  TCGTemp *ts)
1913c896fe29Sbellard {
19141807f4c4SRichard Henderson     int idx = temp_idx(ts);
1915ac56dd48Spbrook 
1916fa477d25SRichard Henderson     if (ts->temp_global) {
1917ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
1918f8b2f202SRichard Henderson     } else if (ts->temp_local) {
1919641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
1920f8b2f202SRichard Henderson     } else {
1921ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
1922c896fe29Sbellard     }
1923c896fe29Sbellard     return buf;
1924c896fe29Sbellard }
1925c896fe29Sbellard 
192643439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
192743439139SRichard Henderson                              int buf_size, TCGArg arg)
1928f8b2f202SRichard Henderson {
192943439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
1930f8b2f202SRichard Henderson }
1931f8b2f202SRichard Henderson 
19326e085f72SRichard Henderson /* Find helper name.  */
19336e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val)
1934e8996ee0Sbellard {
19356e085f72SRichard Henderson     const char *ret = NULL;
1936619205fdSEmilio G. Cota     if (helper_table) {
1937619205fdSEmilio G. Cota         TCGHelperInfo *info = g_hash_table_lookup(helper_table, (gpointer)val);
193872866e82SRichard Henderson         if (info) {
193972866e82SRichard Henderson             ret = info->name;
194072866e82SRichard Henderson         }
1941e8996ee0Sbellard     }
19426e085f72SRichard Henderson     return ret;
19434dc81f28Sbellard }
19444dc81f28Sbellard 
1945f48f3edeSblueswir1 static const char * const cond_name[] =
1946f48f3edeSblueswir1 {
19470aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
19480aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
1949f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
1950f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
1951f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
1952f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
1953f48f3edeSblueswir1     [TCG_COND_LE] = "le",
1954f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
1955f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
1956f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
1957f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
1958f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
1959f48f3edeSblueswir1 };
1960f48f3edeSblueswir1 
1961f713d6adSRichard Henderson static const char * const ldst_name[] =
1962f713d6adSRichard Henderson {
1963f713d6adSRichard Henderson     [MO_UB]   = "ub",
1964f713d6adSRichard Henderson     [MO_SB]   = "sb",
1965f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
1966f713d6adSRichard Henderson     [MO_LESW] = "lesw",
1967f713d6adSRichard Henderson     [MO_LEUL] = "leul",
1968f713d6adSRichard Henderson     [MO_LESL] = "lesl",
1969f713d6adSRichard Henderson     [MO_LEQ]  = "leq",
1970f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
1971f713d6adSRichard Henderson     [MO_BESW] = "besw",
1972f713d6adSRichard Henderson     [MO_BEUL] = "beul",
1973f713d6adSRichard Henderson     [MO_BESL] = "besl",
1974f713d6adSRichard Henderson     [MO_BEQ]  = "beq",
1975f713d6adSRichard Henderson };
1976f713d6adSRichard Henderson 
19771f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
197852bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY
19791f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
19801f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
19811f00b27fSSergey Sorokin #else
19821f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
19831f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
19841f00b27fSSergey Sorokin #endif
19851f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
19861f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
19871f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
19881f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
19891f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
19901f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
19911f00b27fSSergey Sorokin };
19921f00b27fSSergey Sorokin 
1993b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
1994b016486eSRichard Henderson {
1995b016486eSRichard Henderson     return (d & (d - 1)) == 0;
1996b016486eSRichard Henderson }
1997b016486eSRichard Henderson 
1998b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
1999b016486eSRichard Henderson {
2000b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
2001b016486eSRichard Henderson         return ctz32(d);
2002b016486eSRichard Henderson     } else {
2003b016486eSRichard Henderson         return ctz64(d);
2004b016486eSRichard Henderson     }
2005b016486eSRichard Henderson }
2006b016486eSRichard Henderson 
20071894f69aSRichard Henderson static void tcg_dump_ops(TCGContext *s, bool have_prefs)
2008c896fe29Sbellard {
2009c896fe29Sbellard     char buf[128];
2010c45cb8bbSRichard Henderson     TCGOp *op;
2011c896fe29Sbellard 
201215fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
2013c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
2014c45cb8bbSRichard Henderson         const TCGOpDef *def;
2015c45cb8bbSRichard Henderson         TCGOpcode c;
2016bdfb460eSRichard Henderson         int col = 0;
2017c45cb8bbSRichard Henderson 
2018c45cb8bbSRichard Henderson         c = op->opc;
2019c896fe29Sbellard         def = &tcg_op_defs[c];
2020c45cb8bbSRichard Henderson 
2021765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
2022b016486eSRichard Henderson             nb_oargs = 0;
202315fa08f8SRichard Henderson             col += qemu_log("\n ----");
20249aef40edSRichard Henderson 
20259aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
20269aef40edSRichard Henderson                 target_ulong a;
20277e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
2028efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
20297e4597d7Sbellard #else
2030efee3746SRichard Henderson                 a = op->args[i];
20317e4597d7Sbellard #endif
2032bdfb460eSRichard Henderson                 col += qemu_log(" " TARGET_FMT_lx, a);
2033eeacee4dSBlue Swirl             }
20347e4597d7Sbellard         } else if (c == INDEX_op_call) {
2035c896fe29Sbellard             /* variable number of arguments */
2036cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2037cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2038c896fe29Sbellard             nb_cargs = def->nb_cargs;
2039b03cce8eSbellard 
2040cf066674SRichard Henderson             /* function name, flags, out args */
2041bdfb460eSRichard Henderson             col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name,
2042efee3746SRichard Henderson                             tcg_find_helper(s, op->args[nb_oargs + nb_iargs]),
2043efee3746SRichard Henderson                             op->args[nb_oargs + nb_iargs + 1], nb_oargs);
2044b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
204543439139SRichard Henderson                 col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf),
2046efee3746SRichard Henderson                                                        op->args[i]));
2047b03cce8eSbellard             }
2048cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
2049efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
2050cf066674SRichard Henderson                 const char *t = "<dummy>";
2051cf066674SRichard Henderson                 if (arg != TCG_CALL_DUMMY_ARG) {
205243439139SRichard Henderson                     t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
2053b03cce8eSbellard                 }
2054bdfb460eSRichard Henderson                 col += qemu_log(",%s", t);
2055e8996ee0Sbellard             }
2056b03cce8eSbellard         } else {
2057bdfb460eSRichard Henderson             col += qemu_log(" %s ", def->name);
2058c45cb8bbSRichard Henderson 
2059c896fe29Sbellard             nb_oargs = def->nb_oargs;
2060c896fe29Sbellard             nb_iargs = def->nb_iargs;
2061c896fe29Sbellard             nb_cargs = def->nb_cargs;
2062c896fe29Sbellard 
2063d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
2064d2fd745fSRichard Henderson                 col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op),
2065d2fd745fSRichard Henderson                                 8 << TCGOP_VECE(op));
2066d2fd745fSRichard Henderson             }
2067d2fd745fSRichard Henderson 
2068c896fe29Sbellard             k = 0;
2069c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
2070eeacee4dSBlue Swirl                 if (k != 0) {
2071bdfb460eSRichard Henderson                     col += qemu_log(",");
2072eeacee4dSBlue Swirl                 }
207343439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2074efee3746SRichard Henderson                                                       op->args[k++]));
2075c896fe29Sbellard             }
2076c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
2077eeacee4dSBlue Swirl                 if (k != 0) {
2078bdfb460eSRichard Henderson                     col += qemu_log(",");
2079eeacee4dSBlue Swirl                 }
208043439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2081efee3746SRichard Henderson                                                       op->args[k++]));
2082c896fe29Sbellard             }
2083be210acbSRichard Henderson             switch (c) {
2084be210acbSRichard Henderson             case INDEX_op_brcond_i32:
2085ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
2086ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
2087be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
2088be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
2089ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
2090be210acbSRichard Henderson             case INDEX_op_setcond_i64:
2091ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
2092212be173SRichard Henderson             case INDEX_op_cmp_vec:
2093f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
2094efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
2095efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
2096efee3746SRichard Henderson                     col += qemu_log(",%s", cond_name[op->args[k++]]);
2097eeacee4dSBlue Swirl                 } else {
2098efee3746SRichard Henderson                     col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]);
2099eeacee4dSBlue Swirl                 }
2100f48f3edeSblueswir1                 i = 1;
2101be210acbSRichard Henderson                 break;
2102f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
2103f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
210407ce0b05SRichard Henderson             case INDEX_op_qemu_st8_i32:
2105f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
2106f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
210759227d5dSRichard Henderson                 {
2108efee3746SRichard Henderson                     TCGMemOpIdx oi = op->args[k++];
210914776ab5STony Nguyen                     MemOp op = get_memop(oi);
211059227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
211159227d5dSRichard Henderson 
211259c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
2113bdfb460eSRichard Henderson                         col += qemu_log(",$0x%x,%u", op, ix);
211459c4b7e8SRichard Henderson                     } else {
21151f00b27fSSergey Sorokin                         const char *s_al, *s_op;
21161f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
211759c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
2118bdfb460eSRichard Henderson                         col += qemu_log(",%s%s,%u", s_al, s_op, ix);
2119f713d6adSRichard Henderson                     }
2120f713d6adSRichard Henderson                     i = 1;
212159227d5dSRichard Henderson                 }
2122f713d6adSRichard Henderson                 break;
2123be210acbSRichard Henderson             default:
2124f48f3edeSblueswir1                 i = 0;
2125be210acbSRichard Henderson                 break;
2126be210acbSRichard Henderson             }
212751e3972cSRichard Henderson             switch (c) {
212851e3972cSRichard Henderson             case INDEX_op_set_label:
212951e3972cSRichard Henderson             case INDEX_op_br:
213051e3972cSRichard Henderson             case INDEX_op_brcond_i32:
213151e3972cSRichard Henderson             case INDEX_op_brcond_i64:
213251e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2133efee3746SRichard Henderson                 col += qemu_log("%s$L%d", k ? "," : "",
2134efee3746SRichard Henderson                                 arg_label(op->args[k])->id);
213551e3972cSRichard Henderson                 i++, k++;
213651e3972cSRichard Henderson                 break;
213751e3972cSRichard Henderson             default:
213851e3972cSRichard Henderson                 break;
2139eeacee4dSBlue Swirl             }
214051e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
2141efee3746SRichard Henderson                 col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]);
2142bdfb460eSRichard Henderson             }
2143bdfb460eSRichard Henderson         }
2144bdfb460eSRichard Henderson 
21451894f69aSRichard Henderson         if (have_prefs || op->life) {
21467606488cSRobert Foley 
21477606488cSRobert Foley             QemuLogFile *logfile;
21487606488cSRobert Foley 
21497606488cSRobert Foley             rcu_read_lock();
2150d73415a3SStefan Hajnoczi             logfile = qatomic_rcu_read(&qemu_logfile);
21517606488cSRobert Foley             if (logfile) {
21521894f69aSRichard Henderson                 for (; col < 40; ++col) {
21537606488cSRobert Foley                     putc(' ', logfile->fd);
2154bdfb460eSRichard Henderson                 }
21551894f69aSRichard Henderson             }
21567606488cSRobert Foley             rcu_read_unlock();
21577606488cSRobert Foley         }
21581894f69aSRichard Henderson 
21591894f69aSRichard Henderson         if (op->life) {
21601894f69aSRichard Henderson             unsigned life = op->life;
2161bdfb460eSRichard Henderson 
2162bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
2163bdfb460eSRichard Henderson                 qemu_log("  sync:");
2164bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
2165bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
2166bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2167bdfb460eSRichard Henderson                     }
2168bdfb460eSRichard Henderson                 }
2169bdfb460eSRichard Henderson             }
2170bdfb460eSRichard Henderson             life /= DEAD_ARG;
2171bdfb460eSRichard Henderson             if (life) {
2172bdfb460eSRichard Henderson                 qemu_log("  dead:");
2173bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
2174bdfb460eSRichard Henderson                     if (life & 1) {
2175bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2176bdfb460eSRichard Henderson                     }
2177bdfb460eSRichard Henderson                 }
2178c896fe29Sbellard             }
2179b03cce8eSbellard         }
21801894f69aSRichard Henderson 
21811894f69aSRichard Henderson         if (have_prefs) {
21821894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
21831894f69aSRichard Henderson                 TCGRegSet set = op->output_pref[i];
21841894f69aSRichard Henderson 
21851894f69aSRichard Henderson                 if (i == 0) {
21861894f69aSRichard Henderson                     qemu_log("  pref=");
21871894f69aSRichard Henderson                 } else {
21881894f69aSRichard Henderson                     qemu_log(",");
21891894f69aSRichard Henderson                 }
21901894f69aSRichard Henderson                 if (set == 0) {
21911894f69aSRichard Henderson                     qemu_log("none");
21921894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
21931894f69aSRichard Henderson                     qemu_log("all");
21941894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
21951894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
21961894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
21971894f69aSRichard Henderson                     qemu_log("%s", tcg_target_reg_names[reg]);
21981894f69aSRichard Henderson #endif
21991894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
22001894f69aSRichard Henderson                     qemu_log("%#x", (uint32_t)set);
22011894f69aSRichard Henderson                 } else {
22021894f69aSRichard Henderson                     qemu_log("%#" PRIx64, (uint64_t)set);
22031894f69aSRichard Henderson                 }
22041894f69aSRichard Henderson             }
22051894f69aSRichard Henderson         }
22061894f69aSRichard Henderson 
2207eeacee4dSBlue Swirl         qemu_log("\n");
2208c896fe29Sbellard     }
2209c896fe29Sbellard }
2210c896fe29Sbellard 
2211c896fe29Sbellard /* we give more priority to constraints with less registers */
2212c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2213c896fe29Sbellard {
221474a11790SRichard Henderson     const TCGArgConstraint *arg_ct = &def->args_ct[k];
221574a11790SRichard Henderson     int n;
2216c896fe29Sbellard 
2217bc2b17e6SRichard Henderson     if (arg_ct->oalias) {
2218c896fe29Sbellard         /* an alias is equivalent to a single register */
2219c896fe29Sbellard         n = 1;
2220c896fe29Sbellard     } else {
222174a11790SRichard Henderson         n = ctpop64(arg_ct->regs);
2222c896fe29Sbellard     }
2223c896fe29Sbellard     return TCG_TARGET_NB_REGS - n + 1;
2224c896fe29Sbellard }
2225c896fe29Sbellard 
2226c896fe29Sbellard /* sort from highest priority to lowest */
2227c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2228c896fe29Sbellard {
222966792f90SRichard Henderson     int i, j;
223066792f90SRichard Henderson     TCGArgConstraint *a = def->args_ct;
2231c896fe29Sbellard 
223266792f90SRichard Henderson     for (i = 0; i < n; i++) {
223366792f90SRichard Henderson         a[start + i].sort_index = start + i;
223466792f90SRichard Henderson     }
223566792f90SRichard Henderson     if (n <= 1) {
2236c896fe29Sbellard         return;
223766792f90SRichard Henderson     }
2238c896fe29Sbellard     for (i = 0; i < n - 1; i++) {
2239c896fe29Sbellard         for (j = i + 1; j < n; j++) {
224066792f90SRichard Henderson             int p1 = get_constraint_priority(def, a[start + i].sort_index);
224166792f90SRichard Henderson             int p2 = get_constraint_priority(def, a[start + j].sort_index);
2242c896fe29Sbellard             if (p1 < p2) {
224366792f90SRichard Henderson                 int tmp = a[start + i].sort_index;
224466792f90SRichard Henderson                 a[start + i].sort_index = a[start + j].sort_index;
224566792f90SRichard Henderson                 a[start + j].sort_index = tmp;
2246c896fe29Sbellard             }
2247c896fe29Sbellard         }
2248c896fe29Sbellard     }
2249c896fe29Sbellard }
2250c896fe29Sbellard 
2251f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2252c896fe29Sbellard {
2253a9751609SRichard Henderson     TCGOpcode op;
2254c896fe29Sbellard 
2255f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
2256f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
2257f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
2258069ea736SRichard Henderson         TCGType type;
2259069ea736SRichard Henderson         int i, nb_args;
2260f69d277eSRichard Henderson 
2261f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
2262f69d277eSRichard Henderson             continue;
2263f69d277eSRichard Henderson         }
2264f69d277eSRichard Henderson 
2265c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
2266f69d277eSRichard Henderson         if (nb_args == 0) {
2267f69d277eSRichard Henderson             continue;
2268f69d277eSRichard Henderson         }
2269f69d277eSRichard Henderson 
2270f69d277eSRichard Henderson         tdefs = tcg_target_op_def(op);
2271f69d277eSRichard Henderson         /* Missing TCGTargetOpDef entry. */
2272f69d277eSRichard Henderson         tcg_debug_assert(tdefs != NULL);
2273f69d277eSRichard Henderson 
2274069ea736SRichard Henderson         type = (def->flags & TCG_OPF_64BIT ? TCG_TYPE_I64 : TCG_TYPE_I32);
2275c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2276f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
2277f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2278eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2279f69d277eSRichard Henderson 
228017280ff4SRichard Henderson             while (*ct_str != '\0') {
228117280ff4SRichard Henderson                 switch(*ct_str) {
228217280ff4SRichard Henderson                 case '0' ... '9':
228317280ff4SRichard Henderson                     {
228417280ff4SRichard Henderson                         int oarg = *ct_str - '0';
228517280ff4SRichard Henderson                         tcg_debug_assert(ct_str == tdefs->args_ct_str[i]);
2286eabb7b91SAurelien Jarno                         tcg_debug_assert(oarg < def->nb_oargs);
228774a11790SRichard Henderson                         tcg_debug_assert(def->args_ct[oarg].regs != 0);
2288c896fe29Sbellard                         def->args_ct[i] = def->args_ct[oarg];
2289bc2b17e6SRichard Henderson                         /* The output sets oalias.  */
2290bc2b17e6SRichard Henderson                         def->args_ct[oarg].oalias = true;
22915ff9d6a4Sbellard                         def->args_ct[oarg].alias_index = i;
2292bc2b17e6SRichard Henderson                         /* The input sets ialias. */
2293bc2b17e6SRichard Henderson                         def->args_ct[i].ialias = true;
22945ff9d6a4Sbellard                         def->args_ct[i].alias_index = oarg;
229517280ff4SRichard Henderson                     }
229617280ff4SRichard Henderson                     ct_str++;
2297c896fe29Sbellard                     break;
229882790a87SRichard Henderson                 case '&':
2299bc2b17e6SRichard Henderson                     def->args_ct[i].newreg = true;
230082790a87SRichard Henderson                     ct_str++;
230182790a87SRichard Henderson                     break;
2302c896fe29Sbellard                 case 'i':
2303c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2304c896fe29Sbellard                     ct_str++;
2305c896fe29Sbellard                     break;
2306c896fe29Sbellard                 default:
2307069ea736SRichard Henderson                     ct_str = target_parse_constraint(&def->args_ct[i],
2308069ea736SRichard Henderson                                                      ct_str, type);
2309f69d277eSRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2310069ea736SRichard Henderson                     tcg_debug_assert(ct_str != NULL);
2311c896fe29Sbellard                 }
2312c896fe29Sbellard             }
2313c896fe29Sbellard         }
2314c896fe29Sbellard 
2315c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2316eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2317c68aaa18SStefan Weil 
2318c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
2319c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
2320c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
2321c896fe29Sbellard     }
2322c896fe29Sbellard }
2323c896fe29Sbellard 
23240c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
23250c627cdcSRichard Henderson {
2326d88a117eSRichard Henderson     TCGLabel *label;
2327d88a117eSRichard Henderson 
2328d88a117eSRichard Henderson     switch (op->opc) {
2329d88a117eSRichard Henderson     case INDEX_op_br:
2330d88a117eSRichard Henderson         label = arg_label(op->args[0]);
2331d88a117eSRichard Henderson         label->refs--;
2332d88a117eSRichard Henderson         break;
2333d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
2334d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
2335d88a117eSRichard Henderson         label = arg_label(op->args[3]);
2336d88a117eSRichard Henderson         label->refs--;
2337d88a117eSRichard Henderson         break;
2338d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
2339d88a117eSRichard Henderson         label = arg_label(op->args[5]);
2340d88a117eSRichard Henderson         label->refs--;
2341d88a117eSRichard Henderson         break;
2342d88a117eSRichard Henderson     default:
2343d88a117eSRichard Henderson         break;
2344d88a117eSRichard Henderson     }
2345d88a117eSRichard Henderson 
234615fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
234715fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
2348abebf925SRichard Henderson     s->nb_ops--;
23490c627cdcSRichard Henderson 
23500c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
2351d73415a3SStefan Hajnoczi     qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
23520c627cdcSRichard Henderson #endif
23530c627cdcSRichard Henderson }
23540c627cdcSRichard Henderson 
235515fa08f8SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc)
235615fa08f8SRichard Henderson {
235715fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
235815fa08f8SRichard Henderson     TCGOp *op;
235915fa08f8SRichard Henderson 
236015fa08f8SRichard Henderson     if (likely(QTAILQ_EMPTY(&s->free_ops))) {
236115fa08f8SRichard Henderson         op = tcg_malloc(sizeof(TCGOp));
236215fa08f8SRichard Henderson     } else {
236315fa08f8SRichard Henderson         op = QTAILQ_FIRST(&s->free_ops);
236415fa08f8SRichard Henderson         QTAILQ_REMOVE(&s->free_ops, op, link);
236515fa08f8SRichard Henderson     }
236615fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
236715fa08f8SRichard Henderson     op->opc = opc;
2368abebf925SRichard Henderson     s->nb_ops++;
236915fa08f8SRichard Henderson 
237015fa08f8SRichard Henderson     return op;
237115fa08f8SRichard Henderson }
237215fa08f8SRichard Henderson 
237315fa08f8SRichard Henderson TCGOp *tcg_emit_op(TCGOpcode opc)
237415fa08f8SRichard Henderson {
237515fa08f8SRichard Henderson     TCGOp *op = tcg_op_alloc(opc);
237615fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
237715fa08f8SRichard Henderson     return op;
237815fa08f8SRichard Henderson }
237915fa08f8SRichard Henderson 
2380ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
23815a18407fSRichard Henderson {
238215fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
238315fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
23845a18407fSRichard Henderson     return new_op;
23855a18407fSRichard Henderson }
23865a18407fSRichard Henderson 
2387ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
23885a18407fSRichard Henderson {
238915fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
239015fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
23915a18407fSRichard Henderson     return new_op;
23925a18407fSRichard Henderson }
23935a18407fSRichard Henderson 
2394b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
2395b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s)
2396b4fc67c7SRichard Henderson {
2397b4fc67c7SRichard Henderson     TCGOp *op, *op_next;
2398b4fc67c7SRichard Henderson     bool dead = false;
2399b4fc67c7SRichard Henderson 
2400b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
2401b4fc67c7SRichard Henderson         bool remove = dead;
2402b4fc67c7SRichard Henderson         TCGLabel *label;
2403b4fc67c7SRichard Henderson         int call_flags;
2404b4fc67c7SRichard Henderson 
2405b4fc67c7SRichard Henderson         switch (op->opc) {
2406b4fc67c7SRichard Henderson         case INDEX_op_set_label:
2407b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
2408b4fc67c7SRichard Henderson             if (label->refs == 0) {
2409b4fc67c7SRichard Henderson                 /*
2410b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
2411b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
2412b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
2413b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
2414b4fc67c7SRichard Henderson                  * little to be gained by iterating.
2415b4fc67c7SRichard Henderson                  */
2416b4fc67c7SRichard Henderson                 remove = true;
2417b4fc67c7SRichard Henderson             } else {
2418b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
2419b4fc67c7SRichard Henderson                 dead = false;
2420b4fc67c7SRichard Henderson                 remove = false;
2421b4fc67c7SRichard Henderson 
2422b4fc67c7SRichard Henderson                 /*
2423b4fc67c7SRichard Henderson                  * Optimization can fold conditional branches to unconditional.
2424b4fc67c7SRichard Henderson                  * If we find a label with one reference which is preceded by
2425b4fc67c7SRichard Henderson                  * an unconditional branch to it, remove both.  This needed to
2426b4fc67c7SRichard Henderson                  * wait until the dead code in between them was removed.
2427b4fc67c7SRichard Henderson                  */
2428b4fc67c7SRichard Henderson                 if (label->refs == 1) {
2429eae3eb3eSPaolo Bonzini                     TCGOp *op_prev = QTAILQ_PREV(op, link);
2430b4fc67c7SRichard Henderson                     if (op_prev->opc == INDEX_op_br &&
2431b4fc67c7SRichard Henderson                         label == arg_label(op_prev->args[0])) {
2432b4fc67c7SRichard Henderson                         tcg_op_remove(s, op_prev);
2433b4fc67c7SRichard Henderson                         remove = true;
2434b4fc67c7SRichard Henderson                     }
2435b4fc67c7SRichard Henderson                 }
2436b4fc67c7SRichard Henderson             }
2437b4fc67c7SRichard Henderson             break;
2438b4fc67c7SRichard Henderson 
2439b4fc67c7SRichard Henderson         case INDEX_op_br:
2440b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
2441b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
2442b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
2443b4fc67c7SRichard Henderson             dead = true;
2444b4fc67c7SRichard Henderson             break;
2445b4fc67c7SRichard Henderson 
2446b4fc67c7SRichard Henderson         case INDEX_op_call:
2447b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
2448b4fc67c7SRichard Henderson             call_flags = op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1];
2449b4fc67c7SRichard Henderson             if (call_flags & TCG_CALL_NO_RETURN) {
2450b4fc67c7SRichard Henderson                 dead = true;
2451b4fc67c7SRichard Henderson             }
2452b4fc67c7SRichard Henderson             break;
2453b4fc67c7SRichard Henderson 
2454b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
2455b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
2456b4fc67c7SRichard Henderson             remove = false;
2457b4fc67c7SRichard Henderson             break;
2458b4fc67c7SRichard Henderson 
2459b4fc67c7SRichard Henderson         default:
2460b4fc67c7SRichard Henderson             break;
2461b4fc67c7SRichard Henderson         }
2462b4fc67c7SRichard Henderson 
2463b4fc67c7SRichard Henderson         if (remove) {
2464b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
2465b4fc67c7SRichard Henderson         }
2466b4fc67c7SRichard Henderson     }
2467b4fc67c7SRichard Henderson }
2468b4fc67c7SRichard Henderson 
2469c70fbf0aSRichard Henderson #define TS_DEAD  1
2470c70fbf0aSRichard Henderson #define TS_MEM   2
2471c70fbf0aSRichard Henderson 
24725a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
24735a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
24745a18407fSRichard Henderson 
247525f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
247625f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
247725f49c5fSRichard Henderson {
247825f49c5fSRichard Henderson     return ts->state_ptr;
247925f49c5fSRichard Henderson }
248025f49c5fSRichard Henderson 
248125f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
248225f49c5fSRichard Henderson  * maximal regset for its type.
248325f49c5fSRichard Henderson  */
248425f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
248525f49c5fSRichard Henderson {
248625f49c5fSRichard Henderson     *la_temp_pref(ts)
248725f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
248825f49c5fSRichard Henderson }
248925f49c5fSRichard Henderson 
24909c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
24919c43b68dSAurelien Jarno    should be in memory. */
24922616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
2493c896fe29Sbellard {
2494b83eabeaSRichard Henderson     int i;
2495b83eabeaSRichard Henderson 
2496b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2497b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
249825f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2499b83eabeaSRichard Henderson     }
2500b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2501b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
250225f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2503b83eabeaSRichard Henderson     }
2504c896fe29Sbellard }
2505c896fe29Sbellard 
25069c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
25079c43b68dSAurelien Jarno    and local temps should be in memory. */
25082616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
2509641d5fbeSbellard {
2510b83eabeaSRichard Henderson     int i;
2511641d5fbeSbellard 
2512b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2513b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
251425f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2515c70fbf0aSRichard Henderson     }
2516b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2517b83eabeaSRichard Henderson         s->temps[i].state = (s->temps[i].temp_local
2518b83eabeaSRichard Henderson                              ? TS_DEAD | TS_MEM
2519b83eabeaSRichard Henderson                              : TS_DEAD);
252025f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2521641d5fbeSbellard     }
2522641d5fbeSbellard }
2523641d5fbeSbellard 
2524f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
2525f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
2526f65a061cSRichard Henderson {
2527f65a061cSRichard Henderson     int i;
2528f65a061cSRichard Henderson 
2529f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
253025f49c5fSRichard Henderson         int state = s->temps[i].state;
253125f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
253225f49c5fSRichard Henderson         if (state == TS_DEAD) {
253325f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
253425f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
253525f49c5fSRichard Henderson         }
2536f65a061cSRichard Henderson     }
2537f65a061cSRichard Henderson }
2538f65a061cSRichard Henderson 
2539b4cb76e6SRichard Henderson /*
2540b4cb76e6SRichard Henderson  * liveness analysis: conditional branch: all temps are dead,
2541b4cb76e6SRichard Henderson  * globals and local temps should be synced.
2542b4cb76e6SRichard Henderson  */
2543b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
2544b4cb76e6SRichard Henderson {
2545b4cb76e6SRichard Henderson     la_global_sync(s, ng);
2546b4cb76e6SRichard Henderson 
2547b4cb76e6SRichard Henderson     for (int i = ng; i < nt; ++i) {
2548b4cb76e6SRichard Henderson         if (s->temps[i].temp_local) {
2549b4cb76e6SRichard Henderson             int state = s->temps[i].state;
2550b4cb76e6SRichard Henderson             s->temps[i].state = state | TS_MEM;
2551b4cb76e6SRichard Henderson             if (state != TS_DEAD) {
2552b4cb76e6SRichard Henderson                 continue;
2553b4cb76e6SRichard Henderson             }
2554b4cb76e6SRichard Henderson         } else {
2555b4cb76e6SRichard Henderson             s->temps[i].state = TS_DEAD;
2556b4cb76e6SRichard Henderson         }
2557b4cb76e6SRichard Henderson         la_reset_pref(&s->temps[i]);
2558b4cb76e6SRichard Henderson     }
2559b4cb76e6SRichard Henderson }
2560b4cb76e6SRichard Henderson 
2561f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
2562f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
2563f65a061cSRichard Henderson {
2564f65a061cSRichard Henderson     int i;
2565f65a061cSRichard Henderson 
2566f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
2567f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
256825f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
256925f49c5fSRichard Henderson     }
257025f49c5fSRichard Henderson }
257125f49c5fSRichard Henderson 
257225f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
257325f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
257425f49c5fSRichard Henderson {
257525f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
257625f49c5fSRichard Henderson     int i;
257725f49c5fSRichard Henderson 
257825f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
257925f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
258025f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
258125f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
258225f49c5fSRichard Henderson             TCGRegSet set = *pset;
258325f49c5fSRichard Henderson 
258425f49c5fSRichard Henderson             set &= mask;
258525f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
258625f49c5fSRichard Henderson             if (set == 0) {
258725f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
258825f49c5fSRichard Henderson             }
258925f49c5fSRichard Henderson             *pset = set;
259025f49c5fSRichard Henderson         }
2591f65a061cSRichard Henderson     }
2592f65a061cSRichard Henderson }
2593f65a061cSRichard Henderson 
2594a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
2595c896fe29Sbellard    given input arguments is dead. Instructions updating dead
2596c896fe29Sbellard    temporaries are removed. */
2597b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s)
2598c896fe29Sbellard {
2599c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
26002616c808SRichard Henderson     int nb_temps = s->nb_temps;
260115fa08f8SRichard Henderson     TCGOp *op, *op_prev;
260225f49c5fSRichard Henderson     TCGRegSet *prefs;
260325f49c5fSRichard Henderson     int i;
260425f49c5fSRichard Henderson 
260525f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
260625f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
260725f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
260825f49c5fSRichard Henderson     }
2609c896fe29Sbellard 
2610ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
26112616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
2612c896fe29Sbellard 
2613eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
261425f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
2615c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
2616c45cb8bbSRichard Henderson         bool have_opc_new2;
2617a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
261825f49c5fSRichard Henderson         TCGTemp *ts;
2619c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2620c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2621c45cb8bbSRichard Henderson 
2622c45cb8bbSRichard Henderson         switch (opc) {
2623c896fe29Sbellard         case INDEX_op_call:
2624c6e113f5Sbellard             {
2625c6e113f5Sbellard                 int call_flags;
262625f49c5fSRichard Henderson                 int nb_call_regs;
2627c6e113f5Sbellard 
2628cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
2629cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
2630efee3746SRichard Henderson                 call_flags = op->args[nb_oargs + nb_iargs + 1];
2631c6e113f5Sbellard 
2632c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
263378505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
2634c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
263525f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
263625f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
2637c6e113f5Sbellard                             goto do_not_remove_call;
2638c6e113f5Sbellard                         }
26399c43b68dSAurelien Jarno                     }
2640c45cb8bbSRichard Henderson                     goto do_remove;
2641152c35aaSRichard Henderson                 }
2642c6e113f5Sbellard             do_not_remove_call:
2643c896fe29Sbellard 
264425f49c5fSRichard Henderson                 /* Output args are dead.  */
2645c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
264625f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
264725f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
2648a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
26496b64b624SAurelien Jarno                     }
265025f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
2651a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
26529c43b68dSAurelien Jarno                     }
265325f49c5fSRichard Henderson                     ts->state = TS_DEAD;
265425f49c5fSRichard Henderson                     la_reset_pref(ts);
265525f49c5fSRichard Henderson 
265625f49c5fSRichard Henderson                     /* Not used -- it will be tcg_target_call_oarg_regs[i].  */
265725f49c5fSRichard Henderson                     op->output_pref[i] = 0;
2658c896fe29Sbellard                 }
2659c896fe29Sbellard 
266078505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
266178505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
2662f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
2663c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
2664f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
2665b9c18f56Saurel32                 }
2666c896fe29Sbellard 
266725f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
2668866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
266925f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
267025f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
2671a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
2672c896fe29Sbellard                     }
2673c896fe29Sbellard                 }
267425f49c5fSRichard Henderson 
267525f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
267625f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
267725f49c5fSRichard Henderson 
267825f49c5fSRichard Henderson                 nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
267925f49c5fSRichard Henderson 
268025f49c5fSRichard Henderson                 /* Input arguments are live for preceding opcodes.  */
268125f49c5fSRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
268225f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
268325f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
268425f49c5fSRichard Henderson                         /* For those arguments that die, and will be allocated
268525f49c5fSRichard Henderson                          * in registers, clear the register set for that arg,
268625f49c5fSRichard Henderson                          * to be filled in below.  For args that will be on
268725f49c5fSRichard Henderson                          * the stack, reset to any available reg.
268825f49c5fSRichard Henderson                          */
268925f49c5fSRichard Henderson                         *la_temp_pref(ts)
269025f49c5fSRichard Henderson                             = (i < nb_call_regs ? 0 :
269125f49c5fSRichard Henderson                                tcg_target_available_regs[ts->type]);
269225f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
269325f49c5fSRichard Henderson                     }
269425f49c5fSRichard Henderson                 }
269525f49c5fSRichard Henderson 
269625f49c5fSRichard Henderson                 /* For each input argument, add its input register to prefs.
269725f49c5fSRichard Henderson                    If a temp is used once, this produces a single set bit.  */
269825f49c5fSRichard Henderson                 for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) {
269925f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
270025f49c5fSRichard Henderson                     if (ts) {
270125f49c5fSRichard Henderson                         tcg_regset_set_reg(*la_temp_pref(ts),
270225f49c5fSRichard Henderson                                            tcg_target_call_iarg_regs[i]);
2703c70fbf0aSRichard Henderson                     }
2704c19f47bfSAurelien Jarno                 }
2705c6e113f5Sbellard             }
2706c896fe29Sbellard             break;
2707765b842aSRichard Henderson         case INDEX_op_insn_start:
2708c896fe29Sbellard             break;
27095ff9d6a4Sbellard         case INDEX_op_discard:
27105ff9d6a4Sbellard             /* mark the temporary as dead */
271125f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
271225f49c5fSRichard Henderson             ts->state = TS_DEAD;
271325f49c5fSRichard Henderson             la_reset_pref(ts);
27145ff9d6a4Sbellard             break;
27151305c451SRichard Henderson 
27161305c451SRichard Henderson         case INDEX_op_add2_i32:
2717c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
2718f1fae40cSRichard Henderson             goto do_addsub2;
27191305c451SRichard Henderson         case INDEX_op_sub2_i32:
2720c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
2721f1fae40cSRichard Henderson             goto do_addsub2;
2722f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
2723c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
2724f1fae40cSRichard Henderson             goto do_addsub2;
2725f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
2726c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
2727f1fae40cSRichard Henderson         do_addsub2:
27281305c451SRichard Henderson             nb_iargs = 4;
27291305c451SRichard Henderson             nb_oargs = 2;
27301305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
27311305c451SRichard Henderson                the low part.  The result can be optimized to a simple
27321305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
27331305c451SRichard Henderson                cpu mode is set to 32 bit.  */
2734b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2735b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
27361305c451SRichard Henderson                     goto do_remove;
27371305c451SRichard Henderson                 }
2738c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
2739c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
2740c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2741efee3746SRichard Henderson                 op->args[1] = op->args[2];
2742efee3746SRichard Henderson                 op->args[2] = op->args[4];
27431305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
27441305c451SRichard Henderson                 nb_iargs = 2;
27451305c451SRichard Henderson                 nb_oargs = 1;
27461305c451SRichard Henderson             }
27471305c451SRichard Henderson             goto do_not_remove;
27481305c451SRichard Henderson 
27491414968aSRichard Henderson         case INDEX_op_mulu2_i32:
2750c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2751c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
2752c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
275303271524SRichard Henderson             goto do_mul2;
2754f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
2755c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2756c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
2757c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
2758f1fae40cSRichard Henderson             goto do_mul2;
2759f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
2760c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2761c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
2762c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
276303271524SRichard Henderson             goto do_mul2;
2764f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
2765c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2766c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
2767c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
276803271524SRichard Henderson             goto do_mul2;
2769f1fae40cSRichard Henderson         do_mul2:
27701414968aSRichard Henderson             nb_iargs = 2;
27711414968aSRichard Henderson             nb_oargs = 2;
2772b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2773b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
277403271524SRichard Henderson                     /* Both parts of the operation are dead.  */
27751414968aSRichard Henderson                     goto do_remove;
27761414968aSRichard Henderson                 }
277703271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
2778c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2779efee3746SRichard Henderson                 op->args[1] = op->args[2];
2780efee3746SRichard Henderson                 op->args[2] = op->args[3];
2781b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
278203271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
2783c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
2784efee3746SRichard Henderson                 op->args[0] = op->args[1];
2785efee3746SRichard Henderson                 op->args[1] = op->args[2];
2786efee3746SRichard Henderson                 op->args[2] = op->args[3];
278703271524SRichard Henderson             } else {
278803271524SRichard Henderson                 goto do_not_remove;
278903271524SRichard Henderson             }
279003271524SRichard Henderson             /* Mark the single-word operation live.  */
27911414968aSRichard Henderson             nb_oargs = 1;
27921414968aSRichard Henderson             goto do_not_remove;
27931414968aSRichard Henderson 
2794c896fe29Sbellard         default:
27951305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
2796c896fe29Sbellard             nb_iargs = def->nb_iargs;
2797c896fe29Sbellard             nb_oargs = def->nb_oargs;
2798c896fe29Sbellard 
2799c896fe29Sbellard             /* Test if the operation can be removed because all
28005ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
28015ff9d6a4Sbellard                implies side effects */
28025ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
2803c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
2804b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
2805c896fe29Sbellard                         goto do_not_remove;
2806c896fe29Sbellard                     }
28079c43b68dSAurelien Jarno                 }
2808152c35aaSRichard Henderson                 goto do_remove;
2809152c35aaSRichard Henderson             }
2810152c35aaSRichard Henderson             goto do_not_remove;
2811152c35aaSRichard Henderson 
28121305c451SRichard Henderson         do_remove:
28130c627cdcSRichard Henderson             tcg_op_remove(s, op);
2814152c35aaSRichard Henderson             break;
2815152c35aaSRichard Henderson 
2816c896fe29Sbellard         do_not_remove:
2817c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
281825f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
281925f49c5fSRichard Henderson 
282025f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
282125f49c5fSRichard Henderson                 op->output_pref[i] = *la_temp_pref(ts);
282225f49c5fSRichard Henderson 
282325f49c5fSRichard Henderson                 /* Output args are dead.  */
282425f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2825a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
28266b64b624SAurelien Jarno                 }
282725f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
2828a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
28299c43b68dSAurelien Jarno                 }
283025f49c5fSRichard Henderson                 ts->state = TS_DEAD;
283125f49c5fSRichard Henderson                 la_reset_pref(ts);
2832c896fe29Sbellard             }
2833c896fe29Sbellard 
283425f49c5fSRichard Henderson             /* If end of basic block, update.  */
2835ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
2836ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
2837b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_COND_BRANCH) {
2838b4cb76e6SRichard Henderson                 la_bb_sync(s, nb_globals, nb_temps);
2839ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
28402616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
28413d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
2842f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
284325f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
284425f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
284525f49c5fSRichard Henderson                 }
2846c896fe29Sbellard             }
2847c896fe29Sbellard 
284825f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
2849866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
285025f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
285125f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2852a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
2853c896fe29Sbellard                 }
2854c19f47bfSAurelien Jarno             }
285525f49c5fSRichard Henderson 
285625f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
2857c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
285825f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
285925f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
286025f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
286125f49c5fSRichard Henderson                        all regs for the type.  */
286225f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
286325f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
286425f49c5fSRichard Henderson                 }
286525f49c5fSRichard Henderson             }
286625f49c5fSRichard Henderson 
286725f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
286825f49c5fSRichard Henderson             switch (opc) {
286925f49c5fSRichard Henderson             case INDEX_op_mov_i32:
287025f49c5fSRichard Henderson             case INDEX_op_mov_i64:
287125f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
287225f49c5fSRichard Henderson                    have proper constraints.  That said, special case
287325f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
287425f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
287525f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
287625f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
287725f49c5fSRichard Henderson                 }
287825f49c5fSRichard Henderson                 break;
287925f49c5fSRichard Henderson 
288025f49c5fSRichard Henderson             default:
288125f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
288225f49c5fSRichard Henderson                     const TCGArgConstraint *ct = &def->args_ct[i];
288325f49c5fSRichard Henderson                     TCGRegSet set, *pset;
288425f49c5fSRichard Henderson 
288525f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
288625f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
288725f49c5fSRichard Henderson                     set = *pset;
288825f49c5fSRichard Henderson 
28899be0d080SRichard Henderson                     set &= ct->regs;
2890bc2b17e6SRichard Henderson                     if (ct->ialias) {
289125f49c5fSRichard Henderson                         set &= op->output_pref[ct->alias_index];
289225f49c5fSRichard Henderson                     }
289325f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
289425f49c5fSRichard Henderson                     if (set == 0) {
28959be0d080SRichard Henderson                         set = ct->regs;
289625f49c5fSRichard Henderson                     }
289725f49c5fSRichard Henderson                     *pset = set;
289825f49c5fSRichard Henderson                 }
289925f49c5fSRichard Henderson                 break;
2900c896fe29Sbellard             }
2901c896fe29Sbellard             break;
2902c896fe29Sbellard         }
2903bee158cbSRichard Henderson         op->life = arg_life;
2904c896fe29Sbellard     }
29051ff0a2c5SEvgeny Voevodin }
2906c896fe29Sbellard 
29075a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
2908b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s)
29095a18407fSRichard Henderson {
29105a18407fSRichard Henderson     int nb_globals = s->nb_globals;
291115fa08f8SRichard Henderson     int nb_temps, i;
29125a18407fSRichard Henderson     bool changes = false;
291315fa08f8SRichard Henderson     TCGOp *op, *op_next;
29145a18407fSRichard Henderson 
29155a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
29165a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
29175a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
29185a18407fSRichard Henderson         if (its->indirect_reg) {
29195a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
29205a18407fSRichard Henderson             dts->type = its->type;
29215a18407fSRichard Henderson             dts->base_type = its->base_type;
2922b83eabeaSRichard Henderson             its->state_ptr = dts;
2923b83eabeaSRichard Henderson         } else {
2924b83eabeaSRichard Henderson             its->state_ptr = NULL;
29255a18407fSRichard Henderson         }
2926b83eabeaSRichard Henderson         /* All globals begin dead.  */
2927b83eabeaSRichard Henderson         its->state = TS_DEAD;
29285a18407fSRichard Henderson     }
2929b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
2930b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
2931b83eabeaSRichard Henderson         its->state_ptr = NULL;
2932b83eabeaSRichard Henderson         its->state = TS_DEAD;
2933b83eabeaSRichard Henderson     }
29345a18407fSRichard Henderson 
293515fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
29365a18407fSRichard Henderson         TCGOpcode opc = op->opc;
29375a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
29385a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
29395a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
2940b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
29415a18407fSRichard Henderson 
29425a18407fSRichard Henderson         if (opc == INDEX_op_call) {
2943cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2944cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2945efee3746SRichard Henderson             call_flags = op->args[nb_oargs + nb_iargs + 1];
29465a18407fSRichard Henderson         } else {
29475a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
29485a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
29495a18407fSRichard Henderson 
29505a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
2951b4cb76e6SRichard Henderson             if (def->flags & TCG_OPF_COND_BRANCH) {
2952b4cb76e6SRichard Henderson                 /* Like reading globals: sync_globals */
2953b4cb76e6SRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
2954b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
29555a18407fSRichard Henderson                 /* Like writing globals: save_globals */
29565a18407fSRichard Henderson                 call_flags = 0;
29575a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
29585a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
29595a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
29605a18407fSRichard Henderson             } else {
29615a18407fSRichard Henderson                 /* No effect on globals.  */
29625a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
29635a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
29645a18407fSRichard Henderson             }
29655a18407fSRichard Henderson         }
29665a18407fSRichard Henderson 
29675a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
29685a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2969b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2970b83eabeaSRichard Henderson             if (arg_ts) {
2971b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
2972b83eabeaSRichard Henderson                 if (dir_ts && arg_ts->state == TS_DEAD) {
2973b83eabeaSRichard Henderson                     TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
29745a18407fSRichard Henderson                                       ? INDEX_op_ld_i32
29755a18407fSRichard Henderson                                       : INDEX_op_ld_i64);
2976ac1043f6SEmilio G. Cota                     TCGOp *lop = tcg_op_insert_before(s, op, lopc);
29775a18407fSRichard Henderson 
2978b83eabeaSRichard Henderson                     lop->args[0] = temp_arg(dir_ts);
2979b83eabeaSRichard Henderson                     lop->args[1] = temp_arg(arg_ts->mem_base);
2980b83eabeaSRichard Henderson                     lop->args[2] = arg_ts->mem_offset;
29815a18407fSRichard Henderson 
29825a18407fSRichard Henderson                     /* Loaded, but synced with memory.  */
2983b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
29845a18407fSRichard Henderson                 }
29855a18407fSRichard Henderson             }
29865a18407fSRichard Henderson         }
29875a18407fSRichard Henderson 
29885a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
29895a18407fSRichard Henderson            No action is required except keeping temp_state up to date
29905a18407fSRichard Henderson            so that we reload when needed.  */
29915a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2992b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2993b83eabeaSRichard Henderson             if (arg_ts) {
2994b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
2995b83eabeaSRichard Henderson                 if (dir_ts) {
2996b83eabeaSRichard Henderson                     op->args[i] = temp_arg(dir_ts);
29975a18407fSRichard Henderson                     changes = true;
29985a18407fSRichard Henderson                     if (IS_DEAD_ARG(i)) {
2999b83eabeaSRichard Henderson                         arg_ts->state = TS_DEAD;
30005a18407fSRichard Henderson                     }
30015a18407fSRichard Henderson                 }
30025a18407fSRichard Henderson             }
30035a18407fSRichard Henderson         }
30045a18407fSRichard Henderson 
30055a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
30065a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
30075a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
30085a18407fSRichard Henderson             /* Nothing to do */
30095a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
30105a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
30115a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
30125a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
3013b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3014b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3015b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
30165a18407fSRichard Henderson             }
30175a18407fSRichard Henderson         } else {
30185a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
30195a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
30205a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
3021b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3022b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3023b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
30245a18407fSRichard Henderson             }
30255a18407fSRichard Henderson         }
30265a18407fSRichard Henderson 
30275a18407fSRichard Henderson         /* Outputs become available.  */
302861f15c48SRichard Henderson         if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) {
302961f15c48SRichard Henderson             arg_ts = arg_temp(op->args[0]);
303061f15c48SRichard Henderson             dir_ts = arg_ts->state_ptr;
303161f15c48SRichard Henderson             if (dir_ts) {
303261f15c48SRichard Henderson                 op->args[0] = temp_arg(dir_ts);
303361f15c48SRichard Henderson                 changes = true;
303461f15c48SRichard Henderson 
303561f15c48SRichard Henderson                 /* The output is now live and modified.  */
303661f15c48SRichard Henderson                 arg_ts->state = 0;
303761f15c48SRichard Henderson 
303861f15c48SRichard Henderson                 if (NEED_SYNC_ARG(0)) {
303961f15c48SRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
304061f15c48SRichard Henderson                                       ? INDEX_op_st_i32
304161f15c48SRichard Henderson                                       : INDEX_op_st_i64);
304261f15c48SRichard Henderson                     TCGOp *sop = tcg_op_insert_after(s, op, sopc);
304361f15c48SRichard Henderson                     TCGTemp *out_ts = dir_ts;
304461f15c48SRichard Henderson 
304561f15c48SRichard Henderson                     if (IS_DEAD_ARG(0)) {
304661f15c48SRichard Henderson                         out_ts = arg_temp(op->args[1]);
304761f15c48SRichard Henderson                         arg_ts->state = TS_DEAD;
304861f15c48SRichard Henderson                         tcg_op_remove(s, op);
304961f15c48SRichard Henderson                     } else {
305061f15c48SRichard Henderson                         arg_ts->state = TS_MEM;
305161f15c48SRichard Henderson                     }
305261f15c48SRichard Henderson 
305361f15c48SRichard Henderson                     sop->args[0] = temp_arg(out_ts);
305461f15c48SRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
305561f15c48SRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
305661f15c48SRichard Henderson                 } else {
305761f15c48SRichard Henderson                     tcg_debug_assert(!IS_DEAD_ARG(0));
305861f15c48SRichard Henderson                 }
305961f15c48SRichard Henderson             }
306061f15c48SRichard Henderson         } else {
30615a18407fSRichard Henderson             for (i = 0; i < nb_oargs; i++) {
3062b83eabeaSRichard Henderson                 arg_ts = arg_temp(op->args[i]);
3063b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3064b83eabeaSRichard Henderson                 if (!dir_ts) {
30655a18407fSRichard Henderson                     continue;
30665a18407fSRichard Henderson                 }
3067b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
30685a18407fSRichard Henderson                 changes = true;
30695a18407fSRichard Henderson 
30705a18407fSRichard Henderson                 /* The output is now live and modified.  */
3071b83eabeaSRichard Henderson                 arg_ts->state = 0;
30725a18407fSRichard Henderson 
30735a18407fSRichard Henderson                 /* Sync outputs upon their last write.  */
30745a18407fSRichard Henderson                 if (NEED_SYNC_ARG(i)) {
3075b83eabeaSRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
30765a18407fSRichard Henderson                                       ? INDEX_op_st_i32
30775a18407fSRichard Henderson                                       : INDEX_op_st_i64);
3078ac1043f6SEmilio G. Cota                     TCGOp *sop = tcg_op_insert_after(s, op, sopc);
30795a18407fSRichard Henderson 
3080b83eabeaSRichard Henderson                     sop->args[0] = temp_arg(dir_ts);
3081b83eabeaSRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
3082b83eabeaSRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
30835a18407fSRichard Henderson 
3084b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
30855a18407fSRichard Henderson                 }
30865a18407fSRichard Henderson                 /* Drop outputs that are dead.  */
30875a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3088b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
30895a18407fSRichard Henderson                 }
30905a18407fSRichard Henderson             }
30915a18407fSRichard Henderson         }
309261f15c48SRichard Henderson     }
30935a18407fSRichard Henderson 
30945a18407fSRichard Henderson     return changes;
30955a18407fSRichard Henderson }
30965a18407fSRichard Henderson 
30978d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
3098c896fe29Sbellard static void dump_regs(TCGContext *s)
3099c896fe29Sbellard {
3100c896fe29Sbellard     TCGTemp *ts;
3101c896fe29Sbellard     int i;
3102c896fe29Sbellard     char buf[64];
3103c896fe29Sbellard 
3104c896fe29Sbellard     for(i = 0; i < s->nb_temps; i++) {
3105c896fe29Sbellard         ts = &s->temps[i];
310643439139SRichard Henderson         printf("  %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3107c896fe29Sbellard         switch(ts->val_type) {
3108c896fe29Sbellard         case TEMP_VAL_REG:
3109c896fe29Sbellard             printf("%s", tcg_target_reg_names[ts->reg]);
3110c896fe29Sbellard             break;
3111c896fe29Sbellard         case TEMP_VAL_MEM:
3112b3a62939SRichard Henderson             printf("%d(%s)", (int)ts->mem_offset,
3113b3a62939SRichard Henderson                    tcg_target_reg_names[ts->mem_base->reg]);
3114c896fe29Sbellard             break;
3115c896fe29Sbellard         case TEMP_VAL_CONST:
3116c896fe29Sbellard             printf("$0x%" TCG_PRIlx, ts->val);
3117c896fe29Sbellard             break;
3118c896fe29Sbellard         case TEMP_VAL_DEAD:
3119c896fe29Sbellard             printf("D");
3120c896fe29Sbellard             break;
3121c896fe29Sbellard         default:
3122c896fe29Sbellard             printf("???");
3123c896fe29Sbellard             break;
3124c896fe29Sbellard         }
3125c896fe29Sbellard         printf("\n");
3126c896fe29Sbellard     }
3127c896fe29Sbellard 
3128c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
3129f8b2f202SRichard Henderson         if (s->reg_to_temp[i] != NULL) {
3130c896fe29Sbellard             printf("%s: %s\n",
3131c896fe29Sbellard                    tcg_target_reg_names[i],
3132f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i]));
3133c896fe29Sbellard         }
3134c896fe29Sbellard     }
3135c896fe29Sbellard }
3136c896fe29Sbellard 
3137c896fe29Sbellard static void check_regs(TCGContext *s)
3138c896fe29Sbellard {
3139869938aeSRichard Henderson     int reg;
3140b6638662SRichard Henderson     int k;
3141c896fe29Sbellard     TCGTemp *ts;
3142c896fe29Sbellard     char buf[64];
3143c896fe29Sbellard 
3144c896fe29Sbellard     for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
3145f8b2f202SRichard Henderson         ts = s->reg_to_temp[reg];
3146f8b2f202SRichard Henderson         if (ts != NULL) {
3147f8b2f202SRichard Henderson             if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) {
3148c896fe29Sbellard                 printf("Inconsistency for register %s:\n",
3149c896fe29Sbellard                        tcg_target_reg_names[reg]);
3150b03cce8eSbellard                 goto fail;
3151c896fe29Sbellard             }
3152c896fe29Sbellard         }
3153c896fe29Sbellard     }
3154c896fe29Sbellard     for (k = 0; k < s->nb_temps; k++) {
3155c896fe29Sbellard         ts = &s->temps[k];
3156f8b2f202SRichard Henderson         if (ts->val_type == TEMP_VAL_REG && !ts->fixed_reg
3157f8b2f202SRichard Henderson             && s->reg_to_temp[ts->reg] != ts) {
3158c896fe29Sbellard             printf("Inconsistency for temp %s:\n",
3159f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3160b03cce8eSbellard         fail:
3161c896fe29Sbellard             printf("reg state:\n");
3162c896fe29Sbellard             dump_regs(s);
3163c896fe29Sbellard             tcg_abort();
3164c896fe29Sbellard         }
3165c896fe29Sbellard     }
3166c896fe29Sbellard }
3167c896fe29Sbellard #endif
3168c896fe29Sbellard 
31692272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
3170c896fe29Sbellard {
31719b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64)
31729b9c37c3SRichard Henderson     /* Sparc64 stack is accessed with offset of 2047 */
3173b591dc59SBlue Swirl     s->current_frame_offset = (s->current_frame_offset +
3174b591dc59SBlue Swirl                                (tcg_target_long)sizeof(tcg_target_long) - 1) &
3175b591dc59SBlue Swirl         ~(sizeof(tcg_target_long) - 1);
3176f44c9960SBlue Swirl #endif
3177b591dc59SBlue Swirl     if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
3178b591dc59SBlue Swirl         s->frame_end) {
31795ff9d6a4Sbellard         tcg_abort();
3180b591dc59SBlue Swirl     }
3181c896fe29Sbellard     ts->mem_offset = s->current_frame_offset;
3182b3a62939SRichard Henderson     ts->mem_base = s->frame_temp;
3183c896fe29Sbellard     ts->mem_allocated = 1;
3184e2c6d1b4SRichard Henderson     s->current_frame_offset += sizeof(tcg_target_long);
3185c896fe29Sbellard }
3186c896fe29Sbellard 
3187b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
3188b3915dbbSRichard Henderson 
318959d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
319059d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
319159d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
3192c896fe29Sbellard {
319359d7c14eSRichard Henderson     if (ts->fixed_reg) {
319459d7c14eSRichard Henderson         return;
319559d7c14eSRichard Henderson     }
319659d7c14eSRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
319759d7c14eSRichard Henderson         s->reg_to_temp[ts->reg] = NULL;
319859d7c14eSRichard Henderson     }
319959d7c14eSRichard Henderson     ts->val_type = (free_or_dead < 0
320059d7c14eSRichard Henderson                     || ts->temp_local
3201fa477d25SRichard Henderson                     || ts->temp_global
320259d7c14eSRichard Henderson                     ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
320359d7c14eSRichard Henderson }
3204c896fe29Sbellard 
320559d7c14eSRichard Henderson /* Mark a temporary as dead.  */
320659d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
320759d7c14eSRichard Henderson {
320859d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
320959d7c14eSRichard Henderson }
321059d7c14eSRichard Henderson 
321159d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
321259d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
321359d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
321459d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
321598b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
321698b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
321759d7c14eSRichard Henderson {
321859d7c14eSRichard Henderson     if (ts->fixed_reg) {
321959d7c14eSRichard Henderson         return;
322059d7c14eSRichard Henderson     }
322159d7c14eSRichard Henderson     if (!ts->mem_coherent) {
32227f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
32232272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
322459d7c14eSRichard Henderson         }
322559d7c14eSRichard Henderson         switch (ts->val_type) {
322659d7c14eSRichard Henderson         case TEMP_VAL_CONST:
322759d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
322859d7c14eSRichard Henderson                require it later in a register, so attempt to store the
322959d7c14eSRichard Henderson                constant to memory directly.  */
323059d7c14eSRichard Henderson             if (free_or_dead
323159d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
323259d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
323359d7c14eSRichard Henderson                 break;
323459d7c14eSRichard Henderson             }
323559d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
323698b4e186SRichard Henderson                       allocated_regs, preferred_regs);
323759d7c14eSRichard Henderson             /* fallthrough */
323859d7c14eSRichard Henderson 
323959d7c14eSRichard Henderson         case TEMP_VAL_REG:
324059d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
324159d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
324259d7c14eSRichard Henderson             break;
324359d7c14eSRichard Henderson 
324459d7c14eSRichard Henderson         case TEMP_VAL_MEM:
324559d7c14eSRichard Henderson             break;
324659d7c14eSRichard Henderson 
324759d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
324859d7c14eSRichard Henderson         default:
324959d7c14eSRichard Henderson             tcg_abort();
3250c896fe29Sbellard         }
32517f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
32527f6ceedfSAurelien Jarno     }
325359d7c14eSRichard Henderson     if (free_or_dead) {
325459d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
325559d7c14eSRichard Henderson     }
325659d7c14eSRichard Henderson }
32577f6ceedfSAurelien Jarno 
32587f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
3259b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
32607f6ceedfSAurelien Jarno {
3261f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
3262f8b2f202SRichard Henderson     if (ts != NULL) {
326398b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
3264c896fe29Sbellard     }
3265c896fe29Sbellard }
3266c896fe29Sbellard 
3267b016486eSRichard Henderson /**
3268b016486eSRichard Henderson  * tcg_reg_alloc:
3269b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
3270b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
3271b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
3272b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
3273b016486eSRichard Henderson  *
3274b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
3275b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
3276b016486eSRichard Henderson  */
3277b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
3278b016486eSRichard Henderson                             TCGRegSet allocated_regs,
3279b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
3280c896fe29Sbellard {
3281b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
3282b016486eSRichard Henderson     TCGRegSet reg_ct[2];
328391478cefSRichard Henderson     const int *order;
3284c896fe29Sbellard 
3285b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
3286b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
3287b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
3288b016486eSRichard Henderson 
3289b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
3290b016486eSRichard Henderson        or if the preference made no difference.  */
3291b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
3292b016486eSRichard Henderson 
329391478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
3294c896fe29Sbellard 
3295b016486eSRichard Henderson     /* Try free registers, preferences first.  */
3296b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3297b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3298b016486eSRichard Henderson 
3299b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3300b016486eSRichard Henderson             /* One register in the set.  */
3301b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3302b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
3303c896fe29Sbellard                 return reg;
3304c896fe29Sbellard             }
3305b016486eSRichard Henderson         } else {
330691478cefSRichard Henderson             for (i = 0; i < n; i++) {
3307b016486eSRichard Henderson                 TCGReg reg = order[i];
3308b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
3309b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
3310b016486eSRichard Henderson                     return reg;
3311b016486eSRichard Henderson                 }
3312b016486eSRichard Henderson             }
3313b016486eSRichard Henderson         }
3314b016486eSRichard Henderson     }
3315b016486eSRichard Henderson 
3316b016486eSRichard Henderson     /* We must spill something.  */
3317b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3318b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3319b016486eSRichard Henderson 
3320b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3321b016486eSRichard Henderson             /* One register in the set.  */
3322b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3323b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
3324c896fe29Sbellard             return reg;
3325b016486eSRichard Henderson         } else {
3326b016486eSRichard Henderson             for (i = 0; i < n; i++) {
3327b016486eSRichard Henderson                 TCGReg reg = order[i];
3328b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
3329b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
3330b016486eSRichard Henderson                     return reg;
3331b016486eSRichard Henderson                 }
3332b016486eSRichard Henderson             }
3333c896fe29Sbellard         }
3334c896fe29Sbellard     }
3335c896fe29Sbellard 
3336c896fe29Sbellard     tcg_abort();
3337c896fe29Sbellard }
3338c896fe29Sbellard 
333940ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
334040ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
334140ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
3342b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
334340ae5c62SRichard Henderson {
334440ae5c62SRichard Henderson     TCGReg reg;
334540ae5c62SRichard Henderson 
334640ae5c62SRichard Henderson     switch (ts->val_type) {
334740ae5c62SRichard Henderson     case TEMP_VAL_REG:
334840ae5c62SRichard Henderson         return;
334940ae5c62SRichard Henderson     case TEMP_VAL_CONST:
3350b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3351b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
335240ae5c62SRichard Henderson         tcg_out_movi(s, ts->type, reg, ts->val);
335340ae5c62SRichard Henderson         ts->mem_coherent = 0;
335440ae5c62SRichard Henderson         break;
335540ae5c62SRichard Henderson     case TEMP_VAL_MEM:
3356b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3357b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
335840ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
335940ae5c62SRichard Henderson         ts->mem_coherent = 1;
336040ae5c62SRichard Henderson         break;
336140ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
336240ae5c62SRichard Henderson     default:
336340ae5c62SRichard Henderson         tcg_abort();
336440ae5c62SRichard Henderson     }
336540ae5c62SRichard Henderson     ts->reg = reg;
336640ae5c62SRichard Henderson     ts->val_type = TEMP_VAL_REG;
336740ae5c62SRichard Henderson     s->reg_to_temp[reg] = ts;
336840ae5c62SRichard Henderson }
336940ae5c62SRichard Henderson 
337059d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
3371e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
337259d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
33731ad80729SAurelien Jarno {
33742c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
3375eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
3376f8bf00f1SRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg);
33771ad80729SAurelien Jarno }
33781ad80729SAurelien Jarno 
33799814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
3380641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
3381641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
3382641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
3383641d5fbeSbellard {
3384ac3b8891SRichard Henderson     int i, n;
3385641d5fbeSbellard 
3386ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
3387b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
3388641d5fbeSbellard     }
3389e5097dc8Sbellard }
3390e5097dc8Sbellard 
33913d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
33923d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
33933d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
33943d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
33953d5c5f87SAurelien Jarno {
3396ac3b8891SRichard Henderson     int i, n;
33973d5c5f87SAurelien Jarno 
3398ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
339912b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
340012b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
340112b9b11aSRichard Henderson                          || ts->fixed_reg
340212b9b11aSRichard Henderson                          || ts->mem_coherent);
34033d5c5f87SAurelien Jarno     }
34043d5c5f87SAurelien Jarno }
34053d5c5f87SAurelien Jarno 
3406e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
3407e8996ee0Sbellard    all globals are stored at their canonical location. */
3408e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
3409e5097dc8Sbellard {
3410e5097dc8Sbellard     int i;
3411e5097dc8Sbellard 
3412c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
3413b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
3414641d5fbeSbellard         if (ts->temp_local) {
3415b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
3416641d5fbeSbellard         } else {
34172c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
3418eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
3419eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3420c896fe29Sbellard         }
3421641d5fbeSbellard     }
3422e8996ee0Sbellard 
3423e8996ee0Sbellard     save_globals(s, allocated_regs);
3424c896fe29Sbellard }
3425c896fe29Sbellard 
3426bab1671fSRichard Henderson /*
3427b4cb76e6SRichard Henderson  * At a conditional branch, we assume all temporaries are dead and
3428b4cb76e6SRichard Henderson  * all globals and local temps are synced to their location.
3429b4cb76e6SRichard Henderson  */
3430b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
3431b4cb76e6SRichard Henderson {
3432b4cb76e6SRichard Henderson     sync_globals(s, allocated_regs);
3433b4cb76e6SRichard Henderson 
3434b4cb76e6SRichard Henderson     for (int i = s->nb_globals; i < s->nb_temps; i++) {
3435b4cb76e6SRichard Henderson         TCGTemp *ts = &s->temps[i];
3436b4cb76e6SRichard Henderson         /*
3437b4cb76e6SRichard Henderson          * The liveness analysis already ensures that temps are dead.
3438b4cb76e6SRichard Henderson          * Keep tcg_debug_asserts for safety.
3439b4cb76e6SRichard Henderson          */
3440b4cb76e6SRichard Henderson         if (ts->temp_local) {
3441b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
3442b4cb76e6SRichard Henderson         } else {
3443b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3444b4cb76e6SRichard Henderson         }
3445b4cb76e6SRichard Henderson     }
3446b4cb76e6SRichard Henderson }
3447b4cb76e6SRichard Henderson 
3448b4cb76e6SRichard Henderson /*
3449bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_movi_*.
3450bab1671fSRichard Henderson  */
34510fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
3452ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
3453ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
3454e8996ee0Sbellard {
3455d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3456d63e3b6eSRichard Henderson     tcg_debug_assert(!ots->fixed_reg);
345759d7c14eSRichard Henderson 
345859d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
3459f8b2f202SRichard Henderson     if (ots->val_type == TEMP_VAL_REG) {
3460f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = NULL;
3461f8b2f202SRichard Henderson     }
3462e8996ee0Sbellard     ots->val_type = TEMP_VAL_CONST;
3463e8996ee0Sbellard     ots->val = val;
346459d7c14eSRichard Henderson     ots->mem_coherent = 0;
3465ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
3466ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
346759d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
3468f8bf00f1SRichard Henderson         temp_dead(s, ots);
34694c4e1ab2SAurelien Jarno     }
3470e8996ee0Sbellard }
3471e8996ee0Sbellard 
3472dd186292SRichard Henderson static void tcg_reg_alloc_movi(TCGContext *s, const TCGOp *op)
34730fe4fca4SPaolo Bonzini {
347443439139SRichard Henderson     TCGTemp *ots = arg_temp(op->args[0]);
3475dd186292SRichard Henderson     tcg_target_ulong val = op->args[1];
34760fe4fca4SPaolo Bonzini 
347769e3706dSRichard Henderson     tcg_reg_alloc_do_movi(s, ots, val, op->life, op->output_pref[0]);
34780fe4fca4SPaolo Bonzini }
34790fe4fca4SPaolo Bonzini 
3480bab1671fSRichard Henderson /*
3481bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
3482bab1671fSRichard Henderson  */
3483dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
3484c896fe29Sbellard {
3485dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
348669e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
3487c896fe29Sbellard     TCGTemp *ts, *ots;
3488450445d5SRichard Henderson     TCGType otype, itype;
3489c896fe29Sbellard 
3490d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
349169e3706dSRichard Henderson     preferred_regs = op->output_pref[0];
349243439139SRichard Henderson     ots = arg_temp(op->args[0]);
349343439139SRichard Henderson     ts = arg_temp(op->args[1]);
3494450445d5SRichard Henderson 
3495d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3496d63e3b6eSRichard Henderson     tcg_debug_assert(!ots->fixed_reg);
3497d63e3b6eSRichard Henderson 
3498450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
3499450445d5SRichard Henderson     otype = ots->type;
3500450445d5SRichard Henderson     itype = ts->type;
3501c896fe29Sbellard 
35020fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
35030fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
35040fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
35050fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
35060fe4fca4SPaolo Bonzini             temp_dead(s, ts);
35070fe4fca4SPaolo Bonzini         }
350869e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
35090fe4fca4SPaolo Bonzini         return;
35100fe4fca4SPaolo Bonzini     }
35110fe4fca4SPaolo Bonzini 
35120fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
35130fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
35140fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
35150fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
35160fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
351769e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
351869e3706dSRichard Henderson                   allocated_regs, preferred_regs);
3519c29c1d7eSAurelien Jarno     }
3520c29c1d7eSAurelien Jarno 
35210fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
3522d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
3523c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
3524c29c1d7eSAurelien Jarno            liveness analysis disabled). */
3525eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
3526c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
35272272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
3528c29c1d7eSAurelien Jarno         }
3529b3a62939SRichard Henderson         tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset);
3530c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
3531f8bf00f1SRichard Henderson             temp_dead(s, ts);
3532c29c1d7eSAurelien Jarno         }
3533f8bf00f1SRichard Henderson         temp_dead(s, ots);
3534e8996ee0Sbellard     } else {
3535d63e3b6eSRichard Henderson         if (IS_DEAD_ARG(1) && !ts->fixed_reg) {
3536c29c1d7eSAurelien Jarno             /* the mov can be suppressed */
3537c29c1d7eSAurelien Jarno             if (ots->val_type == TEMP_VAL_REG) {
3538f8b2f202SRichard Henderson                 s->reg_to_temp[ots->reg] = NULL;
3539c896fe29Sbellard             }
3540c29c1d7eSAurelien Jarno             ots->reg = ts->reg;
3541f8bf00f1SRichard Henderson             temp_dead(s, ts);
3542c29c1d7eSAurelien Jarno         } else {
3543c29c1d7eSAurelien Jarno             if (ots->val_type != TEMP_VAL_REG) {
3544c29c1d7eSAurelien Jarno                 /* When allocating a new register, make sure to not spill the
3545c29c1d7eSAurelien Jarno                    input one. */
3546c29c1d7eSAurelien Jarno                 tcg_regset_set_reg(allocated_regs, ts->reg);
3547450445d5SRichard Henderson                 ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
354869e3706dSRichard Henderson                                          allocated_regs, preferred_regs,
3549b016486eSRichard Henderson                                          ots->indirect_base);
3550c29c1d7eSAurelien Jarno             }
355178113e83SRichard Henderson             if (!tcg_out_mov(s, otype, ots->reg, ts->reg)) {
3552240c08d0SRichard Henderson                 /*
3553240c08d0SRichard Henderson                  * Cross register class move not supported.
3554240c08d0SRichard Henderson                  * Store the source register into the destination slot
3555240c08d0SRichard Henderson                  * and leave the destination temp as TEMP_VAL_MEM.
3556240c08d0SRichard Henderson                  */
3557240c08d0SRichard Henderson                 assert(!ots->fixed_reg);
3558240c08d0SRichard Henderson                 if (!ts->mem_allocated) {
3559240c08d0SRichard Henderson                     temp_allocate_frame(s, ots);
3560240c08d0SRichard Henderson                 }
3561240c08d0SRichard Henderson                 tcg_out_st(s, ts->type, ts->reg,
3562240c08d0SRichard Henderson                            ots->mem_base->reg, ots->mem_offset);
3563240c08d0SRichard Henderson                 ots->mem_coherent = 1;
3564240c08d0SRichard Henderson                 temp_free_or_dead(s, ots, -1);
3565240c08d0SRichard Henderson                 return;
356678113e83SRichard Henderson             }
3567c29c1d7eSAurelien Jarno         }
3568c896fe29Sbellard         ots->val_type = TEMP_VAL_REG;
3569c896fe29Sbellard         ots->mem_coherent = 0;
3570f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3571ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(0)) {
357298b4e186SRichard Henderson             temp_sync(s, ots, allocated_regs, 0, 0);
3573c29c1d7eSAurelien Jarno         }
3574ec7a869dSAurelien Jarno     }
3575c896fe29Sbellard }
3576c896fe29Sbellard 
3577bab1671fSRichard Henderson /*
3578bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
3579bab1671fSRichard Henderson  */
3580bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
3581bab1671fSRichard Henderson {
3582bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
3583bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
3584bab1671fSRichard Henderson     TCGTemp *its, *ots;
3585bab1671fSRichard Henderson     TCGType itype, vtype;
3586d6ecb4a9SRichard Henderson     intptr_t endian_fixup;
3587bab1671fSRichard Henderson     unsigned vece;
3588bab1671fSRichard Henderson     bool ok;
3589bab1671fSRichard Henderson 
3590bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
3591bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
3592bab1671fSRichard Henderson 
3593bab1671fSRichard Henderson     /* ENV should not be modified.  */
3594bab1671fSRichard Henderson     tcg_debug_assert(!ots->fixed_reg);
3595bab1671fSRichard Henderson 
3596bab1671fSRichard Henderson     itype = its->type;
3597bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
3598bab1671fSRichard Henderson     vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
3599bab1671fSRichard Henderson 
3600bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
3601bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
3602bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
3603bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
3604bab1671fSRichard Henderson             temp_dead(s, its);
3605bab1671fSRichard Henderson         }
3606bab1671fSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, op->output_pref[0]);
3607bab1671fSRichard Henderson         return;
3608bab1671fSRichard Henderson     }
3609bab1671fSRichard Henderson 
36109be0d080SRichard Henderson     dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
36119be0d080SRichard Henderson     dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs;
3612bab1671fSRichard Henderson 
3613bab1671fSRichard Henderson     /* Allocate the output register now.  */
3614bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
3615bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
3616bab1671fSRichard Henderson 
3617bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
3618bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
3619bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
3620bab1671fSRichard Henderson         }
3621bab1671fSRichard Henderson         ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
3622bab1671fSRichard Henderson                                  op->output_pref[0], ots->indirect_base);
3623bab1671fSRichard Henderson         ots->val_type = TEMP_VAL_REG;
3624bab1671fSRichard Henderson         ots->mem_coherent = 0;
3625bab1671fSRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3626bab1671fSRichard Henderson     }
3627bab1671fSRichard Henderson 
3628bab1671fSRichard Henderson     switch (its->val_type) {
3629bab1671fSRichard Henderson     case TEMP_VAL_REG:
3630bab1671fSRichard Henderson         /*
3631bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
3632bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
3633bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
3634bab1671fSRichard Henderson          */
3635bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
3636bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
3637bab1671fSRichard Henderson                 goto done;
3638bab1671fSRichard Henderson             }
3639bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
3640bab1671fSRichard Henderson         }
3641bab1671fSRichard Henderson         if (!its->mem_coherent) {
3642bab1671fSRichard Henderson             /*
3643bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
3644bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
3645bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
3646bab1671fSRichard Henderson              */
3647bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
3648bab1671fSRichard Henderson                 break;
3649bab1671fSRichard Henderson             }
3650bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
3651bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
3652bab1671fSRichard Henderson         }
3653bab1671fSRichard Henderson         /* fall through */
3654bab1671fSRichard Henderson 
3655bab1671fSRichard Henderson     case TEMP_VAL_MEM:
3656d6ecb4a9SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
3657d6ecb4a9SRichard Henderson         endian_fixup = itype == TCG_TYPE_I32 ? 4 : 8;
3658d6ecb4a9SRichard Henderson         endian_fixup -= 1 << vece;
3659d6ecb4a9SRichard Henderson #else
3660d6ecb4a9SRichard Henderson         endian_fixup = 0;
3661d6ecb4a9SRichard Henderson #endif
3662d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
3663d6ecb4a9SRichard Henderson                              its->mem_offset + endian_fixup)) {
3664d6ecb4a9SRichard Henderson             goto done;
3665d6ecb4a9SRichard Henderson         }
3666bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
3667bab1671fSRichard Henderson         break;
3668bab1671fSRichard Henderson 
3669bab1671fSRichard Henderson     default:
3670bab1671fSRichard Henderson         g_assert_not_reached();
3671bab1671fSRichard Henderson     }
3672bab1671fSRichard Henderson 
3673bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
3674bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
3675bab1671fSRichard Henderson     tcg_debug_assert(ok);
3676bab1671fSRichard Henderson 
3677bab1671fSRichard Henderson  done:
3678bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
3679bab1671fSRichard Henderson         temp_dead(s, its);
3680bab1671fSRichard Henderson     }
3681bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
3682bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
3683bab1671fSRichard Henderson     }
3684bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
3685bab1671fSRichard Henderson         temp_dead(s, ots);
3686bab1671fSRichard Henderson     }
3687bab1671fSRichard Henderson }
3688bab1671fSRichard Henderson 
3689dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
3690c896fe29Sbellard {
3691dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3692dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
369382790a87SRichard Henderson     TCGRegSet i_allocated_regs;
369482790a87SRichard Henderson     TCGRegSet o_allocated_regs;
3695b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
3696b6638662SRichard Henderson     TCGReg reg;
3697c896fe29Sbellard     TCGArg arg;
3698c896fe29Sbellard     const TCGArgConstraint *arg_ct;
3699c896fe29Sbellard     TCGTemp *ts;
3700c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
3701c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
3702c896fe29Sbellard 
3703c896fe29Sbellard     nb_oargs = def->nb_oargs;
3704c896fe29Sbellard     nb_iargs = def->nb_iargs;
3705c896fe29Sbellard 
3706c896fe29Sbellard     /* copy constants */
3707c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
3708dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
3709c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
3710c896fe29Sbellard 
3711d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
3712d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
371382790a87SRichard Henderson 
3714c896fe29Sbellard     /* satisfy input constraints */
3715c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
3716d62816f2SRichard Henderson         TCGRegSet i_preferred_regs, o_preferred_regs;
3717d62816f2SRichard Henderson 
371866792f90SRichard Henderson         i = def->args_ct[nb_oargs + k].sort_index;
3719dd186292SRichard Henderson         arg = op->args[i];
3720c896fe29Sbellard         arg_ct = &def->args_ct[i];
372143439139SRichard Henderson         ts = arg_temp(arg);
372240ae5c62SRichard Henderson 
372340ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
372440ae5c62SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct)) {
3725c896fe29Sbellard             /* constant is OK for instruction */
3726c896fe29Sbellard             const_args[i] = 1;
3727c896fe29Sbellard             new_args[i] = ts->val;
3728d62816f2SRichard Henderson             continue;
3729c896fe29Sbellard         }
373040ae5c62SRichard Henderson 
3731d62816f2SRichard Henderson         i_preferred_regs = o_preferred_regs = 0;
3732bc2b17e6SRichard Henderson         if (arg_ct->ialias) {
3733d62816f2SRichard Henderson             o_preferred_regs = op->output_pref[arg_ct->alias_index];
37345ff9d6a4Sbellard             if (ts->fixed_reg) {
37355ff9d6a4Sbellard                 /* if fixed register, we must allocate a new register
37365ff9d6a4Sbellard                    if the alias is not the same register */
3737d62816f2SRichard Henderson                 if (arg != op->args[arg_ct->alias_index]) {
37385ff9d6a4Sbellard                     goto allocate_in_reg;
3739d62816f2SRichard Henderson                 }
37405ff9d6a4Sbellard             } else {
3741c896fe29Sbellard                 /* if the input is aliased to an output and if it is
3742c896fe29Sbellard                    not dead after the instruction, we must allocate
3743c896fe29Sbellard                    a new register and move it */
3744866cb6cbSAurelien Jarno                 if (!IS_DEAD_ARG(i)) {
3745c896fe29Sbellard                     goto allocate_in_reg;
3746c896fe29Sbellard                 }
3747d62816f2SRichard Henderson 
37487e1df267SAurelien Jarno                 /* check if the current register has already been allocated
37497e1df267SAurelien Jarno                    for another input aliased to an output */
3750d62816f2SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG) {
37517e1df267SAurelien Jarno                     int k2, i2;
3752d62816f2SRichard Henderson                     reg = ts->reg;
37537e1df267SAurelien Jarno                     for (k2 = 0 ; k2 < k ; k2++) {
375466792f90SRichard Henderson                         i2 = def->args_ct[nb_oargs + k2].sort_index;
3755bc2b17e6SRichard Henderson                         if (def->args_ct[i2].ialias && reg == new_args[i2]) {
37567e1df267SAurelien Jarno                             goto allocate_in_reg;
37577e1df267SAurelien Jarno                         }
37587e1df267SAurelien Jarno                     }
37595ff9d6a4Sbellard                 }
3760d62816f2SRichard Henderson                 i_preferred_regs = o_preferred_regs;
3761866cb6cbSAurelien Jarno             }
3762d62816f2SRichard Henderson         }
3763d62816f2SRichard Henderson 
37649be0d080SRichard Henderson         temp_load(s, ts, arg_ct->regs, i_allocated_regs, i_preferred_regs);
3765c896fe29Sbellard         reg = ts->reg;
3766d62816f2SRichard Henderson 
37679be0d080SRichard Henderson         if (tcg_regset_test_reg(arg_ct->regs, reg)) {
3768c896fe29Sbellard             /* nothing to do : the constraint is satisfied */
3769c896fe29Sbellard         } else {
3770c896fe29Sbellard         allocate_in_reg:
3771c896fe29Sbellard             /* allocate a new register matching the constraint
3772c896fe29Sbellard                and move the temporary register into it */
3773d62816f2SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
3774d62816f2SRichard Henderson                       i_allocated_regs, 0);
37759be0d080SRichard Henderson             reg = tcg_reg_alloc(s, arg_ct->regs, i_allocated_regs,
3776d62816f2SRichard Henderson                                 o_preferred_regs, ts->indirect_base);
377778113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
3778240c08d0SRichard Henderson                 /*
3779240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
3780240c08d0SRichard Henderson                  * temp back to its slot and load from there.
3781240c08d0SRichard Henderson                  */
3782240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
3783240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
3784240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
378578113e83SRichard Henderson             }
3786c896fe29Sbellard         }
3787c896fe29Sbellard         new_args[i] = reg;
3788c896fe29Sbellard         const_args[i] = 0;
378982790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
3790c896fe29Sbellard     }
3791c896fe29Sbellard 
3792c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
3793866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
3794866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
379543439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
3796c896fe29Sbellard         }
3797c896fe29Sbellard     }
3798c896fe29Sbellard 
3799b4cb76e6SRichard Henderson     if (def->flags & TCG_OPF_COND_BRANCH) {
3800b4cb76e6SRichard Henderson         tcg_reg_alloc_cbranch(s, i_allocated_regs);
3801b4cb76e6SRichard Henderson     } else if (def->flags & TCG_OPF_BB_END) {
380282790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
3803a52ad07eSAurelien Jarno     } else {
3804c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
3805b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
3806c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
3807c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
380882790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
3809c896fe29Sbellard                 }
3810c896fe29Sbellard             }
38113d5c5f87SAurelien Jarno         }
38123d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
38133d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
38143d5c5f87SAurelien Jarno                an exception. */
381582790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
3816c896fe29Sbellard         }
3817c896fe29Sbellard 
3818c896fe29Sbellard         /* satisfy the output constraints */
3819c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
382066792f90SRichard Henderson             i = def->args_ct[k].sort_index;
3821dd186292SRichard Henderson             arg = op->args[i];
3822c896fe29Sbellard             arg_ct = &def->args_ct[i];
382343439139SRichard Henderson             ts = arg_temp(arg);
3824d63e3b6eSRichard Henderson 
3825d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
3826d63e3b6eSRichard Henderson             tcg_debug_assert(!ts->fixed_reg);
3827d63e3b6eSRichard Henderson 
3828bc2b17e6SRichard Henderson             if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
38295ff9d6a4Sbellard                 reg = new_args[arg_ct->alias_index];
3830bc2b17e6SRichard Henderson             } else if (arg_ct->newreg) {
38319be0d080SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->regs,
383282790a87SRichard Henderson                                     i_allocated_regs | o_allocated_regs,
383369e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
3834c896fe29Sbellard             } else {
38359be0d080SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
383669e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
3837c896fe29Sbellard             }
383882790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
3839639368ddSAurelien Jarno             if (ts->val_type == TEMP_VAL_REG) {
3840f8b2f202SRichard Henderson                 s->reg_to_temp[ts->reg] = NULL;
3841639368ddSAurelien Jarno             }
3842c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
3843c896fe29Sbellard             ts->reg = reg;
3844d63e3b6eSRichard Henderson             /*
3845d63e3b6eSRichard Henderson              * Temp value is modified, so the value kept in memory is
3846d63e3b6eSRichard Henderson              * potentially not the same.
3847d63e3b6eSRichard Henderson              */
3848c896fe29Sbellard             ts->mem_coherent = 0;
3849f8b2f202SRichard Henderson             s->reg_to_temp[reg] = ts;
3850c896fe29Sbellard             new_args[i] = reg;
3851c896fe29Sbellard         }
3852e8996ee0Sbellard     }
3853c896fe29Sbellard 
3854c896fe29Sbellard     /* emit instruction */
3855d2fd745fSRichard Henderson     if (def->flags & TCG_OPF_VECTOR) {
3856d2fd745fSRichard Henderson         tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
3857d2fd745fSRichard Henderson                        new_args, const_args);
3858d2fd745fSRichard Henderson     } else {
3859dd186292SRichard Henderson         tcg_out_op(s, op->opc, new_args, const_args);
3860d2fd745fSRichard Henderson     }
3861c896fe29Sbellard 
3862c896fe29Sbellard     /* move the outputs in the correct register if needed */
3863c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
386443439139SRichard Henderson         ts = arg_temp(op->args[i]);
3865d63e3b6eSRichard Henderson 
3866d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
3867d63e3b6eSRichard Henderson         tcg_debug_assert(!ts->fixed_reg);
3868d63e3b6eSRichard Henderson 
3869ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
387098b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
387159d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
3872f8bf00f1SRichard Henderson             temp_dead(s, ts);
3873ec7a869dSAurelien Jarno         }
3874c896fe29Sbellard     }
3875c896fe29Sbellard }
3876c896fe29Sbellard 
3877b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP
3878b03cce8eSbellard #define STACK_DIR(x) (-(x))
3879b03cce8eSbellard #else
3880b03cce8eSbellard #define STACK_DIR(x) (x)
3881b03cce8eSbellard #endif
3882b03cce8eSbellard 
3883dd186292SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
3884c896fe29Sbellard {
3885cd9090aaSRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
3886cd9090aaSRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
3887dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3888b6638662SRichard Henderson     int flags, nb_regs, i;
3889b6638662SRichard Henderson     TCGReg reg;
3890cf066674SRichard Henderson     TCGArg arg;
3891c896fe29Sbellard     TCGTemp *ts;
3892d3452f1fSRichard Henderson     intptr_t stack_offset;
3893d3452f1fSRichard Henderson     size_t call_stack_size;
3894cf066674SRichard Henderson     tcg_insn_unit *func_addr;
3895cf066674SRichard Henderson     int allocate_args;
3896c896fe29Sbellard     TCGRegSet allocated_regs;
3897c896fe29Sbellard 
3898dd186292SRichard Henderson     func_addr = (tcg_insn_unit *)(intptr_t)op->args[nb_oargs + nb_iargs];
3899dd186292SRichard Henderson     flags = op->args[nb_oargs + nb_iargs + 1];
3900c896fe29Sbellard 
39016e17d0c5SStefan Weil     nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
3902c45cb8bbSRichard Henderson     if (nb_regs > nb_iargs) {
3903c45cb8bbSRichard Henderson         nb_regs = nb_iargs;
3904cf066674SRichard Henderson     }
3905c896fe29Sbellard 
3906c896fe29Sbellard     /* assign stack slots first */
3907c45cb8bbSRichard Henderson     call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long);
3908c896fe29Sbellard     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
3909c896fe29Sbellard         ~(TCG_TARGET_STACK_ALIGN - 1);
3910b03cce8eSbellard     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
3911b03cce8eSbellard     if (allocate_args) {
3912345649c0SBlue Swirl         /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
3913345649c0SBlue Swirl            preallocate call stack */
3914345649c0SBlue Swirl         tcg_abort();
3915b03cce8eSbellard     }
391639cf05d3Sbellard 
391739cf05d3Sbellard     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
3918c45cb8bbSRichard Henderson     for (i = nb_regs; i < nb_iargs; i++) {
3919dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
392039cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP
392139cf05d3Sbellard         stack_offset -= sizeof(tcg_target_long);
392239cf05d3Sbellard #endif
392339cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
392443439139SRichard Henderson             ts = arg_temp(arg);
392540ae5c62SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
3926b722452aSRichard Henderson                       s->reserved_regs, 0);
3927e4d5434cSblueswir1             tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
392839cf05d3Sbellard         }
392939cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP
393039cf05d3Sbellard         stack_offset += sizeof(tcg_target_long);
393139cf05d3Sbellard #endif
3932c896fe29Sbellard     }
3933c896fe29Sbellard 
3934c896fe29Sbellard     /* assign input registers */
3935d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
3936c896fe29Sbellard     for (i = 0; i < nb_regs; i++) {
3937dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
393839cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
393943439139SRichard Henderson             ts = arg_temp(arg);
3940c896fe29Sbellard             reg = tcg_target_call_iarg_regs[i];
394140ae5c62SRichard Henderson 
3942c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
3943c896fe29Sbellard                 if (ts->reg != reg) {
39444250da10SRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
394578113e83SRichard Henderson                     if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
3946240c08d0SRichard Henderson                         /*
3947240c08d0SRichard Henderson                          * Cross register class move not supported.  Sync the
3948240c08d0SRichard Henderson                          * temp back to its slot and load from there.
3949240c08d0SRichard Henderson                          */
3950240c08d0SRichard Henderson                         temp_sync(s, ts, allocated_regs, 0, 0);
3951240c08d0SRichard Henderson                         tcg_out_ld(s, ts->type, reg,
3952240c08d0SRichard Henderson                                    ts->mem_base->reg, ts->mem_offset);
395378113e83SRichard Henderson                     }
3954c896fe29Sbellard                 }
3955c896fe29Sbellard             } else {
3956ccb1bb66SRichard Henderson                 TCGRegSet arg_set = 0;
395740ae5c62SRichard Henderson 
39584250da10SRichard Henderson                 tcg_reg_free(s, reg, allocated_regs);
395940ae5c62SRichard Henderson                 tcg_regset_set_reg(arg_set, reg);
3960b722452aSRichard Henderson                 temp_load(s, ts, arg_set, allocated_regs, 0);
3961c896fe29Sbellard             }
396240ae5c62SRichard Henderson 
3963c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
3964c896fe29Sbellard         }
396539cf05d3Sbellard     }
3966c896fe29Sbellard 
3967c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
3968866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3969866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
397043439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
3971c896fe29Sbellard         }
3972c896fe29Sbellard     }
3973c896fe29Sbellard 
3974c896fe29Sbellard     /* clobber call registers */
3975c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
3976c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
3977b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
3978c896fe29Sbellard         }
3979c896fe29Sbellard     }
3980c896fe29Sbellard 
398178505279SAurelien Jarno     /* Save globals if they might be written by the helper, sync them if
398278505279SAurelien Jarno        they might be read. */
398378505279SAurelien Jarno     if (flags & TCG_CALL_NO_READ_GLOBALS) {
398478505279SAurelien Jarno         /* Nothing to do */
398578505279SAurelien Jarno     } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) {
398678505279SAurelien Jarno         sync_globals(s, allocated_regs);
398778505279SAurelien Jarno     } else {
3988e8996ee0Sbellard         save_globals(s, allocated_regs);
3989b9c18f56Saurel32     }
3990c896fe29Sbellard 
3991cf066674SRichard Henderson     tcg_out_call(s, func_addr);
3992c896fe29Sbellard 
3993c896fe29Sbellard     /* assign output registers and emit moves if needed */
3994c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
3995dd186292SRichard Henderson         arg = op->args[i];
399643439139SRichard Henderson         ts = arg_temp(arg);
3997d63e3b6eSRichard Henderson 
3998d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
3999d63e3b6eSRichard Henderson         tcg_debug_assert(!ts->fixed_reg);
4000d63e3b6eSRichard Henderson 
4001c896fe29Sbellard         reg = tcg_target_call_oarg_regs[i];
4002eabb7b91SAurelien Jarno         tcg_debug_assert(s->reg_to_temp[reg] == NULL);
4003639368ddSAurelien Jarno         if (ts->val_type == TEMP_VAL_REG) {
4004f8b2f202SRichard Henderson             s->reg_to_temp[ts->reg] = NULL;
4005639368ddSAurelien Jarno         }
4006c896fe29Sbellard         ts->val_type = TEMP_VAL_REG;
4007c896fe29Sbellard         ts->reg = reg;
4008c896fe29Sbellard         ts->mem_coherent = 0;
4009f8b2f202SRichard Henderson         s->reg_to_temp[reg] = ts;
4010ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
401198b4e186SRichard Henderson             temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i));
401259d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4013f8bf00f1SRichard Henderson             temp_dead(s, ts);
4014c896fe29Sbellard         }
4015c896fe29Sbellard     }
40168c11ad25SAurelien Jarno }
4017c896fe29Sbellard 
4018c896fe29Sbellard #ifdef CONFIG_PROFILER
4019c896fe29Sbellard 
4020c3fac113SEmilio G. Cota /* avoid copy/paste errors */
4021c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field)                       \
4022c3fac113SEmilio G. Cota     do {                                                \
4023d73415a3SStefan Hajnoczi         (to)->field += qatomic_read(&((from)->field));  \
4024c3fac113SEmilio G. Cota     } while (0)
4025c896fe29Sbellard 
4026c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field)                                       \
4027c3fac113SEmilio G. Cota     do {                                                                \
4028d73415a3SStefan Hajnoczi         typeof((from)->field) val__ = qatomic_read(&((from)->field));   \
4029c3fac113SEmilio G. Cota         if (val__ > (to)->field) {                                      \
4030c3fac113SEmilio G. Cota             (to)->field = val__;                                        \
4031c3fac113SEmilio G. Cota         }                                                               \
4032c3fac113SEmilio G. Cota     } while (0)
4033c3fac113SEmilio G. Cota 
4034c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */
4035c3fac113SEmilio G. Cota static inline
4036c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
4037c896fe29Sbellard {
4038d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
4039c3fac113SEmilio G. Cota     unsigned int i;
4040c3fac113SEmilio G. Cota 
40413468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4042d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
40433468b59eSEmilio G. Cota         const TCGProfile *orig = &s->prof;
4044c3fac113SEmilio G. Cota 
4045c3fac113SEmilio G. Cota         if (counters) {
404672fd2efbSEmilio G. Cota             PROF_ADD(prof, orig, cpu_exec_time);
4047c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count1);
4048c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count);
4049c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, op_count);
4050c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, op_count_max);
4051c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, temp_count);
4052c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, temp_count_max);
4053c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, del_op_count);
4054c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_in_len);
4055c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_out_len);
4056c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, search_out_len);
4057c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, interm_time);
4058c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_time);
4059c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, la_time);
4060c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, opt_time);
4061c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_count);
4062c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_time);
4063c3fac113SEmilio G. Cota         }
4064c3fac113SEmilio G. Cota         if (table) {
4065c896fe29Sbellard             int i;
4066d70724ceSzhanghailiang 
406715fc7daaSRichard Henderson             for (i = 0; i < NB_OPS; i++) {
4068c3fac113SEmilio G. Cota                 PROF_ADD(prof, orig, table_op_count[i]);
4069c3fac113SEmilio G. Cota             }
4070c3fac113SEmilio G. Cota         }
4071c3fac113SEmilio G. Cota     }
4072c3fac113SEmilio G. Cota }
4073c3fac113SEmilio G. Cota 
4074c3fac113SEmilio G. Cota #undef PROF_ADD
4075c3fac113SEmilio G. Cota #undef PROF_MAX
4076c3fac113SEmilio G. Cota 
4077c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof)
4078c3fac113SEmilio G. Cota {
4079c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, true, false);
4080c3fac113SEmilio G. Cota }
4081c3fac113SEmilio G. Cota 
4082c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof)
4083c3fac113SEmilio G. Cota {
4084c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, false, true);
4085c3fac113SEmilio G. Cota }
4086c3fac113SEmilio G. Cota 
4087d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
4088c3fac113SEmilio G. Cota {
4089c3fac113SEmilio G. Cota     TCGProfile prof = {};
4090c3fac113SEmilio G. Cota     int i;
4091c3fac113SEmilio G. Cota 
4092c3fac113SEmilio G. Cota     tcg_profile_snapshot_table(&prof);
4093c3fac113SEmilio G. Cota     for (i = 0; i < NB_OPS; i++) {
4094d4c51a0aSMarkus Armbruster         qemu_printf("%s %" PRId64 "\n", tcg_op_defs[i].name,
4095c3fac113SEmilio G. Cota                     prof.table_op_count[i]);
4096c896fe29Sbellard     }
4097c896fe29Sbellard }
409872fd2efbSEmilio G. Cota 
409972fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
410072fd2efbSEmilio G. Cota {
4101d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
410272fd2efbSEmilio G. Cota     unsigned int i;
410372fd2efbSEmilio G. Cota     int64_t ret = 0;
410472fd2efbSEmilio G. Cota 
410572fd2efbSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4106d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
410772fd2efbSEmilio G. Cota         const TCGProfile *prof = &s->prof;
410872fd2efbSEmilio G. Cota 
4109d73415a3SStefan Hajnoczi         ret += qatomic_read(&prof->cpu_exec_time);
411072fd2efbSEmilio G. Cota     }
411172fd2efbSEmilio G. Cota     return ret;
411272fd2efbSEmilio G. Cota }
4113246ae24dSMax Filippov #else
4114d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
4115246ae24dSMax Filippov {
4116d4c51a0aSMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4117246ae24dSMax Filippov }
411872fd2efbSEmilio G. Cota 
411972fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
412072fd2efbSEmilio G. Cota {
412172fd2efbSEmilio G. Cota     error_report("%s: TCG profiler not compiled", __func__);
412272fd2efbSEmilio G. Cota     exit(EXIT_FAILURE);
412372fd2efbSEmilio G. Cota }
4124c896fe29Sbellard #endif
4125c896fe29Sbellard 
4126c896fe29Sbellard 
41275bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
4128c896fe29Sbellard {
4129c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER
4130c3fac113SEmilio G. Cota     TCGProfile *prof = &s->prof;
4131c3fac113SEmilio G. Cota #endif
413215fa08f8SRichard Henderson     int i, num_insns;
413315fa08f8SRichard Henderson     TCGOp *op;
4134c896fe29Sbellard 
413504fe6400SRichard Henderson #ifdef CONFIG_PROFILER
413604fe6400SRichard Henderson     {
4137c1f543b7SEmilio G. Cota         int n = 0;
413804fe6400SRichard Henderson 
413915fa08f8SRichard Henderson         QTAILQ_FOREACH(op, &s->ops, link) {
414015fa08f8SRichard Henderson             n++;
414115fa08f8SRichard Henderson         }
4142d73415a3SStefan Hajnoczi         qatomic_set(&prof->op_count, prof->op_count + n);
4143c3fac113SEmilio G. Cota         if (n > prof->op_count_max) {
4144d73415a3SStefan Hajnoczi             qatomic_set(&prof->op_count_max, n);
414504fe6400SRichard Henderson         }
414604fe6400SRichard Henderson 
414704fe6400SRichard Henderson         n = s->nb_temps;
4148d73415a3SStefan Hajnoczi         qatomic_set(&prof->temp_count, prof->temp_count + n);
4149c3fac113SEmilio G. Cota         if (n > prof->temp_count_max) {
4150d73415a3SStefan Hajnoczi             qatomic_set(&prof->temp_count_max, n);
415104fe6400SRichard Henderson         }
415204fe6400SRichard Henderson     }
415304fe6400SRichard Henderson #endif
415404fe6400SRichard Henderson 
4155c896fe29Sbellard #ifdef DEBUG_DISAS
4156d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
4157d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
4158fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
415993fcfe39Saliguori         qemu_log("OP:\n");
41601894f69aSRichard Henderson         tcg_dump_ops(s, false);
416193fcfe39Saliguori         qemu_log("\n");
4162fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
4163c896fe29Sbellard     }
4164c896fe29Sbellard #endif
4165c896fe29Sbellard 
4166bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
4167bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
4168bef16ab4SRichard Henderson     {
4169bef16ab4SRichard Henderson         TCGLabel *l;
4170bef16ab4SRichard Henderson         bool error = false;
4171bef16ab4SRichard Henderson 
4172bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
4173bef16ab4SRichard Henderson             if (unlikely(!l->present) && l->refs) {
4174bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
4175bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
4176bef16ab4SRichard Henderson                 error = true;
4177bef16ab4SRichard Henderson             }
4178bef16ab4SRichard Henderson         }
4179bef16ab4SRichard Henderson         assert(!error);
4180bef16ab4SRichard Henderson     }
4181bef16ab4SRichard Henderson #endif
4182bef16ab4SRichard Henderson 
4183c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
4184d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
4185c5cc28ffSAurelien Jarno #endif
4186c5cc28ffSAurelien Jarno 
41878f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
4188c45cb8bbSRichard Henderson     tcg_optimize(s);
41898f2e8c07SKirill Batuzov #endif
41908f2e8c07SKirill Batuzov 
4191a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4192d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
4193d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time - profile_getclock());
4194a23a9ec6Sbellard #endif
4195c5cc28ffSAurelien Jarno 
4196b4fc67c7SRichard Henderson     reachable_code_pass(s);
4197b83eabeaSRichard Henderson     liveness_pass_1(s);
41985a18407fSRichard Henderson 
41995a18407fSRichard Henderson     if (s->nb_indirects > 0) {
42005a18407fSRichard Henderson #ifdef DEBUG_DISAS
42015a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
42025a18407fSRichard Henderson                      && qemu_log_in_addr_range(tb->pc))) {
4203fc59d2d8SRobert Foley             FILE *logfile = qemu_log_lock();
42045a18407fSRichard Henderson             qemu_log("OP before indirect lowering:\n");
42051894f69aSRichard Henderson             tcg_dump_ops(s, false);
42065a18407fSRichard Henderson             qemu_log("\n");
4207fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
42085a18407fSRichard Henderson         }
42095a18407fSRichard Henderson #endif
42105a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
4211b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
42125a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
4213b83eabeaSRichard Henderson             liveness_pass_1(s);
42145a18407fSRichard Henderson         }
42155a18407fSRichard Henderson     }
4216c5cc28ffSAurelien Jarno 
4217a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4218d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time + profile_getclock());
4219a23a9ec6Sbellard #endif
4220c896fe29Sbellard 
4221c896fe29Sbellard #ifdef DEBUG_DISAS
4222d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
4223d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
4224fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
4225c5cc28ffSAurelien Jarno         qemu_log("OP after optimization and liveness analysis:\n");
42261894f69aSRichard Henderson         tcg_dump_ops(s, true);
422793fcfe39Saliguori         qemu_log("\n");
4228fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
4229c896fe29Sbellard     }
4230c896fe29Sbellard #endif
4231c896fe29Sbellard 
4232c896fe29Sbellard     tcg_reg_alloc_start(s);
4233c896fe29Sbellard 
4234e7e168f4SEmilio G. Cota     s->code_buf = tb->tc.ptr;
4235e7e168f4SEmilio G. Cota     s->code_ptr = tb->tc.ptr;
4236c896fe29Sbellard 
4237659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
42386001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
4239659ef5cbSRichard Henderson #endif
424057a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
424157a26946SRichard Henderson     s->pool_labels = NULL;
424257a26946SRichard Henderson #endif
42439ecefc84SRichard Henderson 
4244fca8a500SRichard Henderson     num_insns = -1;
424515fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
4246c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
4247b3db8758Sblueswir1 
4248c896fe29Sbellard #ifdef CONFIG_PROFILER
4249d73415a3SStefan Hajnoczi         qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
4250c896fe29Sbellard #endif
4251c45cb8bbSRichard Henderson 
4252c896fe29Sbellard         switch (opc) {
4253c896fe29Sbellard         case INDEX_op_mov_i32:
4254c896fe29Sbellard         case INDEX_op_mov_i64:
4255d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
4256dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
4257c896fe29Sbellard             break;
4258e8996ee0Sbellard         case INDEX_op_movi_i32:
4259e8996ee0Sbellard         case INDEX_op_movi_i64:
4260d2fd745fSRichard Henderson         case INDEX_op_dupi_vec:
4261dd186292SRichard Henderson             tcg_reg_alloc_movi(s, op);
4262e8996ee0Sbellard             break;
4263bab1671fSRichard Henderson         case INDEX_op_dup_vec:
4264bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
4265bab1671fSRichard Henderson             break;
4266765b842aSRichard Henderson         case INDEX_op_insn_start:
4267fca8a500SRichard Henderson             if (num_insns >= 0) {
42689f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
42699f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
42709f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
42719f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
4272fca8a500SRichard Henderson             }
4273fca8a500SRichard Henderson             num_insns++;
4274bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
4275bad729e2SRichard Henderson                 target_ulong a;
4276bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
4277efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
4278bad729e2SRichard Henderson #else
4279efee3746SRichard Henderson                 a = op->args[i];
4280bad729e2SRichard Henderson #endif
4281fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
4282bad729e2SRichard Henderson             }
4283c896fe29Sbellard             break;
42845ff9d6a4Sbellard         case INDEX_op_discard:
428543439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
42865ff9d6a4Sbellard             break;
4287c896fe29Sbellard         case INDEX_op_set_label:
4288e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
4289efee3746SRichard Henderson             tcg_out_label(s, arg_label(op->args[0]), s->code_ptr);
4290c896fe29Sbellard             break;
4291c896fe29Sbellard         case INDEX_op_call:
4292dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
4293c45cb8bbSRichard Henderson             break;
4294c896fe29Sbellard         default:
429525c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
4296be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
4297c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
4298c896fe29Sbellard                faster to have specialized register allocator functions for
4299c896fe29Sbellard                some common argument patterns */
4300dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
4301c896fe29Sbellard             break;
4302c896fe29Sbellard         }
43038d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
4304c896fe29Sbellard         check_regs(s);
4305c896fe29Sbellard #endif
4306b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
4307b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
4308b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
4309b125f9dcSRichard Henderson            generating code without having to check during generation.  */
4310644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
4311b125f9dcSRichard Henderson             return -1;
4312b125f9dcSRichard Henderson         }
43136e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
43146e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
43156e6c4efeSRichard Henderson             return -2;
43166e6c4efeSRichard Henderson         }
4317c896fe29Sbellard     }
4318fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
4319fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
4320c45cb8bbSRichard Henderson 
4321b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
4322659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
4323aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
4324aeee05f5SRichard Henderson     if (i < 0) {
4325aeee05f5SRichard Henderson         return i;
432623dceda6SRichard Henderson     }
4327659ef5cbSRichard Henderson #endif
432857a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
43291768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
43301768987bSRichard Henderson     if (i < 0) {
43311768987bSRichard Henderson         return i;
433257a26946SRichard Henderson     }
433357a26946SRichard Henderson #endif
43347ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
43357ecd02a0SRichard Henderson         return -2;
43367ecd02a0SRichard Henderson     }
4337c896fe29Sbellard 
4338df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
4339c896fe29Sbellard     /* flush instruction cache */
43401da8de39SRichard Henderson     flush_idcache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_buf,
43411da8de39SRichard Henderson                         tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
4342df5d2b16SRichard Henderson #endif
43432aeabc08SStefan Weil 
43441813e175SRichard Henderson     return tcg_current_code_size(s);
4345c896fe29Sbellard }
4346c896fe29Sbellard 
4347a23a9ec6Sbellard #ifdef CONFIG_PROFILER
43483de2faa9SMarkus Armbruster void tcg_dump_info(void)
4349a23a9ec6Sbellard {
4350c3fac113SEmilio G. Cota     TCGProfile prof = {};
4351c3fac113SEmilio G. Cota     const TCGProfile *s;
4352c3fac113SEmilio G. Cota     int64_t tb_count;
4353c3fac113SEmilio G. Cota     int64_t tb_div_count;
4354c3fac113SEmilio G. Cota     int64_t tot;
4355c3fac113SEmilio G. Cota 
4356c3fac113SEmilio G. Cota     tcg_profile_snapshot_counters(&prof);
4357c3fac113SEmilio G. Cota     s = &prof;
4358c3fac113SEmilio G. Cota     tb_count = s->tb_count;
4359c3fac113SEmilio G. Cota     tb_div_count = tb_count ? tb_count : 1;
4360c3fac113SEmilio G. Cota     tot = s->interm_time + s->code_time;
4361a23a9ec6Sbellard 
43623de2faa9SMarkus Armbruster     qemu_printf("JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
4363a23a9ec6Sbellard                 tot, tot / 2.4e9);
43643de2faa9SMarkus Armbruster     qemu_printf("translated TBs      %" PRId64 " (aborted=%" PRId64
43653de2faa9SMarkus Armbruster                 " %0.1f%%)\n",
4366fca8a500SRichard Henderson                 tb_count, s->tb_count1 - tb_count,
4367fca8a500SRichard Henderson                 (double)(s->tb_count1 - s->tb_count)
4368fca8a500SRichard Henderson                 / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
43693de2faa9SMarkus Armbruster     qemu_printf("avg ops/TB          %0.1f max=%d\n",
4370fca8a500SRichard Henderson                 (double)s->op_count / tb_div_count, s->op_count_max);
43713de2faa9SMarkus Armbruster     qemu_printf("deleted ops/TB      %0.2f\n",
4372fca8a500SRichard Henderson                 (double)s->del_op_count / tb_div_count);
43733de2faa9SMarkus Armbruster     qemu_printf("avg temps/TB        %0.2f max=%d\n",
4374fca8a500SRichard Henderson                 (double)s->temp_count / tb_div_count, s->temp_count_max);
43753de2faa9SMarkus Armbruster     qemu_printf("avg host code/TB    %0.1f\n",
4376fca8a500SRichard Henderson                 (double)s->code_out_len / tb_div_count);
43773de2faa9SMarkus Armbruster     qemu_printf("avg search data/TB  %0.1f\n",
4378fca8a500SRichard Henderson                 (double)s->search_out_len / tb_div_count);
4379a23a9ec6Sbellard 
43803de2faa9SMarkus Armbruster     qemu_printf("cycles/op           %0.1f\n",
4381a23a9ec6Sbellard                 s->op_count ? (double)tot / s->op_count : 0);
43823de2faa9SMarkus Armbruster     qemu_printf("cycles/in byte      %0.1f\n",
4383a23a9ec6Sbellard                 s->code_in_len ? (double)tot / s->code_in_len : 0);
43843de2faa9SMarkus Armbruster     qemu_printf("cycles/out byte     %0.1f\n",
4385a23a9ec6Sbellard                 s->code_out_len ? (double)tot / s->code_out_len : 0);
43863de2faa9SMarkus Armbruster     qemu_printf("cycles/search byte     %0.1f\n",
4387fca8a500SRichard Henderson                 s->search_out_len ? (double)tot / s->search_out_len : 0);
4388fca8a500SRichard Henderson     if (tot == 0) {
4389a23a9ec6Sbellard         tot = 1;
4390fca8a500SRichard Henderson     }
43913de2faa9SMarkus Armbruster     qemu_printf("  gen_interm time   %0.1f%%\n",
4392a23a9ec6Sbellard                 (double)s->interm_time / tot * 100.0);
43933de2faa9SMarkus Armbruster     qemu_printf("  gen_code time     %0.1f%%\n",
4394a23a9ec6Sbellard                 (double)s->code_time / tot * 100.0);
43953de2faa9SMarkus Armbruster     qemu_printf("optim./code time    %0.1f%%\n",
4396c5cc28ffSAurelien Jarno                 (double)s->opt_time / (s->code_time ? s->code_time : 1)
4397c5cc28ffSAurelien Jarno                 * 100.0);
43983de2faa9SMarkus Armbruster     qemu_printf("liveness/code time  %0.1f%%\n",
4399a23a9ec6Sbellard                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
44003de2faa9SMarkus Armbruster     qemu_printf("cpu_restore count   %" PRId64 "\n",
4401a23a9ec6Sbellard                 s->restore_count);
44023de2faa9SMarkus Armbruster     qemu_printf("  avg cycles        %0.1f\n",
4403a23a9ec6Sbellard                 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
4404a23a9ec6Sbellard }
4405a23a9ec6Sbellard #else
44063de2faa9SMarkus Armbruster void tcg_dump_info(void)
4407a23a9ec6Sbellard {
44083de2faa9SMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4409a23a9ec6Sbellard }
4410a23a9ec6Sbellard #endif
4411813da627SRichard Henderson 
4412813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
44135872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
44145872bbf2SRichard Henderson 
44155872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
44165872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
44175872bbf2SRichard Henderson 
44185872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
44195872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
44205872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
44215872bbf2SRichard Henderson 
44225872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
44235872bbf2SRichard Henderson */
4424813da627SRichard Henderson 
4425813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
4426813da627SRichard Henderson typedef enum {
4427813da627SRichard Henderson     JIT_NOACTION = 0,
4428813da627SRichard Henderson     JIT_REGISTER_FN,
4429813da627SRichard Henderson     JIT_UNREGISTER_FN
4430813da627SRichard Henderson } jit_actions_t;
4431813da627SRichard Henderson 
4432813da627SRichard Henderson struct jit_code_entry {
4433813da627SRichard Henderson     struct jit_code_entry *next_entry;
4434813da627SRichard Henderson     struct jit_code_entry *prev_entry;
4435813da627SRichard Henderson     const void *symfile_addr;
4436813da627SRichard Henderson     uint64_t symfile_size;
4437813da627SRichard Henderson };
4438813da627SRichard Henderson 
4439813da627SRichard Henderson struct jit_descriptor {
4440813da627SRichard Henderson     uint32_t version;
4441813da627SRichard Henderson     uint32_t action_flag;
4442813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
4443813da627SRichard Henderson     struct jit_code_entry *first_entry;
4444813da627SRichard Henderson };
4445813da627SRichard Henderson 
4446813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
4447813da627SRichard Henderson void __jit_debug_register_code(void)
4448813da627SRichard Henderson {
4449813da627SRichard Henderson     asm("");
4450813da627SRichard Henderson }
4451813da627SRichard Henderson 
4452813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
4453813da627SRichard Henderson    the version before we can set it.  */
4454813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
4455813da627SRichard Henderson 
4456813da627SRichard Henderson /* End GDB interface.  */
4457813da627SRichard Henderson 
4458813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
4459813da627SRichard Henderson {
4460813da627SRichard Henderson     const char *p = strtab + 1;
4461813da627SRichard Henderson 
4462813da627SRichard Henderson     while (1) {
4463813da627SRichard Henderson         if (strcmp(p, str) == 0) {
4464813da627SRichard Henderson             return p - strtab;
4465813da627SRichard Henderson         }
4466813da627SRichard Henderson         p += strlen(p) + 1;
4467813da627SRichard Henderson     }
4468813da627SRichard Henderson }
4469813da627SRichard Henderson 
44705872bbf2SRichard Henderson static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
44712c90784aSRichard Henderson                                  const void *debug_frame,
44722c90784aSRichard Henderson                                  size_t debug_frame_size)
4473813da627SRichard Henderson {
44745872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
44755872bbf2SRichard Henderson         uint32_t  len;
44765872bbf2SRichard Henderson         uint16_t  version;
44775872bbf2SRichard Henderson         uint32_t  abbrev;
44785872bbf2SRichard Henderson         uint8_t   ptr_size;
44795872bbf2SRichard Henderson         uint8_t   cu_die;
44805872bbf2SRichard Henderson         uint16_t  cu_lang;
44815872bbf2SRichard Henderson         uintptr_t cu_low_pc;
44825872bbf2SRichard Henderson         uintptr_t cu_high_pc;
44835872bbf2SRichard Henderson         uint8_t   fn_die;
44845872bbf2SRichard Henderson         char      fn_name[16];
44855872bbf2SRichard Henderson         uintptr_t fn_low_pc;
44865872bbf2SRichard Henderson         uintptr_t fn_high_pc;
44875872bbf2SRichard Henderson         uint8_t   cu_eoc;
44885872bbf2SRichard Henderson     };
4489813da627SRichard Henderson 
4490813da627SRichard Henderson     struct ElfImage {
4491813da627SRichard Henderson         ElfW(Ehdr) ehdr;
4492813da627SRichard Henderson         ElfW(Phdr) phdr;
44935872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
44945872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
44955872bbf2SRichard Henderson         struct DebugInfo di;
44965872bbf2SRichard Henderson         uint8_t    da[24];
44975872bbf2SRichard Henderson         char       str[80];
44985872bbf2SRichard Henderson     };
44995872bbf2SRichard Henderson 
45005872bbf2SRichard Henderson     struct ElfImage *img;
45015872bbf2SRichard Henderson 
45025872bbf2SRichard Henderson     static const struct ElfImage img_template = {
45035872bbf2SRichard Henderson         .ehdr = {
45045872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
45055872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
45065872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
45075872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
45085872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
45095872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
45105872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
45115872bbf2SRichard Henderson             .e_type = ET_EXEC,
45125872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
45135872bbf2SRichard Henderson             .e_version = EV_CURRENT,
45145872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
45155872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
45165872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
45175872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
45185872bbf2SRichard Henderson             .e_phnum = 1,
45195872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
45205872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
45215872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
4522abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
4523abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
4524abbb3eaeSRichard Henderson #endif
4525abbb3eaeSRichard Henderson #ifdef ELF_OSABI
4526abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
4527abbb3eaeSRichard Henderson #endif
45285872bbf2SRichard Henderson         },
45295872bbf2SRichard Henderson         .phdr = {
45305872bbf2SRichard Henderson             .p_type = PT_LOAD,
45315872bbf2SRichard Henderson             .p_flags = PF_X,
45325872bbf2SRichard Henderson         },
45335872bbf2SRichard Henderson         .shdr = {
45345872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
45355872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
45365872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
45375872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
45385872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
45395872bbf2SRichard Henderson             [1] = { /* .text */
45405872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
45415872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
45425872bbf2SRichard Henderson             },
45435872bbf2SRichard Henderson             [2] = { /* .debug_info */
45445872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
45455872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
45465872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
45475872bbf2SRichard Henderson             },
45485872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
45495872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
45505872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
45515872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
45525872bbf2SRichard Henderson             },
45535872bbf2SRichard Henderson             [4] = { /* .debug_frame */
45545872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
45555872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
45565872bbf2SRichard Henderson             },
45575872bbf2SRichard Henderson             [5] = { /* .symtab */
45585872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
45595872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
45605872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
45615872bbf2SRichard Henderson                 .sh_info = 1,
45625872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
45635872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
45645872bbf2SRichard Henderson             },
45655872bbf2SRichard Henderson             [6] = { /* .strtab */
45665872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
45675872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
45685872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
45695872bbf2SRichard Henderson             }
45705872bbf2SRichard Henderson         },
45715872bbf2SRichard Henderson         .sym = {
45725872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
45735872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
45745872bbf2SRichard Henderson                 .st_shndx = 1,
45755872bbf2SRichard Henderson             }
45765872bbf2SRichard Henderson         },
45775872bbf2SRichard Henderson         .di = {
45785872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
45795872bbf2SRichard Henderson             .version = 2,
45805872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
45815872bbf2SRichard Henderson             .cu_die = 1,
45825872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
45835872bbf2SRichard Henderson             .fn_die = 2,
45845872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
45855872bbf2SRichard Henderson         },
45865872bbf2SRichard Henderson         .da = {
45875872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
45885872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
45895872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
45905872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
45915872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
45925872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
45935872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
45945872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
45955872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
45965872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
45975872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
45985872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
45995872bbf2SRichard Henderson             0           /* no more abbrev */
46005872bbf2SRichard Henderson         },
46015872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
46025872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
4603813da627SRichard Henderson     };
4604813da627SRichard Henderson 
4605813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
4606813da627SRichard Henderson     static struct jit_code_entry one_entry;
4607813da627SRichard Henderson 
46085872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
4609813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
46102c90784aSRichard Henderson     DebugFrameHeader *dfh;
4611813da627SRichard Henderson 
46125872bbf2SRichard Henderson     img = g_malloc(img_size);
46135872bbf2SRichard Henderson     *img = img_template;
4614813da627SRichard Henderson 
46155872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
46165872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
46175872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
4618813da627SRichard Henderson 
46195872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
46205872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
46215872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
4622813da627SRichard Henderson 
46235872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
46245872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
46255872bbf2SRichard Henderson 
46265872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
46275872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
46285872bbf2SRichard Henderson 
46295872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
46305872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
46315872bbf2SRichard Henderson 
46325872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
46335872bbf2SRichard Henderson     img->sym[1].st_value = buf;
46345872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
46355872bbf2SRichard Henderson 
46365872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
463745aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
46385872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
463945aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
4640813da627SRichard Henderson 
46412c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
46422c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
46432c90784aSRichard Henderson     dfh->fde.func_start = buf;
46442c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
46452c90784aSRichard Henderson 
4646813da627SRichard Henderson #ifdef DEBUG_JIT
4647813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
4648813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
4649813da627SRichard Henderson     {
4650813da627SRichard Henderson         FILE *f = fopen("/tmp/qemu.jit", "w+b");
4651813da627SRichard Henderson         if (f) {
46525872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
4653813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
4654813da627SRichard Henderson             }
4655813da627SRichard Henderson             fclose(f);
4656813da627SRichard Henderson         }
4657813da627SRichard Henderson     }
4658813da627SRichard Henderson #endif
4659813da627SRichard Henderson 
4660813da627SRichard Henderson     one_entry.symfile_addr = img;
4661813da627SRichard Henderson     one_entry.symfile_size = img_size;
4662813da627SRichard Henderson 
4663813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
4664813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
4665813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
4666813da627SRichard Henderson     __jit_debug_register_code();
4667813da627SRichard Henderson }
4668813da627SRichard Henderson #else
46695872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
46705872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
4671813da627SRichard Henderson 
4672813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size,
46732c90784aSRichard Henderson                                  const void *debug_frame,
46742c90784aSRichard Henderson                                  size_t debug_frame_size)
4675813da627SRichard Henderson {
4676813da627SRichard Henderson }
4677813da627SRichard Henderson 
4678813da627SRichard Henderson void tcg_register_jit(void *buf, size_t buf_size)
4679813da627SRichard Henderson {
4680813da627SRichard Henderson }
4681813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
4682db432672SRichard Henderson 
4683db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
4684db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
4685db432672SRichard Henderson {
4686db432672SRichard Henderson     g_assert_not_reached();
4687db432672SRichard Henderson }
4688db432672SRichard Henderson #endif
4689