xref: /qemu/tcg/tcg.c (revision 07ce0b05300de5bc8f1932a4cfbe38f3323e5ab1)
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;
164df2cce29SEmilio G. Cota 
165be2cdc5eSEmilio G. Cota struct tcg_region_tree {
166be2cdc5eSEmilio G. Cota     QemuMutex lock;
167be2cdc5eSEmilio G. Cota     GTree *tree;
168be2cdc5eSEmilio G. Cota     /* padding to avoid false sharing is computed at run-time */
169be2cdc5eSEmilio G. Cota };
170be2cdc5eSEmilio G. Cota 
171e8feb96fSEmilio G. Cota /*
172e8feb96fSEmilio G. Cota  * We divide code_gen_buffer into equally-sized "regions" that TCG threads
173e8feb96fSEmilio G. Cota  * dynamically allocate from as demand dictates. Given appropriate region
174e8feb96fSEmilio G. Cota  * sizing, this minimizes flushes even when some TCG threads generate a lot
175e8feb96fSEmilio G. Cota  * more code than others.
176e8feb96fSEmilio G. Cota  */
177e8feb96fSEmilio G. Cota struct tcg_region_state {
178e8feb96fSEmilio G. Cota     QemuMutex lock;
179e8feb96fSEmilio G. Cota 
180e8feb96fSEmilio G. Cota     /* fields set at init time */
181e8feb96fSEmilio G. Cota     void *start;
182e8feb96fSEmilio G. Cota     void *start_aligned;
183e8feb96fSEmilio G. Cota     void *end;
184e8feb96fSEmilio G. Cota     size_t n;
185e8feb96fSEmilio G. Cota     size_t size; /* size of one region */
186e8feb96fSEmilio G. Cota     size_t stride; /* .size + guard size */
187e8feb96fSEmilio G. Cota 
188e8feb96fSEmilio G. Cota     /* fields protected by the lock */
189e8feb96fSEmilio G. Cota     size_t current; /* current region index */
190e8feb96fSEmilio G. Cota     size_t agg_size_full; /* aggregate size of full regions */
191e8feb96fSEmilio G. Cota };
192e8feb96fSEmilio G. Cota 
193e8feb96fSEmilio G. Cota static struct tcg_region_state region;
194be2cdc5eSEmilio G. Cota /*
195be2cdc5eSEmilio G. Cota  * This is an array of struct tcg_region_tree's, with padding.
196be2cdc5eSEmilio G. Cota  * We use void * to simplify the computation of region_trees[i]; each
197be2cdc5eSEmilio G. Cota  * struct is found every tree_size bytes.
198be2cdc5eSEmilio G. Cota  */
199be2cdc5eSEmilio G. Cota static void *region_trees;
200be2cdc5eSEmilio G. Cota static size_t tree_size;
201d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
202b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
203c896fe29Sbellard 
2041813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
2054196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
206c896fe29Sbellard {
207c896fe29Sbellard     *s->code_ptr++ = v;
208c896fe29Sbellard }
209c896fe29Sbellard 
2104196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
2114196dca6SPeter Maydell                                                       uint8_t v)
2125c53bb81SPeter Maydell {
2131813e175SRichard Henderson     *p = v;
2145c53bb81SPeter Maydell }
2151813e175SRichard Henderson #endif
2165c53bb81SPeter Maydell 
2171813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
2184196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
219c896fe29Sbellard {
2201813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2211813e175SRichard Henderson         *s->code_ptr++ = v;
2221813e175SRichard Henderson     } else {
2231813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2244387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2251813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
2261813e175SRichard Henderson     }
227c896fe29Sbellard }
228c896fe29Sbellard 
2294196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2304196dca6SPeter Maydell                                                        uint16_t v)
2315c53bb81SPeter Maydell {
2321813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2331813e175SRichard Henderson         *p = v;
2341813e175SRichard Henderson     } else {
2355c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2365c53bb81SPeter Maydell     }
2371813e175SRichard Henderson }
2381813e175SRichard Henderson #endif
2395c53bb81SPeter Maydell 
2401813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
2414196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
242c896fe29Sbellard {
2431813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2441813e175SRichard Henderson         *s->code_ptr++ = v;
2451813e175SRichard Henderson     } else {
2461813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2474387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2481813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
2491813e175SRichard Henderson     }
250c896fe29Sbellard }
251c896fe29Sbellard 
2524196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
2534196dca6SPeter Maydell                                                        uint32_t v)
2545c53bb81SPeter Maydell {
2551813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2561813e175SRichard Henderson         *p = v;
2571813e175SRichard Henderson     } else {
2585c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2595c53bb81SPeter Maydell     }
2601813e175SRichard Henderson }
2611813e175SRichard Henderson #endif
2625c53bb81SPeter Maydell 
2631813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
2644196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
265ac26eb69SRichard Henderson {
2661813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2671813e175SRichard Henderson         *s->code_ptr++ = v;
2681813e175SRichard Henderson     } else {
2691813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2704387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2711813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
2721813e175SRichard Henderson     }
273ac26eb69SRichard Henderson }
274ac26eb69SRichard Henderson 
2754196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
2764196dca6SPeter Maydell                                                        uint64_t v)
2775c53bb81SPeter Maydell {
2781813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2791813e175SRichard Henderson         *p = v;
2801813e175SRichard Henderson     } else {
2815c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2825c53bb81SPeter Maydell     }
2831813e175SRichard Henderson }
2841813e175SRichard Henderson #endif
2855c53bb81SPeter Maydell 
286c896fe29Sbellard /* label relocation processing */
287c896fe29Sbellard 
2881813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
289bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
290c896fe29Sbellard {
2917ecd02a0SRichard Henderson     TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation));
292c896fe29Sbellard 
293c896fe29Sbellard     r->type = type;
294c896fe29Sbellard     r->ptr = code_ptr;
295c896fe29Sbellard     r->addend = addend;
2967ecd02a0SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
297c896fe29Sbellard }
298c896fe29Sbellard 
299bec16311SRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr)
300c896fe29Sbellard {
301eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
302c896fe29Sbellard     l->has_value = 1;
3031813e175SRichard Henderson     l->u.value_ptr = ptr;
304c896fe29Sbellard }
305c896fe29Sbellard 
30642a268c2SRichard Henderson TCGLabel *gen_new_label(void)
307c896fe29Sbellard {
308b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
30951e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
310c896fe29Sbellard 
3117ecd02a0SRichard Henderson     memset(l, 0, sizeof(TCGLabel));
3127ecd02a0SRichard Henderson     l->id = s->nb_labels++;
3137ecd02a0SRichard Henderson     QSIMPLEQ_INIT(&l->relocs);
3147ecd02a0SRichard Henderson 
315bef16ab4SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
31642a268c2SRichard Henderson 
31742a268c2SRichard Henderson     return l;
318c896fe29Sbellard }
319c896fe29Sbellard 
3207ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s)
3217ecd02a0SRichard Henderson {
3227ecd02a0SRichard Henderson     TCGLabel *l;
3237ecd02a0SRichard Henderson 
3247ecd02a0SRichard Henderson     QSIMPLEQ_FOREACH(l, &s->labels, next) {
3257ecd02a0SRichard Henderson         TCGRelocation *r;
3267ecd02a0SRichard Henderson         uintptr_t value = l->u.value;
3277ecd02a0SRichard Henderson 
3287ecd02a0SRichard Henderson         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
3297ecd02a0SRichard Henderson             if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
3307ecd02a0SRichard Henderson                 return false;
3317ecd02a0SRichard Henderson             }
3327ecd02a0SRichard Henderson         }
3337ecd02a0SRichard Henderson     }
3347ecd02a0SRichard Henderson     return true;
3357ecd02a0SRichard Henderson }
3367ecd02a0SRichard Henderson 
3379f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3389f754620SRichard Henderson {
339f14bed3fSRichard Henderson     /*
340f14bed3fSRichard Henderson      * We will check for overflow at the end of the opcode loop in
341f14bed3fSRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
342f14bed3fSRichard Henderson      */
343f14bed3fSRichard Henderson     s->tb_jmp_reset_offset[which] = tcg_current_code_size(s);
3449f754620SRichard Henderson }
3459f754620SRichard Henderson 
346139c1837SPaolo Bonzini #include "tcg-target.c.inc"
347c896fe29Sbellard 
348be2cdc5eSEmilio G. Cota /* compare a pointer @ptr and a tb_tc @s */
349be2cdc5eSEmilio G. Cota static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s)
350be2cdc5eSEmilio G. Cota {
351be2cdc5eSEmilio G. Cota     if (ptr >= s->ptr + s->size) {
352be2cdc5eSEmilio G. Cota         return 1;
353be2cdc5eSEmilio G. Cota     } else if (ptr < s->ptr) {
354be2cdc5eSEmilio G. Cota         return -1;
355be2cdc5eSEmilio G. Cota     }
356be2cdc5eSEmilio G. Cota     return 0;
357be2cdc5eSEmilio G. Cota }
358be2cdc5eSEmilio G. Cota 
359be2cdc5eSEmilio G. Cota static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp)
360be2cdc5eSEmilio G. Cota {
361be2cdc5eSEmilio G. Cota     const struct tb_tc *a = ap;
362be2cdc5eSEmilio G. Cota     const struct tb_tc *b = bp;
363be2cdc5eSEmilio G. Cota 
364be2cdc5eSEmilio G. Cota     /*
365be2cdc5eSEmilio G. Cota      * When both sizes are set, we know this isn't a lookup.
366be2cdc5eSEmilio G. Cota      * This is the most likely case: every TB must be inserted; lookups
367be2cdc5eSEmilio G. Cota      * are a lot less frequent.
368be2cdc5eSEmilio G. Cota      */
369be2cdc5eSEmilio G. Cota     if (likely(a->size && b->size)) {
370be2cdc5eSEmilio G. Cota         if (a->ptr > b->ptr) {
371be2cdc5eSEmilio G. Cota             return 1;
372be2cdc5eSEmilio G. Cota         } else if (a->ptr < b->ptr) {
373be2cdc5eSEmilio G. Cota             return -1;
374be2cdc5eSEmilio G. Cota         }
375be2cdc5eSEmilio G. Cota         /* a->ptr == b->ptr should happen only on deletions */
376be2cdc5eSEmilio G. Cota         g_assert(a->size == b->size);
377be2cdc5eSEmilio G. Cota         return 0;
378be2cdc5eSEmilio G. Cota     }
379be2cdc5eSEmilio G. Cota     /*
380be2cdc5eSEmilio G. Cota      * All lookups have either .size field set to 0.
381be2cdc5eSEmilio G. Cota      * From the glib sources we see that @ap is always the lookup key. However
382be2cdc5eSEmilio G. Cota      * the docs provide no guarantee, so we just mark this case as likely.
383be2cdc5eSEmilio G. Cota      */
384be2cdc5eSEmilio G. Cota     if (likely(a->size == 0)) {
385be2cdc5eSEmilio G. Cota         return ptr_cmp_tb_tc(a->ptr, b);
386be2cdc5eSEmilio G. Cota     }
387be2cdc5eSEmilio G. Cota     return ptr_cmp_tb_tc(b->ptr, a);
388be2cdc5eSEmilio G. Cota }
389be2cdc5eSEmilio G. Cota 
390be2cdc5eSEmilio G. Cota static void tcg_region_trees_init(void)
391be2cdc5eSEmilio G. Cota {
392be2cdc5eSEmilio G. Cota     size_t i;
393be2cdc5eSEmilio G. Cota 
394be2cdc5eSEmilio G. Cota     tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize);
395be2cdc5eSEmilio G. Cota     region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size);
396be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
397be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
398be2cdc5eSEmilio G. Cota 
399be2cdc5eSEmilio G. Cota         qemu_mutex_init(&rt->lock);
400be2cdc5eSEmilio G. Cota         rt->tree = g_tree_new(tb_tc_cmp);
401be2cdc5eSEmilio G. Cota     }
402be2cdc5eSEmilio G. Cota }
403be2cdc5eSEmilio G. Cota 
404be2cdc5eSEmilio G. Cota static struct tcg_region_tree *tc_ptr_to_region_tree(void *p)
405be2cdc5eSEmilio G. Cota {
406be2cdc5eSEmilio G. Cota     size_t region_idx;
407be2cdc5eSEmilio G. Cota 
408be2cdc5eSEmilio G. Cota     if (p < region.start_aligned) {
409be2cdc5eSEmilio G. Cota         region_idx = 0;
410be2cdc5eSEmilio G. Cota     } else {
411be2cdc5eSEmilio G. Cota         ptrdiff_t offset = p - region.start_aligned;
412be2cdc5eSEmilio G. Cota 
413be2cdc5eSEmilio G. Cota         if (offset > region.stride * (region.n - 1)) {
414be2cdc5eSEmilio G. Cota             region_idx = region.n - 1;
415be2cdc5eSEmilio G. Cota         } else {
416be2cdc5eSEmilio G. Cota             region_idx = offset / region.stride;
417be2cdc5eSEmilio G. Cota         }
418be2cdc5eSEmilio G. Cota     }
419be2cdc5eSEmilio G. Cota     return region_trees + region_idx * tree_size;
420be2cdc5eSEmilio G. Cota }
421be2cdc5eSEmilio G. Cota 
422be2cdc5eSEmilio G. Cota void tcg_tb_insert(TranslationBlock *tb)
423be2cdc5eSEmilio G. Cota {
424be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
425be2cdc5eSEmilio G. Cota 
426be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
427be2cdc5eSEmilio G. Cota     g_tree_insert(rt->tree, &tb->tc, tb);
428be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
429be2cdc5eSEmilio G. Cota }
430be2cdc5eSEmilio G. Cota 
431be2cdc5eSEmilio G. Cota void tcg_tb_remove(TranslationBlock *tb)
432be2cdc5eSEmilio G. Cota {
433be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
434be2cdc5eSEmilio G. Cota 
435be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
436be2cdc5eSEmilio G. Cota     g_tree_remove(rt->tree, &tb->tc);
437be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
438be2cdc5eSEmilio G. Cota }
439be2cdc5eSEmilio G. Cota 
440be2cdc5eSEmilio G. Cota /*
441be2cdc5eSEmilio G. Cota  * Find the TB 'tb' such that
442be2cdc5eSEmilio G. Cota  * tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size
443be2cdc5eSEmilio G. Cota  * Return NULL if not found.
444be2cdc5eSEmilio G. Cota  */
445be2cdc5eSEmilio G. Cota TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr)
446be2cdc5eSEmilio G. Cota {
447be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr);
448be2cdc5eSEmilio G. Cota     TranslationBlock *tb;
449be2cdc5eSEmilio G. Cota     struct tb_tc s = { .ptr = (void *)tc_ptr };
450be2cdc5eSEmilio G. Cota 
451be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
452be2cdc5eSEmilio G. Cota     tb = g_tree_lookup(rt->tree, &s);
453be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
454be2cdc5eSEmilio G. Cota     return tb;
455be2cdc5eSEmilio G. Cota }
456be2cdc5eSEmilio G. Cota 
457be2cdc5eSEmilio G. Cota static void tcg_region_tree_lock_all(void)
458be2cdc5eSEmilio G. Cota {
459be2cdc5eSEmilio G. Cota     size_t i;
460be2cdc5eSEmilio G. Cota 
461be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
462be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
463be2cdc5eSEmilio G. Cota 
464be2cdc5eSEmilio G. Cota         qemu_mutex_lock(&rt->lock);
465be2cdc5eSEmilio G. Cota     }
466be2cdc5eSEmilio G. Cota }
467be2cdc5eSEmilio G. Cota 
468be2cdc5eSEmilio G. Cota static void tcg_region_tree_unlock_all(void)
469be2cdc5eSEmilio G. Cota {
470be2cdc5eSEmilio G. Cota     size_t i;
471be2cdc5eSEmilio G. Cota 
472be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
473be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
474be2cdc5eSEmilio G. Cota 
475be2cdc5eSEmilio G. Cota         qemu_mutex_unlock(&rt->lock);
476be2cdc5eSEmilio G. Cota     }
477be2cdc5eSEmilio G. Cota }
478be2cdc5eSEmilio G. Cota 
479be2cdc5eSEmilio G. Cota void tcg_tb_foreach(GTraverseFunc func, gpointer user_data)
480be2cdc5eSEmilio G. Cota {
481be2cdc5eSEmilio G. Cota     size_t i;
482be2cdc5eSEmilio G. Cota 
483be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
484be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
485be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
486be2cdc5eSEmilio G. Cota 
487be2cdc5eSEmilio G. Cota         g_tree_foreach(rt->tree, func, user_data);
488be2cdc5eSEmilio G. Cota     }
489be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
490be2cdc5eSEmilio G. Cota }
491be2cdc5eSEmilio G. Cota 
492be2cdc5eSEmilio G. Cota size_t tcg_nb_tbs(void)
493be2cdc5eSEmilio G. Cota {
494be2cdc5eSEmilio G. Cota     size_t nb_tbs = 0;
495be2cdc5eSEmilio G. Cota     size_t i;
496be2cdc5eSEmilio G. Cota 
497be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
498be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
499be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
500be2cdc5eSEmilio G. Cota 
501be2cdc5eSEmilio G. Cota         nb_tbs += g_tree_nnodes(rt->tree);
502be2cdc5eSEmilio G. Cota     }
503be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
504be2cdc5eSEmilio G. Cota     return nb_tbs;
505be2cdc5eSEmilio G. Cota }
506be2cdc5eSEmilio G. Cota 
507938e897aSEmilio G. Cota static gboolean tcg_region_tree_traverse(gpointer k, gpointer v, gpointer data)
508938e897aSEmilio G. Cota {
509938e897aSEmilio G. Cota     TranslationBlock *tb = v;
510938e897aSEmilio G. Cota 
511938e897aSEmilio G. Cota     tb_destroy(tb);
512938e897aSEmilio G. Cota     return FALSE;
513938e897aSEmilio G. Cota }
514938e897aSEmilio G. Cota 
515be2cdc5eSEmilio G. Cota static void tcg_region_tree_reset_all(void)
516be2cdc5eSEmilio G. Cota {
517be2cdc5eSEmilio G. Cota     size_t i;
518be2cdc5eSEmilio G. Cota 
519be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
520be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
521be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
522be2cdc5eSEmilio G. Cota 
523938e897aSEmilio G. Cota         g_tree_foreach(rt->tree, tcg_region_tree_traverse, NULL);
524be2cdc5eSEmilio G. Cota         /* Increment the refcount first so that destroy acts as a reset */
525be2cdc5eSEmilio G. Cota         g_tree_ref(rt->tree);
526be2cdc5eSEmilio G. Cota         g_tree_destroy(rt->tree);
527be2cdc5eSEmilio G. Cota     }
528be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
529be2cdc5eSEmilio G. Cota }
530be2cdc5eSEmilio G. Cota 
531e8feb96fSEmilio G. Cota static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend)
532e8feb96fSEmilio G. Cota {
533e8feb96fSEmilio G. Cota     void *start, *end;
534e8feb96fSEmilio G. Cota 
535e8feb96fSEmilio G. Cota     start = region.start_aligned + curr_region * region.stride;
536e8feb96fSEmilio G. Cota     end = start + region.size;
537e8feb96fSEmilio G. Cota 
538e8feb96fSEmilio G. Cota     if (curr_region == 0) {
539e8feb96fSEmilio G. Cota         start = region.start;
540e8feb96fSEmilio G. Cota     }
541e8feb96fSEmilio G. Cota     if (curr_region == region.n - 1) {
542e8feb96fSEmilio G. Cota         end = region.end;
543e8feb96fSEmilio G. Cota     }
544e8feb96fSEmilio G. Cota 
545e8feb96fSEmilio G. Cota     *pstart = start;
546e8feb96fSEmilio G. Cota     *pend = end;
547e8feb96fSEmilio G. Cota }
548e8feb96fSEmilio G. Cota 
549e8feb96fSEmilio G. Cota static void tcg_region_assign(TCGContext *s, size_t curr_region)
550e8feb96fSEmilio G. Cota {
551e8feb96fSEmilio G. Cota     void *start, *end;
552e8feb96fSEmilio G. Cota 
553e8feb96fSEmilio G. Cota     tcg_region_bounds(curr_region, &start, &end);
554e8feb96fSEmilio G. Cota 
555e8feb96fSEmilio G. Cota     s->code_gen_buffer = start;
556e8feb96fSEmilio G. Cota     s->code_gen_ptr = start;
557e8feb96fSEmilio G. Cota     s->code_gen_buffer_size = end - start;
558e8feb96fSEmilio G. Cota     s->code_gen_highwater = end - TCG_HIGHWATER;
559e8feb96fSEmilio G. Cota }
560e8feb96fSEmilio G. Cota 
561e8feb96fSEmilio G. Cota static bool tcg_region_alloc__locked(TCGContext *s)
562e8feb96fSEmilio G. Cota {
563e8feb96fSEmilio G. Cota     if (region.current == region.n) {
564e8feb96fSEmilio G. Cota         return true;
565e8feb96fSEmilio G. Cota     }
566e8feb96fSEmilio G. Cota     tcg_region_assign(s, region.current);
567e8feb96fSEmilio G. Cota     region.current++;
568e8feb96fSEmilio G. Cota     return false;
569e8feb96fSEmilio G. Cota }
570e8feb96fSEmilio G. Cota 
571e8feb96fSEmilio G. Cota /*
572e8feb96fSEmilio G. Cota  * Request a new region once the one in use has filled up.
573e8feb96fSEmilio G. Cota  * Returns true on error.
574e8feb96fSEmilio G. Cota  */
575e8feb96fSEmilio G. Cota static bool tcg_region_alloc(TCGContext *s)
576e8feb96fSEmilio G. Cota {
577e8feb96fSEmilio G. Cota     bool err;
578e8feb96fSEmilio G. Cota     /* read the region size now; alloc__locked will overwrite it on success */
579e8feb96fSEmilio G. Cota     size_t size_full = s->code_gen_buffer_size;
580e8feb96fSEmilio G. Cota 
581e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
582e8feb96fSEmilio G. Cota     err = tcg_region_alloc__locked(s);
583e8feb96fSEmilio G. Cota     if (!err) {
584e8feb96fSEmilio G. Cota         region.agg_size_full += size_full - TCG_HIGHWATER;
585e8feb96fSEmilio G. Cota     }
586e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
587e8feb96fSEmilio G. Cota     return err;
588e8feb96fSEmilio G. Cota }
589e8feb96fSEmilio G. Cota 
590e8feb96fSEmilio G. Cota /*
591e8feb96fSEmilio G. Cota  * Perform a context's first region allocation.
592e8feb96fSEmilio G. Cota  * This function does _not_ increment region.agg_size_full.
593e8feb96fSEmilio G. Cota  */
594e8feb96fSEmilio G. Cota static inline bool tcg_region_initial_alloc__locked(TCGContext *s)
595e8feb96fSEmilio G. Cota {
596e8feb96fSEmilio G. Cota     return tcg_region_alloc__locked(s);
597e8feb96fSEmilio G. Cota }
598e8feb96fSEmilio G. Cota 
599e8feb96fSEmilio G. Cota /* Call from a safe-work context */
600e8feb96fSEmilio G. Cota void tcg_region_reset_all(void)
601e8feb96fSEmilio G. Cota {
602d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
603e8feb96fSEmilio G. Cota     unsigned int i;
604e8feb96fSEmilio G. Cota 
605e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
606e8feb96fSEmilio G. Cota     region.current = 0;
607e8feb96fSEmilio G. Cota     region.agg_size_full = 0;
608e8feb96fSEmilio G. Cota 
6093468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
610d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
6113468b59eSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(s);
612e8feb96fSEmilio G. Cota 
613e8feb96fSEmilio G. Cota         g_assert(!err);
614e8feb96fSEmilio G. Cota     }
615e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
616be2cdc5eSEmilio G. Cota 
617be2cdc5eSEmilio G. Cota     tcg_region_tree_reset_all();
618e8feb96fSEmilio G. Cota }
619e8feb96fSEmilio G. Cota 
6203468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
6213468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
6223468b59eSEmilio G. Cota {
6233468b59eSEmilio G. Cota     return 1;
6243468b59eSEmilio G. Cota }
6253468b59eSEmilio G. Cota #else
6263468b59eSEmilio G. Cota /*
6273468b59eSEmilio G. Cota  * It is likely that some vCPUs will translate more code than others, so we
6283468b59eSEmilio G. Cota  * first try to set more regions than max_cpus, with those regions being of
6293468b59eSEmilio G. Cota  * reasonable size. If that's not possible we make do by evenly dividing
6303468b59eSEmilio G. Cota  * the code_gen_buffer among the vCPUs.
6313468b59eSEmilio G. Cota  */
6323468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
6333468b59eSEmilio G. Cota {
6343468b59eSEmilio G. Cota     size_t i;
6353468b59eSEmilio G. Cota 
6363468b59eSEmilio G. Cota     /* Use a single region if all we have is one vCPU thread */
6375cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY)
6385cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
6395cc8767dSLike Xu     unsigned int max_cpus = ms->smp.max_cpus;
6405cc8767dSLike Xu #endif
6413468b59eSEmilio G. Cota     if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) {
6423468b59eSEmilio G. Cota         return 1;
6433468b59eSEmilio G. Cota     }
6443468b59eSEmilio G. Cota 
6453468b59eSEmilio G. Cota     /* Try to have more regions than max_cpus, with each region being >= 2 MB */
6463468b59eSEmilio G. Cota     for (i = 8; i > 0; i--) {
6473468b59eSEmilio G. Cota         size_t regions_per_thread = i;
6483468b59eSEmilio G. Cota         size_t region_size;
6493468b59eSEmilio G. Cota 
6503468b59eSEmilio G. Cota         region_size = tcg_init_ctx.code_gen_buffer_size;
6513468b59eSEmilio G. Cota         region_size /= max_cpus * regions_per_thread;
6523468b59eSEmilio G. Cota 
6533468b59eSEmilio G. Cota         if (region_size >= 2 * 1024u * 1024) {
6543468b59eSEmilio G. Cota             return max_cpus * regions_per_thread;
6553468b59eSEmilio G. Cota         }
6563468b59eSEmilio G. Cota     }
6573468b59eSEmilio G. Cota     /* If we can't, then just allocate one region per vCPU thread */
6583468b59eSEmilio G. Cota     return max_cpus;
6593468b59eSEmilio G. Cota }
6603468b59eSEmilio G. Cota #endif
6613468b59eSEmilio G. Cota 
662e8feb96fSEmilio G. Cota /*
663e8feb96fSEmilio G. Cota  * Initializes region partitioning.
664e8feb96fSEmilio G. Cota  *
665e8feb96fSEmilio G. Cota  * Called at init time from the parent thread (i.e. the one calling
666e8feb96fSEmilio G. Cota  * tcg_context_init), after the target's TCG globals have been set.
6673468b59eSEmilio G. Cota  *
6683468b59eSEmilio G. Cota  * Region partitioning works by splitting code_gen_buffer into separate regions,
6693468b59eSEmilio G. Cota  * and then assigning regions to TCG threads so that the threads can translate
6703468b59eSEmilio G. Cota  * code in parallel without synchronization.
6713468b59eSEmilio G. Cota  *
6723468b59eSEmilio G. Cota  * In softmmu the number of TCG threads is bounded by max_cpus, so we use at
6733468b59eSEmilio G. Cota  * least max_cpus regions in MTTCG. In !MTTCG we use a single region.
6743468b59eSEmilio G. Cota  * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...])
6753468b59eSEmilio G. Cota  * must have been parsed before calling this function, since it calls
6763468b59eSEmilio G. Cota  * qemu_tcg_mttcg_enabled().
6773468b59eSEmilio G. Cota  *
6783468b59eSEmilio G. Cota  * In user-mode we use a single region.  Having multiple regions in user-mode
6793468b59eSEmilio G. Cota  * is not supported, because the number of vCPU threads (recall that each thread
6803468b59eSEmilio G. Cota  * spawned by the guest corresponds to a vCPU thread) is only bounded by the
6813468b59eSEmilio G. Cota  * OS, and usually this number is huge (tens of thousands is not uncommon).
6823468b59eSEmilio G. Cota  * Thus, given this large bound on the number of vCPU threads and the fact
6833468b59eSEmilio G. Cota  * that code_gen_buffer is allocated at compile-time, we cannot guarantee
6843468b59eSEmilio G. Cota  * that the availability of at least one region per vCPU thread.
6853468b59eSEmilio G. Cota  *
6863468b59eSEmilio G. Cota  * However, this user-mode limitation is unlikely to be a significant problem
6873468b59eSEmilio G. Cota  * in practice. Multi-threaded guests share most if not all of their translated
6883468b59eSEmilio G. Cota  * code, which makes parallel code generation less appealing than in softmmu.
689e8feb96fSEmilio G. Cota  */
690e8feb96fSEmilio G. Cota void tcg_region_init(void)
691e8feb96fSEmilio G. Cota {
692e8feb96fSEmilio G. Cota     void *buf = tcg_init_ctx.code_gen_buffer;
693e8feb96fSEmilio G. Cota     void *aligned;
694e8feb96fSEmilio G. Cota     size_t size = tcg_init_ctx.code_gen_buffer_size;
695e8feb96fSEmilio G. Cota     size_t page_size = qemu_real_host_page_size;
696e8feb96fSEmilio G. Cota     size_t region_size;
697e8feb96fSEmilio G. Cota     size_t n_regions;
698e8feb96fSEmilio G. Cota     size_t i;
699e8feb96fSEmilio G. Cota 
7003468b59eSEmilio G. Cota     n_regions = tcg_n_regions();
701e8feb96fSEmilio G. Cota 
702e8feb96fSEmilio G. Cota     /* The first region will be 'aligned - buf' bytes larger than the others */
703e8feb96fSEmilio G. Cota     aligned = QEMU_ALIGN_PTR_UP(buf, page_size);
704e8feb96fSEmilio G. Cota     g_assert(aligned < tcg_init_ctx.code_gen_buffer + size);
705e8feb96fSEmilio G. Cota     /*
706e8feb96fSEmilio G. Cota      * Make region_size a multiple of page_size, using aligned as the start.
707e8feb96fSEmilio G. Cota      * As a result of this we might end up with a few extra pages at the end of
708e8feb96fSEmilio G. Cota      * the buffer; we will assign those to the last region.
709e8feb96fSEmilio G. Cota      */
710e8feb96fSEmilio G. Cota     region_size = (size - (aligned - buf)) / n_regions;
711e8feb96fSEmilio G. Cota     region_size = QEMU_ALIGN_DOWN(region_size, page_size);
712e8feb96fSEmilio G. Cota 
713e8feb96fSEmilio G. Cota     /* A region must have at least 2 pages; one code, one guard */
714e8feb96fSEmilio G. Cota     g_assert(region_size >= 2 * page_size);
715e8feb96fSEmilio G. Cota 
716e8feb96fSEmilio G. Cota     /* init the region struct */
717e8feb96fSEmilio G. Cota     qemu_mutex_init(&region.lock);
718e8feb96fSEmilio G. Cota     region.n = n_regions;
719e8feb96fSEmilio G. Cota     region.size = region_size - page_size;
720e8feb96fSEmilio G. Cota     region.stride = region_size;
721e8feb96fSEmilio G. Cota     region.start = buf;
722e8feb96fSEmilio G. Cota     region.start_aligned = aligned;
723e8feb96fSEmilio G. Cota     /* page-align the end, since its last page will be a guard page */
724e8feb96fSEmilio G. Cota     region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size);
725e8feb96fSEmilio G. Cota     /* account for that last guard page */
726e8feb96fSEmilio G. Cota     region.end -= page_size;
727e8feb96fSEmilio G. Cota 
728e8feb96fSEmilio G. Cota     /* set guard pages */
729e8feb96fSEmilio G. Cota     for (i = 0; i < region.n; i++) {
730e8feb96fSEmilio G. Cota         void *start, *end;
731e8feb96fSEmilio G. Cota         int rc;
732e8feb96fSEmilio G. Cota 
733e8feb96fSEmilio G. Cota         tcg_region_bounds(i, &start, &end);
734e8feb96fSEmilio G. Cota         rc = qemu_mprotect_none(end, page_size);
735e8feb96fSEmilio G. Cota         g_assert(!rc);
736e8feb96fSEmilio G. Cota     }
737e8feb96fSEmilio G. Cota 
738be2cdc5eSEmilio G. Cota     tcg_region_trees_init();
739be2cdc5eSEmilio G. Cota 
7403468b59eSEmilio G. Cota     /* In user-mode we support only one ctx, so do the initial allocation now */
7413468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
742e8feb96fSEmilio G. Cota     {
743e8feb96fSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(tcg_ctx);
744e8feb96fSEmilio G. Cota 
745e8feb96fSEmilio G. Cota         g_assert(!err);
746e8feb96fSEmilio G. Cota     }
7473468b59eSEmilio G. Cota #endif
748e8feb96fSEmilio G. Cota }
749e8feb96fSEmilio G. Cota 
75038b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s)
75138b47b19SEmilio G. Cota {
75238b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
75338b47b19SEmilio G. Cota     s->plugin_tb = g_new0(struct qemu_plugin_tb, 1);
75438b47b19SEmilio G. Cota     s->plugin_tb->insns =
75538b47b19SEmilio G. Cota         g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn);
75638b47b19SEmilio G. Cota #endif
75738b47b19SEmilio G. Cota }
75838b47b19SEmilio G. Cota 
759e8feb96fSEmilio G. Cota /*
7603468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
7613468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
7623468b59eSEmilio G. Cota  * before initiating translation.
7633468b59eSEmilio G. Cota  *
7643468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
7653468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
7663468b59eSEmilio G. Cota  *
7673468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
7683468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
7693468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
7703468b59eSEmilio G. Cota  *
7713468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
7723468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
7733468b59eSEmilio G. Cota  */
7743468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
7753468b59eSEmilio G. Cota void tcg_register_thread(void)
7763468b59eSEmilio G. Cota {
7773468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
7783468b59eSEmilio G. Cota }
7793468b59eSEmilio G. Cota #else
7803468b59eSEmilio G. Cota void tcg_register_thread(void)
7813468b59eSEmilio G. Cota {
7825cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
7833468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
7843468b59eSEmilio G. Cota     unsigned int i, n;
7853468b59eSEmilio G. Cota     bool err;
7863468b59eSEmilio G. Cota 
7873468b59eSEmilio G. Cota     *s = tcg_init_ctx;
7883468b59eSEmilio G. Cota 
7893468b59eSEmilio G. Cota     /* Relink mem_base.  */
7903468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
7913468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
7923468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
7933468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
7943468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
7953468b59eSEmilio G. Cota         }
7963468b59eSEmilio G. Cota     }
7973468b59eSEmilio G. Cota 
7983468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
799d73415a3SStefan Hajnoczi     n = qatomic_fetch_inc(&n_tcg_ctxs);
8005cc8767dSLike Xu     g_assert(n < ms->smp.max_cpus);
801d73415a3SStefan Hajnoczi     qatomic_set(&tcg_ctxs[n], s);
8023468b59eSEmilio G. Cota 
80338b47b19SEmilio G. Cota     if (n > 0) {
80438b47b19SEmilio G. Cota         alloc_tcg_plugin_context(s);
80538b47b19SEmilio G. Cota     }
80638b47b19SEmilio G. Cota 
8073468b59eSEmilio G. Cota     tcg_ctx = s;
8083468b59eSEmilio G. Cota     qemu_mutex_lock(&region.lock);
8093468b59eSEmilio G. Cota     err = tcg_region_initial_alloc__locked(tcg_ctx);
8103468b59eSEmilio G. Cota     g_assert(!err);
8113468b59eSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
8123468b59eSEmilio G. Cota }
8133468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
8143468b59eSEmilio G. Cota 
8153468b59eSEmilio G. Cota /*
816e8feb96fSEmilio G. Cota  * Returns the size (in bytes) of all translated code (i.e. from all regions)
817e8feb96fSEmilio G. Cota  * currently in the cache.
818e8feb96fSEmilio G. Cota  * See also: tcg_code_capacity()
819e8feb96fSEmilio G. Cota  * Do not confuse with tcg_current_code_size(); that one applies to a single
820e8feb96fSEmilio G. Cota  * TCG context.
821e8feb96fSEmilio G. Cota  */
822e8feb96fSEmilio G. Cota size_t tcg_code_size(void)
823e8feb96fSEmilio G. Cota {
824d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
825e8feb96fSEmilio G. Cota     unsigned int i;
826e8feb96fSEmilio G. Cota     size_t total;
827e8feb96fSEmilio G. Cota 
828e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
829e8feb96fSEmilio G. Cota     total = region.agg_size_full;
8303468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
831d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
832e8feb96fSEmilio G. Cota         size_t size;
833e8feb96fSEmilio G. Cota 
834d73415a3SStefan Hajnoczi         size = qatomic_read(&s->code_gen_ptr) - s->code_gen_buffer;
835e8feb96fSEmilio G. Cota         g_assert(size <= s->code_gen_buffer_size);
836e8feb96fSEmilio G. Cota         total += size;
837e8feb96fSEmilio G. Cota     }
838e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
839e8feb96fSEmilio G. Cota     return total;
840e8feb96fSEmilio G. Cota }
841e8feb96fSEmilio G. Cota 
842e8feb96fSEmilio G. Cota /*
843e8feb96fSEmilio G. Cota  * Returns the code capacity (in bytes) of the entire cache, i.e. including all
844e8feb96fSEmilio G. Cota  * regions.
845e8feb96fSEmilio G. Cota  * See also: tcg_code_size()
846e8feb96fSEmilio G. Cota  */
847e8feb96fSEmilio G. Cota size_t tcg_code_capacity(void)
848e8feb96fSEmilio G. Cota {
849e8feb96fSEmilio G. Cota     size_t guard_size, capacity;
850e8feb96fSEmilio G. Cota 
851e8feb96fSEmilio G. Cota     /* no need for synchronization; these variables are set at init time */
852e8feb96fSEmilio G. Cota     guard_size = region.stride - region.size;
853e8feb96fSEmilio G. Cota     capacity = region.end + guard_size - region.start;
854e8feb96fSEmilio G. Cota     capacity -= region.n * (guard_size + TCG_HIGHWATER);
855e8feb96fSEmilio G. Cota     return capacity;
856e8feb96fSEmilio G. Cota }
857e8feb96fSEmilio G. Cota 
858128ed227SEmilio G. Cota size_t tcg_tb_phys_invalidate_count(void)
859128ed227SEmilio G. Cota {
860d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
861128ed227SEmilio G. Cota     unsigned int i;
862128ed227SEmilio G. Cota     size_t total = 0;
863128ed227SEmilio G. Cota 
864128ed227SEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
865d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
866128ed227SEmilio G. Cota 
867d73415a3SStefan Hajnoczi         total += qatomic_read(&s->tb_phys_invalidate_count);
868128ed227SEmilio G. Cota     }
869128ed227SEmilio G. Cota     return total;
870128ed227SEmilio G. Cota }
871128ed227SEmilio G. Cota 
872c896fe29Sbellard /* pool based memory allocation */
873c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
874c896fe29Sbellard {
875c896fe29Sbellard     TCGPool *p;
876c896fe29Sbellard     int pool_size;
877c896fe29Sbellard 
878c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
879c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
8807267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
881c896fe29Sbellard         p->size = size;
8824055299eSKirill Batuzov         p->next = s->pool_first_large;
8834055299eSKirill Batuzov         s->pool_first_large = p;
8844055299eSKirill Batuzov         return p->data;
885c896fe29Sbellard     } else {
886c896fe29Sbellard         p = s->pool_current;
887c896fe29Sbellard         if (!p) {
888c896fe29Sbellard             p = s->pool_first;
889c896fe29Sbellard             if (!p)
890c896fe29Sbellard                 goto new_pool;
891c896fe29Sbellard         } else {
892c896fe29Sbellard             if (!p->next) {
893c896fe29Sbellard             new_pool:
894c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
8957267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
896c896fe29Sbellard                 p->size = pool_size;
897c896fe29Sbellard                 p->next = NULL;
898c896fe29Sbellard                 if (s->pool_current)
899c896fe29Sbellard                     s->pool_current->next = p;
900c896fe29Sbellard                 else
901c896fe29Sbellard                     s->pool_first = p;
902c896fe29Sbellard             } else {
903c896fe29Sbellard                 p = p->next;
904c896fe29Sbellard             }
905c896fe29Sbellard         }
906c896fe29Sbellard     }
907c896fe29Sbellard     s->pool_current = p;
908c896fe29Sbellard     s->pool_cur = p->data + size;
909c896fe29Sbellard     s->pool_end = p->data + p->size;
910c896fe29Sbellard     return p->data;
911c896fe29Sbellard }
912c896fe29Sbellard 
913c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
914c896fe29Sbellard {
9154055299eSKirill Batuzov     TCGPool *p, *t;
9164055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
9174055299eSKirill Batuzov         t = p->next;
9184055299eSKirill Batuzov         g_free(p);
9194055299eSKirill Batuzov     }
9204055299eSKirill Batuzov     s->pool_first_large = NULL;
921c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
922c896fe29Sbellard     s->pool_current = NULL;
923c896fe29Sbellard }
924c896fe29Sbellard 
925100b5e01SRichard Henderson typedef struct TCGHelperInfo {
926100b5e01SRichard Henderson     void *func;
927100b5e01SRichard Henderson     const char *name;
928afb49896SRichard Henderson     unsigned flags;
929afb49896SRichard Henderson     unsigned sizemask;
930100b5e01SRichard Henderson } TCGHelperInfo;
931100b5e01SRichard Henderson 
9322ef6175aSRichard Henderson #include "exec/helper-proto.h"
9332ef6175aSRichard Henderson 
934100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = {
9352ef6175aSRichard Henderson #include "exec/helper-tcg.h"
936100b5e01SRichard Henderson };
937619205fdSEmilio G. Cota static GHashTable *helper_table;
938100b5e01SRichard Henderson 
93991478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
940f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
9411c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
9421c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
94391478cefSRichard Henderson 
944c896fe29Sbellard void tcg_context_init(TCGContext *s)
945c896fe29Sbellard {
946100b5e01SRichard Henderson     int op, total_args, n, i;
947c896fe29Sbellard     TCGOpDef *def;
948c896fe29Sbellard     TCGArgConstraint *args_ct;
9491c2adb95SRichard Henderson     TCGTemp *ts;
950c896fe29Sbellard 
951c896fe29Sbellard     memset(s, 0, sizeof(*s));
952c896fe29Sbellard     s->nb_globals = 0;
953c896fe29Sbellard 
954c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
955c896fe29Sbellard        space */
956c896fe29Sbellard     total_args = 0;
957c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
958c896fe29Sbellard         def = &tcg_op_defs[op];
959c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
960c896fe29Sbellard         total_args += n;
961c896fe29Sbellard     }
962c896fe29Sbellard 
963bc2b17e6SRichard Henderson     args_ct = g_new0(TCGArgConstraint, total_args);
964c896fe29Sbellard 
965c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
966c896fe29Sbellard         def = &tcg_op_defs[op];
967c896fe29Sbellard         def->args_ct = args_ct;
968c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
969c896fe29Sbellard         args_ct += n;
970c896fe29Sbellard     }
971c896fe29Sbellard 
9725cd8f621SRichard Henderson     /* Register helpers.  */
97384fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
974619205fdSEmilio G. Cota     helper_table = g_hash_table_new(NULL, NULL);
97584fd9dd3SRichard Henderson 
976100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
97784fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
97872866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
979100b5e01SRichard Henderson     }
9805cd8f621SRichard Henderson 
981c896fe29Sbellard     tcg_target_init(s);
982f69d277eSRichard Henderson     process_op_defs(s);
98391478cefSRichard Henderson 
98491478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
98591478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
98691478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
98791478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
98891478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
98991478cefSRichard Henderson             break;
99091478cefSRichard Henderson         }
99191478cefSRichard Henderson     }
99291478cefSRichard Henderson     for (i = 0; i < n; ++i) {
99391478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
99491478cefSRichard Henderson     }
99591478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
99691478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
99791478cefSRichard Henderson     }
998b1311c4aSEmilio G. Cota 
99938b47b19SEmilio G. Cota     alloc_tcg_plugin_context(s);
100038b47b19SEmilio G. Cota 
1001b1311c4aSEmilio G. Cota     tcg_ctx = s;
10023468b59eSEmilio G. Cota     /*
10033468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
10043468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
10053468b59eSEmilio G. Cota      * reasoning behind this.
10063468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
10073468b59eSEmilio G. Cota      */
10083468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
1009df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
1010df2cce29SEmilio G. Cota     n_tcg_ctxs = 1;
10113468b59eSEmilio G. Cota #else
10125cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
10135cc8767dSLike Xu     unsigned int max_cpus = ms->smp.max_cpus;
10143468b59eSEmilio G. Cota     tcg_ctxs = g_new(TCGContext *, max_cpus);
10153468b59eSEmilio G. Cota #endif
10161c2adb95SRichard Henderson 
10171c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
10181c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
10191c2adb95SRichard Henderson     cpu_env = temp_tcgv_ptr(ts);
10209002ec79SRichard Henderson }
1021b03cce8eSbellard 
10226e3b2bfdSEmilio G. Cota /*
10236e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
10246e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
10256e3b2bfdSEmilio G. Cota  */
10266e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
10276e3b2bfdSEmilio G. Cota {
10286e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
10296e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
10306e3b2bfdSEmilio G. Cota     void *next;
10316e3b2bfdSEmilio G. Cota 
1032e8feb96fSEmilio G. Cota  retry:
10336e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
10346e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
10356e3b2bfdSEmilio G. Cota 
10366e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
1037e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
10386e3b2bfdSEmilio G. Cota             return NULL;
10396e3b2bfdSEmilio G. Cota         }
1040e8feb96fSEmilio G. Cota         goto retry;
1041e8feb96fSEmilio G. Cota     }
1042d73415a3SStefan Hajnoczi     qatomic_set(&s->code_gen_ptr, next);
104357a26946SRichard Henderson     s->data_gen_ptr = NULL;
10446e3b2bfdSEmilio G. Cota     return tb;
10456e3b2bfdSEmilio G. Cota }
10466e3b2bfdSEmilio G. Cota 
10479002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
10489002ec79SRichard Henderson {
10498163b749SRichard Henderson     size_t prologue_size, total_size;
10508163b749SRichard Henderson     void *buf0, *buf1;
10518163b749SRichard Henderson 
10528163b749SRichard Henderson     /* Put the prologue at the beginning of code_gen_buffer.  */
10538163b749SRichard Henderson     buf0 = s->code_gen_buffer;
10545b38ee31SRichard Henderson     total_size = s->code_gen_buffer_size;
10558163b749SRichard Henderson     s->code_ptr = buf0;
10568163b749SRichard Henderson     s->code_buf = buf0;
10575b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
10588163b749SRichard Henderson     s->code_gen_prologue = buf0;
10598163b749SRichard Henderson 
10605b38ee31SRichard Henderson     /* Compute a high-water mark, at which we voluntarily flush the buffer
10615b38ee31SRichard Henderson        and start over.  The size here is arbitrary, significantly larger
10625b38ee31SRichard Henderson        than we expect the code generation for any one opcode to require.  */
10635b38ee31SRichard Henderson     s->code_gen_highwater = s->code_gen_buffer + (total_size - TCG_HIGHWATER);
10645b38ee31SRichard Henderson 
10655b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
10665b38ee31SRichard Henderson     s->pool_labels = NULL;
10675b38ee31SRichard Henderson #endif
10685b38ee31SRichard Henderson 
10698163b749SRichard Henderson     /* Generate the prologue.  */
1070b03cce8eSbellard     tcg_target_qemu_prologue(s);
10715b38ee31SRichard Henderson 
10725b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
10735b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
10745b38ee31SRichard Henderson     {
10751768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
10761768987bSRichard Henderson         tcg_debug_assert(result == 0);
10775b38ee31SRichard Henderson     }
10785b38ee31SRichard Henderson #endif
10795b38ee31SRichard Henderson 
10808163b749SRichard Henderson     buf1 = s->code_ptr;
10818163b749SRichard Henderson     flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1);
10828163b749SRichard Henderson 
10838163b749SRichard Henderson     /* Deduct the prologue from the buffer.  */
10848163b749SRichard Henderson     prologue_size = tcg_current_code_size(s);
10858163b749SRichard Henderson     s->code_gen_ptr = buf1;
10868163b749SRichard Henderson     s->code_gen_buffer = buf1;
10878163b749SRichard Henderson     s->code_buf = buf1;
10885b38ee31SRichard Henderson     total_size -= prologue_size;
10898163b749SRichard Henderson     s->code_gen_buffer_size = total_size;
10908163b749SRichard Henderson 
10918163b749SRichard Henderson     tcg_register_jit(s->code_gen_buffer, total_size);
1092d6b64b2bSRichard Henderson 
1093d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
1094d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
1095fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
10968163b749SRichard Henderson         qemu_log("PROLOGUE: [size=%zu]\n", prologue_size);
10975b38ee31SRichard Henderson         if (s->data_gen_ptr) {
10985b38ee31SRichard Henderson             size_t code_size = s->data_gen_ptr - buf0;
10995b38ee31SRichard Henderson             size_t data_size = prologue_size - code_size;
11005b38ee31SRichard Henderson             size_t i;
11015b38ee31SRichard Henderson 
11024c389f6eSRichard Henderson             log_disas(buf0, code_size);
11035b38ee31SRichard Henderson 
11045b38ee31SRichard Henderson             for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
11055b38ee31SRichard Henderson                 if (sizeof(tcg_target_ulong) == 8) {
11065b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
11075b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
11085b38ee31SRichard Henderson                              *(uint64_t *)(s->data_gen_ptr + i));
11095b38ee31SRichard Henderson                 } else {
11105b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .long  0x%08x\n",
11115b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
11125b38ee31SRichard Henderson                              *(uint32_t *)(s->data_gen_ptr + i));
11135b38ee31SRichard Henderson                 }
11145b38ee31SRichard Henderson             }
11155b38ee31SRichard Henderson         } else {
11164c389f6eSRichard Henderson             log_disas(buf0, prologue_size);
11175b38ee31SRichard Henderson         }
1118d6b64b2bSRichard Henderson         qemu_log("\n");
1119d6b64b2bSRichard Henderson         qemu_log_flush();
1120fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
1121d6b64b2bSRichard Henderson     }
1122d6b64b2bSRichard Henderson #endif
1123cedbcb01SEmilio G. Cota 
1124cedbcb01SEmilio G. Cota     /* Assert that goto_ptr is implemented completely.  */
1125cedbcb01SEmilio G. Cota     if (TCG_TARGET_HAS_goto_ptr) {
1126cedbcb01SEmilio G. Cota         tcg_debug_assert(s->code_gen_epilogue != NULL);
1127cedbcb01SEmilio G. Cota     }
1128c896fe29Sbellard }
1129c896fe29Sbellard 
1130c896fe29Sbellard void tcg_func_start(TCGContext *s)
1131c896fe29Sbellard {
1132c896fe29Sbellard     tcg_pool_reset(s);
1133c896fe29Sbellard     s->nb_temps = s->nb_globals;
11340ec9eabcSRichard Henderson 
11350ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
11360ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
11370ec9eabcSRichard Henderson 
1138abebf925SRichard Henderson     s->nb_ops = 0;
1139c896fe29Sbellard     s->nb_labels = 0;
1140c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1141c896fe29Sbellard 
11420a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
11430a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
11440a209d4bSRichard Henderson #endif
11450a209d4bSRichard Henderson 
114615fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
114715fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
1148bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
1149c896fe29Sbellard }
1150c896fe29Sbellard 
11517ca4b752SRichard Henderson static inline TCGTemp *tcg_temp_alloc(TCGContext *s)
11527ca4b752SRichard Henderson {
11537ca4b752SRichard Henderson     int n = s->nb_temps++;
11547ca4b752SRichard Henderson     tcg_debug_assert(n < TCG_MAX_TEMPS);
11557ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
11567ca4b752SRichard Henderson }
11577ca4b752SRichard Henderson 
11587ca4b752SRichard Henderson static inline TCGTemp *tcg_global_alloc(TCGContext *s)
11597ca4b752SRichard Henderson {
1160fa477d25SRichard Henderson     TCGTemp *ts;
1161fa477d25SRichard Henderson 
11627ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
11637ca4b752SRichard Henderson     s->nb_globals++;
1164fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1165fa477d25SRichard Henderson     ts->temp_global = 1;
1166fa477d25SRichard Henderson 
1167fa477d25SRichard Henderson     return ts;
1168c896fe29Sbellard }
1169c896fe29Sbellard 
1170085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1171b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1172c896fe29Sbellard {
1173c896fe29Sbellard     TCGTemp *ts;
1174c896fe29Sbellard 
1175b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
1176c896fe29Sbellard         tcg_abort();
1177b3a62939SRichard Henderson     }
11787ca4b752SRichard Henderson 
11797ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1180c896fe29Sbellard     ts->base_type = type;
1181c896fe29Sbellard     ts->type = type;
1182c896fe29Sbellard     ts->fixed_reg = 1;
1183c896fe29Sbellard     ts->reg = reg;
1184c896fe29Sbellard     ts->name = name;
1185c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
11867ca4b752SRichard Henderson 
1187085272b3SRichard Henderson     return ts;
1188a7812ae4Spbrook }
1189a7812ae4Spbrook 
1190b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1191a7812ae4Spbrook {
1192b3a62939SRichard Henderson     s->frame_start = start;
1193b3a62939SRichard Henderson     s->frame_end = start + size;
1194085272b3SRichard Henderson     s->frame_temp
1195085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1196b3a62939SRichard Henderson }
1197a7812ae4Spbrook 
1198085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
1199e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
1200c896fe29Sbellard {
1201b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1202dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
12037ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1204b3915dbbSRichard Henderson     int indirect_reg = 0, bigendian = 0;
12057ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
12067ca4b752SRichard Henderson     bigendian = 1;
12077ca4b752SRichard Henderson #endif
1208c896fe29Sbellard 
1209b3915dbbSRichard Henderson     if (!base_ts->fixed_reg) {
12105a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
12115a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1212b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
12135a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
12145a18407fSRichard Henderson                             ? 2 : 1);
12155a18407fSRichard Henderson         indirect_reg = 1;
1216b3915dbbSRichard Henderson     }
1217b3915dbbSRichard Henderson 
12187ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
12197ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1220c896fe29Sbellard         char buf[64];
12217ca4b752SRichard Henderson 
12227ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1223c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1224b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1225c896fe29Sbellard         ts->mem_allocated = 1;
1226b3a62939SRichard Henderson         ts->mem_base = base_ts;
12277ca4b752SRichard Henderson         ts->mem_offset = offset + bigendian * 4;
1228c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1229c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1230c896fe29Sbellard         ts->name = strdup(buf);
1231c896fe29Sbellard 
12327ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
12337ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
12347ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1235b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
12367ca4b752SRichard Henderson         ts2->mem_allocated = 1;
12377ca4b752SRichard Henderson         ts2->mem_base = base_ts;
12387ca4b752SRichard Henderson         ts2->mem_offset = offset + (1 - bigendian) * 4;
1239c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1240c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1241120c1084SRichard Henderson         ts2->name = strdup(buf);
12427ca4b752SRichard Henderson     } else {
1243c896fe29Sbellard         ts->base_type = type;
1244c896fe29Sbellard         ts->type = type;
1245b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1246c896fe29Sbellard         ts->mem_allocated = 1;
1247b3a62939SRichard Henderson         ts->mem_base = base_ts;
1248c896fe29Sbellard         ts->mem_offset = offset;
1249c896fe29Sbellard         ts->name = name;
1250c896fe29Sbellard     }
1251085272b3SRichard Henderson     return ts;
1252c896fe29Sbellard }
1253c896fe29Sbellard 
12545bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local)
1255c896fe29Sbellard {
1256b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1257c896fe29Sbellard     TCGTemp *ts;
1258641d5fbeSbellard     int idx, k;
1259c896fe29Sbellard 
12600ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
12610ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
12620ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
12630ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
12640ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
12650ec9eabcSRichard Henderson 
1266e8996ee0Sbellard         ts = &s->temps[idx];
1267e8996ee0Sbellard         ts->temp_allocated = 1;
12687ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
12697ca4b752SRichard Henderson         tcg_debug_assert(ts->temp_local == temp_local);
1270e8996ee0Sbellard     } else {
12717ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
12727ca4b752SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
12737ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
12747ca4b752SRichard Henderson 
1275c896fe29Sbellard             ts->base_type = type;
1276c896fe29Sbellard             ts->type = TCG_TYPE_I32;
1277e8996ee0Sbellard             ts->temp_allocated = 1;
1278641d5fbeSbellard             ts->temp_local = temp_local;
12797ca4b752SRichard Henderson 
12807ca4b752SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
12817ca4b752SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
12827ca4b752SRichard Henderson             ts2->type = TCG_TYPE_I32;
12837ca4b752SRichard Henderson             ts2->temp_allocated = 1;
12847ca4b752SRichard Henderson             ts2->temp_local = temp_local;
12857ca4b752SRichard Henderson         } else {
1286c896fe29Sbellard             ts->base_type = type;
1287c896fe29Sbellard             ts->type = type;
1288e8996ee0Sbellard             ts->temp_allocated = 1;
1289641d5fbeSbellard             ts->temp_local = temp_local;
1290c896fe29Sbellard         }
1291e8996ee0Sbellard     }
129227bfd83cSPeter Maydell 
129327bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
129427bfd83cSPeter Maydell     s->temps_in_use++;
129527bfd83cSPeter Maydell #endif
1296085272b3SRichard Henderson     return ts;
1297c896fe29Sbellard }
1298c896fe29Sbellard 
1299d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1300d2fd745fSRichard Henderson {
1301d2fd745fSRichard Henderson     TCGTemp *t;
1302d2fd745fSRichard Henderson 
1303d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1304d2fd745fSRichard Henderson     switch (type) {
1305d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1306d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1307d2fd745fSRichard Henderson         break;
1308d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1309d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1310d2fd745fSRichard Henderson         break;
1311d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1312d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1313d2fd745fSRichard Henderson         break;
1314d2fd745fSRichard Henderson     default:
1315d2fd745fSRichard Henderson         g_assert_not_reached();
1316d2fd745fSRichard Henderson     }
1317d2fd745fSRichard Henderson #endif
1318d2fd745fSRichard Henderson 
1319d2fd745fSRichard Henderson     t = tcg_temp_new_internal(type, 0);
1320d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1321d2fd745fSRichard Henderson }
1322d2fd745fSRichard Henderson 
1323d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1324d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1325d2fd745fSRichard Henderson {
1326d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1327d2fd745fSRichard Henderson 
1328d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1329d2fd745fSRichard Henderson 
1330d2fd745fSRichard Henderson     t = tcg_temp_new_internal(t->base_type, 0);
1331d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1332d2fd745fSRichard Henderson }
1333d2fd745fSRichard Henderson 
13345bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1335c896fe29Sbellard {
1336b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1337085272b3SRichard Henderson     int k, idx;
1338c896fe29Sbellard 
133927bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
134027bfd83cSPeter Maydell     s->temps_in_use--;
134127bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
134227bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
134327bfd83cSPeter Maydell     }
134427bfd83cSPeter Maydell #endif
134527bfd83cSPeter Maydell 
1346085272b3SRichard Henderson     tcg_debug_assert(ts->temp_global == 0);
1347eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
1348e8996ee0Sbellard     ts->temp_allocated = 0;
13490ec9eabcSRichard Henderson 
1350085272b3SRichard Henderson     idx = temp_idx(ts);
135118d13fa2SAlexander Graf     k = ts->base_type + (ts->temp_local ? TCG_TYPE_COUNT : 0);
13520ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
1353e8996ee0Sbellard }
1354e8996ee0Sbellard 
1355a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
1356a7812ae4Spbrook {
1357a7812ae4Spbrook     TCGv_i32 t0;
1358a7812ae4Spbrook     t0 = tcg_temp_new_i32();
1359e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
1360e8996ee0Sbellard     return t0;
1361c896fe29Sbellard }
1362c896fe29Sbellard 
1363a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
1364c896fe29Sbellard {
1365a7812ae4Spbrook     TCGv_i64 t0;
1366a7812ae4Spbrook     t0 = tcg_temp_new_i64();
1367e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
1368e8996ee0Sbellard     return t0;
1369c896fe29Sbellard }
1370c896fe29Sbellard 
1371a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
1372bdffd4a9Saurel32 {
1373a7812ae4Spbrook     TCGv_i32 t0;
1374a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
1375bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
1376bdffd4a9Saurel32     return t0;
1377bdffd4a9Saurel32 }
1378bdffd4a9Saurel32 
1379a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
1380bdffd4a9Saurel32 {
1381a7812ae4Spbrook     TCGv_i64 t0;
1382a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
1383bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
1384bdffd4a9Saurel32     return t0;
1385bdffd4a9Saurel32 }
1386bdffd4a9Saurel32 
138727bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
138827bfd83cSPeter Maydell void tcg_clear_temp_count(void)
138927bfd83cSPeter Maydell {
1390b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
139127bfd83cSPeter Maydell     s->temps_in_use = 0;
139227bfd83cSPeter Maydell }
139327bfd83cSPeter Maydell 
139427bfd83cSPeter Maydell int tcg_check_temp_count(void)
139527bfd83cSPeter Maydell {
1396b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
139727bfd83cSPeter Maydell     if (s->temps_in_use) {
139827bfd83cSPeter Maydell         /* Clear the count so that we don't give another
139927bfd83cSPeter Maydell          * warning immediately next time around.
140027bfd83cSPeter Maydell          */
140127bfd83cSPeter Maydell         s->temps_in_use = 0;
140227bfd83cSPeter Maydell         return 1;
140327bfd83cSPeter Maydell     }
140427bfd83cSPeter Maydell     return 0;
140527bfd83cSPeter Maydell }
140627bfd83cSPeter Maydell #endif
140727bfd83cSPeter Maydell 
1408be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1409be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1410be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1411be0f34b5SRichard Henderson {
1412d2fd745fSRichard Henderson     const bool have_vec
1413d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1414d2fd745fSRichard Henderson 
1415be0f34b5SRichard Henderson     switch (op) {
1416be0f34b5SRichard Henderson     case INDEX_op_discard:
1417be0f34b5SRichard Henderson     case INDEX_op_set_label:
1418be0f34b5SRichard Henderson     case INDEX_op_call:
1419be0f34b5SRichard Henderson     case INDEX_op_br:
1420be0f34b5SRichard Henderson     case INDEX_op_mb:
1421be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1422be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1423be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1424be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i32:
1425be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i32:
1426be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i64:
1427be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i64:
1428be0f34b5SRichard Henderson         return true;
1429be0f34b5SRichard Henderson 
1430*07ce0b05SRichard Henderson     case INDEX_op_qemu_st8_i32:
1431*07ce0b05SRichard Henderson         return TCG_TARGET_HAS_qemu_st8_i32;
1432*07ce0b05SRichard Henderson 
1433be0f34b5SRichard Henderson     case INDEX_op_goto_ptr:
1434be0f34b5SRichard Henderson         return TCG_TARGET_HAS_goto_ptr;
1435be0f34b5SRichard Henderson 
1436be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1437be0f34b5SRichard Henderson     case INDEX_op_movi_i32:
1438be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1439be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1440be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1441be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1442be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1443be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1444be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1445be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1446be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1447be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1448be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1449be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1450be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1451be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1452be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1453be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1454be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1455be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1456be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1457be0f34b5SRichard Henderson         return true;
1458be0f34b5SRichard Henderson 
1459be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1460be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1461be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1462be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1463be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1464be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1465be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1466be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1467be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1468be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1469be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1470be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1471be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1472be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1473be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1474be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1475be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1476be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1477be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1478be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1479fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
1480fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
1481be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1482be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1483be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1484be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1485be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1486be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1487be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1488be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1489be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1490be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1491be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1492be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1493be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1494be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1495be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1496be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1497be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1498be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1499be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1500be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1501be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1502be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1503be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1504be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1505be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1506be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1507be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1508be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1509be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1510be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1511be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1512be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1513be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1514be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1515be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1516be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1517be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1518be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1519be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1520be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1521be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1522be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1523be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1524be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1525be0f34b5SRichard Henderson 
1526be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1527be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1528be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1529be0f34b5SRichard Henderson 
1530be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1531be0f34b5SRichard Henderson     case INDEX_op_movi_i64:
1532be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1533be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1534be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1535be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1536be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1537be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1538be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1539be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1540be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1541be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1542be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1543be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1544be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1545be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1546be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1547be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1548be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1549be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1550be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1551be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1552be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1553be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1554be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1555be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1556be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1557be0f34b5SRichard Henderson 
1558be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1559be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1560be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1561be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1562be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1563be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1564be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1565be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1566be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1567be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
1568be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
1569be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
1570be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
1571be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
1572be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
1573be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
1574be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
1575be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
1576be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
1577be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
1578fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
1579fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
1580be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
1581be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrl_i64_i32;
1582be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
1583be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrh_i64_i32;
1584be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
1585be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
1586be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
1587be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
1588be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
1589be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
1590be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
1591be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
1592be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
1593be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
1594be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
1595be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
1596be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
1597be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
1598be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
1599be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
1600be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
1601be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
1602be0f34b5SRichard Henderson     case INDEX_op_not_i64:
1603be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
1604be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
1605be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
1606be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
1607be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
1608be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
1609be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
1610be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
1611be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
1612be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
1613be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
1614be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
1615be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
1616be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
1617be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
1618be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
1619be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
1620be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
1621be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
1622be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
1623be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
1624be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
1625be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
1626be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
1627be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
1628be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
1629be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
1630be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
1631be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
1632be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
1633be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
1634be0f34b5SRichard Henderson 
1635d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
1636d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
1637d2fd745fSRichard Henderson     case INDEX_op_dupi_vec:
163837ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
1639d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
1640d2fd745fSRichard Henderson     case INDEX_op_st_vec:
1641d2fd745fSRichard Henderson     case INDEX_op_add_vec:
1642d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
1643d2fd745fSRichard Henderson     case INDEX_op_and_vec:
1644d2fd745fSRichard Henderson     case INDEX_op_or_vec:
1645d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
1646212be173SRichard Henderson     case INDEX_op_cmp_vec:
1647d2fd745fSRichard Henderson         return have_vec;
1648d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
1649d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
1650d2fd745fSRichard Henderson     case INDEX_op_not_vec:
1651d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
1652d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
1653d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
1654bcefc902SRichard Henderson     case INDEX_op_abs_vec:
1655bcefc902SRichard Henderson         return have_vec && TCG_TARGET_HAS_abs_vec;
1656d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
1657d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
1658d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
1659d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
16603774030aSRichard Henderson     case INDEX_op_mul_vec:
16613774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
1662d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
1663d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
1664d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
1665d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
1666d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
1667d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
1668d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
1669d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
1670d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
1671d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
1672d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
1673d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
1674b0f7e744SRichard Henderson     case INDEX_op_rotli_vec:
1675b0f7e744SRichard Henderson         return have_vec && TCG_TARGET_HAS_roti_vec;
167623850a74SRichard Henderson     case INDEX_op_rotls_vec:
167723850a74SRichard Henderson         return have_vec && TCG_TARGET_HAS_rots_vec;
16785d0ceda9SRichard Henderson     case INDEX_op_rotlv_vec:
16795d0ceda9SRichard Henderson     case INDEX_op_rotrv_vec:
16805d0ceda9SRichard Henderson         return have_vec && TCG_TARGET_HAS_rotv_vec;
16818afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
16828afaf050SRichard Henderson     case INDEX_op_usadd_vec:
16838afaf050SRichard Henderson     case INDEX_op_sssub_vec:
16848afaf050SRichard Henderson     case INDEX_op_ussub_vec:
16858afaf050SRichard Henderson         return have_vec && TCG_TARGET_HAS_sat_vec;
1686dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
1687dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
1688dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
1689dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
1690dd0a0fcdSRichard Henderson         return have_vec && TCG_TARGET_HAS_minmax_vec;
169138dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
169238dc1294SRichard Henderson         return have_vec && TCG_TARGET_HAS_bitsel_vec;
1693f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
1694f75da298SRichard Henderson         return have_vec && TCG_TARGET_HAS_cmpsel_vec;
1695d2fd745fSRichard Henderson 
1696db432672SRichard Henderson     default:
1697db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
1698db432672SRichard Henderson         return true;
1699be0f34b5SRichard Henderson     }
1700be0f34b5SRichard Henderson }
1701be0f34b5SRichard Henderson 
170239cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment
170339cf05d3Sbellard    and endian swap. Maybe it would be better to do the alignment
170439cf05d3Sbellard    and endian swap in tcg_reg_alloc_call(). */
1705ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
1706c896fe29Sbellard {
170775e8b9b7SRichard Henderson     int i, real_args, nb_rets, pi;
1708bbb8a1b4SRichard Henderson     unsigned sizemask, flags;
1709afb49896SRichard Henderson     TCGHelperInfo *info;
171075e8b9b7SRichard Henderson     TCGOp *op;
1711afb49896SRichard Henderson 
1712619205fdSEmilio G. Cota     info = g_hash_table_lookup(helper_table, (gpointer)func);
1713bbb8a1b4SRichard Henderson     flags = info->flags;
1714bbb8a1b4SRichard Henderson     sizemask = info->sizemask;
17152bece2c8SRichard Henderson 
171638b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
171738b47b19SEmilio G. Cota     /* detect non-plugin helpers */
171838b47b19SEmilio G. Cota     if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) {
171938b47b19SEmilio G. Cota         tcg_ctx->plugin_insn->calls_helpers = true;
172038b47b19SEmilio G. Cota     }
172138b47b19SEmilio G. Cota #endif
172238b47b19SEmilio G. Cota 
172334b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
172434b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
172534b1a49cSRichard Henderson     /* We have 64-bit values in one register, but need to pass as two
172634b1a49cSRichard Henderson        separate parameters.  Split them.  */
172734b1a49cSRichard Henderson     int orig_sizemask = sizemask;
172834b1a49cSRichard Henderson     int orig_nargs = nargs;
172934b1a49cSRichard Henderson     TCGv_i64 retl, reth;
1730ae8b75dcSRichard Henderson     TCGTemp *split_args[MAX_OPC_PARAM];
173134b1a49cSRichard Henderson 
1732f764718dSRichard Henderson     retl = NULL;
1733f764718dSRichard Henderson     reth = NULL;
173434b1a49cSRichard Henderson     if (sizemask != 0) {
173534b1a49cSRichard Henderson         for (i = real_args = 0; i < nargs; ++i) {
173634b1a49cSRichard Henderson             int is_64bit = sizemask & (1 << (i+1)*2);
173734b1a49cSRichard Henderson             if (is_64bit) {
1738085272b3SRichard Henderson                 TCGv_i64 orig = temp_tcgv_i64(args[i]);
173934b1a49cSRichard Henderson                 TCGv_i32 h = tcg_temp_new_i32();
174034b1a49cSRichard Henderson                 TCGv_i32 l = tcg_temp_new_i32();
174134b1a49cSRichard Henderson                 tcg_gen_extr_i64_i32(l, h, orig);
1742ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(h);
1743ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(l);
174434b1a49cSRichard Henderson             } else {
174534b1a49cSRichard Henderson                 split_args[real_args++] = args[i];
174634b1a49cSRichard Henderson             }
174734b1a49cSRichard Henderson         }
174834b1a49cSRichard Henderson         nargs = real_args;
174934b1a49cSRichard Henderson         args = split_args;
175034b1a49cSRichard Henderson         sizemask = 0;
175134b1a49cSRichard Henderson     }
175234b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
17532bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
17542bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
17552bece2c8SRichard Henderson         int is_signed = sizemask & (2 << (i+1)*2);
17562bece2c8SRichard Henderson         if (!is_64bit) {
17572bece2c8SRichard Henderson             TCGv_i64 temp = tcg_temp_new_i64();
1758085272b3SRichard Henderson             TCGv_i64 orig = temp_tcgv_i64(args[i]);
17592bece2c8SRichard Henderson             if (is_signed) {
17602bece2c8SRichard Henderson                 tcg_gen_ext32s_i64(temp, orig);
17612bece2c8SRichard Henderson             } else {
17622bece2c8SRichard Henderson                 tcg_gen_ext32u_i64(temp, orig);
17632bece2c8SRichard Henderson             }
1764ae8b75dcSRichard Henderson             args[i] = tcgv_i64_temp(temp);
17652bece2c8SRichard Henderson         }
17662bece2c8SRichard Henderson     }
17672bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
17682bece2c8SRichard Henderson 
176915fa08f8SRichard Henderson     op = tcg_emit_op(INDEX_op_call);
177075e8b9b7SRichard Henderson 
177175e8b9b7SRichard Henderson     pi = 0;
1772ae8b75dcSRichard Henderson     if (ret != NULL) {
177334b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
177434b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
177534b1a49cSRichard Henderson         if (orig_sizemask & 1) {
177634b1a49cSRichard Henderson             /* The 32-bit ABI is going to return the 64-bit value in
177734b1a49cSRichard Henderson                the %o0/%o1 register pair.  Prepare for this by using
177834b1a49cSRichard Henderson                two return temporaries, and reassemble below.  */
177934b1a49cSRichard Henderson             retl = tcg_temp_new_i64();
178034b1a49cSRichard Henderson             reth = tcg_temp_new_i64();
1781ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(reth);
1782ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(retl);
178334b1a49cSRichard Henderson             nb_rets = 2;
178434b1a49cSRichard Henderson         } else {
1785ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
178634b1a49cSRichard Henderson             nb_rets = 1;
178734b1a49cSRichard Henderson         }
178834b1a49cSRichard Henderson #else
178934b1a49cSRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) {
179002eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
1791ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1792ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1793a7812ae4Spbrook #else
1794ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1795ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1796a7812ae4Spbrook #endif
1797a7812ae4Spbrook             nb_rets = 2;
179834b1a49cSRichard Henderson         } else {
1799ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1800a7812ae4Spbrook             nb_rets = 1;
1801a7812ae4Spbrook         }
180234b1a49cSRichard Henderson #endif
1803a7812ae4Spbrook     } else {
1804a7812ae4Spbrook         nb_rets = 0;
1805a7812ae4Spbrook     }
1806cd9090aaSRichard Henderson     TCGOP_CALLO(op) = nb_rets;
180775e8b9b7SRichard Henderson 
1808a7812ae4Spbrook     real_args = 0;
1809a7812ae4Spbrook     for (i = 0; i < nargs; i++) {
18102bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
1811bbb8a1b4SRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
181239cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS
181339cf05d3Sbellard             /* some targets want aligned 64 bit args */
1814ebd486d5Smalc             if (real_args & 1) {
181575e8b9b7SRichard Henderson                 op->args[pi++] = TCG_CALL_DUMMY_ARG;
1816ebd486d5Smalc                 real_args++;
181739cf05d3Sbellard             }
181839cf05d3Sbellard #endif
18193f90f252SRichard Henderson            /* If stack grows up, then we will be placing successive
18203f90f252SRichard Henderson               arguments at lower addresses, which means we need to
18213f90f252SRichard Henderson               reverse the order compared to how we would normally
18223f90f252SRichard Henderson               treat either big or little-endian.  For those arguments
18233f90f252SRichard Henderson               that will wind up in registers, this still works for
18243f90f252SRichard Henderson               HPPA (the only current STACK_GROWSUP target) since the
18253f90f252SRichard Henderson               argument registers are *also* allocated in decreasing
18263f90f252SRichard Henderson               order.  If another such target is added, this logic may
18273f90f252SRichard Henderson               have to get more complicated to differentiate between
18283f90f252SRichard Henderson               stack arguments and register arguments.  */
182902eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
1830ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1831ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1832c896fe29Sbellard #else
1833ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1834ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1835c896fe29Sbellard #endif
1836a7812ae4Spbrook             real_args += 2;
18372bece2c8SRichard Henderson             continue;
18382bece2c8SRichard Henderson         }
18392bece2c8SRichard Henderson 
1840ae8b75dcSRichard Henderson         op->args[pi++] = temp_arg(args[i]);
1841a7812ae4Spbrook         real_args++;
1842c896fe29Sbellard     }
184375e8b9b7SRichard Henderson     op->args[pi++] = (uintptr_t)func;
184475e8b9b7SRichard Henderson     op->args[pi++] = flags;
1845cd9090aaSRichard Henderson     TCGOP_CALLI(op) = real_args;
1846a7812ae4Spbrook 
184775e8b9b7SRichard Henderson     /* Make sure the fields didn't overflow.  */
1848cd9090aaSRichard Henderson     tcg_debug_assert(TCGOP_CALLI(op) == real_args);
184975e8b9b7SRichard Henderson     tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
18502bece2c8SRichard Henderson 
185134b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
185234b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
185334b1a49cSRichard Henderson     /* Free all of the parts we allocated above.  */
185434b1a49cSRichard Henderson     for (i = real_args = 0; i < orig_nargs; ++i) {
185534b1a49cSRichard Henderson         int is_64bit = orig_sizemask & (1 << (i+1)*2);
185634b1a49cSRichard Henderson         if (is_64bit) {
1857085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
1858085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
185934b1a49cSRichard Henderson         } else {
186034b1a49cSRichard Henderson             real_args++;
186134b1a49cSRichard Henderson         }
186234b1a49cSRichard Henderson     }
186334b1a49cSRichard Henderson     if (orig_sizemask & 1) {
186434b1a49cSRichard Henderson         /* The 32-bit ABI returned two 32-bit pieces.  Re-assemble them.
186534b1a49cSRichard Henderson            Note that describing these as TCGv_i64 eliminates an unnecessary
186634b1a49cSRichard Henderson            zero-extension that tcg_gen_concat_i32_i64 would create.  */
1867085272b3SRichard Henderson         tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth);
186834b1a49cSRichard Henderson         tcg_temp_free_i64(retl);
186934b1a49cSRichard Henderson         tcg_temp_free_i64(reth);
187034b1a49cSRichard Henderson     }
187134b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
18722bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
18732bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
18742bece2c8SRichard Henderson         if (!is_64bit) {
1875085272b3SRichard Henderson             tcg_temp_free_internal(args[i]);
18762bece2c8SRichard Henderson         }
18772bece2c8SRichard Henderson     }
18782bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
1879a7812ae4Spbrook }
1880c896fe29Sbellard 
18818fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
1882c896fe29Sbellard {
1883ac3b8891SRichard Henderson     int i, n;
1884c896fe29Sbellard     TCGTemp *ts;
1885ac3b8891SRichard Henderson 
1886ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
1887c896fe29Sbellard         ts = &s->temps[i];
1888ac3b8891SRichard Henderson         ts->val_type = (ts->fixed_reg ? TEMP_VAL_REG : TEMP_VAL_MEM);
1889c896fe29Sbellard     }
1890ac3b8891SRichard Henderson     for (n = s->nb_temps; i < n; i++) {
1891e8996ee0Sbellard         ts = &s->temps[i];
1892ac3b8891SRichard Henderson         ts->val_type = (ts->temp_local ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
1893e8996ee0Sbellard         ts->mem_allocated = 0;
1894e8996ee0Sbellard         ts->fixed_reg = 0;
1895e8996ee0Sbellard     }
1896f8b2f202SRichard Henderson 
1897f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
1898c896fe29Sbellard }
1899c896fe29Sbellard 
1900f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
1901f8b2f202SRichard Henderson                                  TCGTemp *ts)
1902c896fe29Sbellard {
19031807f4c4SRichard Henderson     int idx = temp_idx(ts);
1904ac56dd48Spbrook 
1905fa477d25SRichard Henderson     if (ts->temp_global) {
1906ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
1907f8b2f202SRichard Henderson     } else if (ts->temp_local) {
1908641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
1909f8b2f202SRichard Henderson     } else {
1910ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
1911c896fe29Sbellard     }
1912c896fe29Sbellard     return buf;
1913c896fe29Sbellard }
1914c896fe29Sbellard 
191543439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
191643439139SRichard Henderson                              int buf_size, TCGArg arg)
1917f8b2f202SRichard Henderson {
191843439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
1919f8b2f202SRichard Henderson }
1920f8b2f202SRichard Henderson 
19216e085f72SRichard Henderson /* Find helper name.  */
19226e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val)
1923e8996ee0Sbellard {
19246e085f72SRichard Henderson     const char *ret = NULL;
1925619205fdSEmilio G. Cota     if (helper_table) {
1926619205fdSEmilio G. Cota         TCGHelperInfo *info = g_hash_table_lookup(helper_table, (gpointer)val);
192772866e82SRichard Henderson         if (info) {
192872866e82SRichard Henderson             ret = info->name;
192972866e82SRichard Henderson         }
1930e8996ee0Sbellard     }
19316e085f72SRichard Henderson     return ret;
19324dc81f28Sbellard }
19334dc81f28Sbellard 
1934f48f3edeSblueswir1 static const char * const cond_name[] =
1935f48f3edeSblueswir1 {
19360aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
19370aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
1938f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
1939f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
1940f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
1941f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
1942f48f3edeSblueswir1     [TCG_COND_LE] = "le",
1943f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
1944f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
1945f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
1946f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
1947f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
1948f48f3edeSblueswir1 };
1949f48f3edeSblueswir1 
1950f713d6adSRichard Henderson static const char * const ldst_name[] =
1951f713d6adSRichard Henderson {
1952f713d6adSRichard Henderson     [MO_UB]   = "ub",
1953f713d6adSRichard Henderson     [MO_SB]   = "sb",
1954f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
1955f713d6adSRichard Henderson     [MO_LESW] = "lesw",
1956f713d6adSRichard Henderson     [MO_LEUL] = "leul",
1957f713d6adSRichard Henderson     [MO_LESL] = "lesl",
1958f713d6adSRichard Henderson     [MO_LEQ]  = "leq",
1959f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
1960f713d6adSRichard Henderson     [MO_BESW] = "besw",
1961f713d6adSRichard Henderson     [MO_BEUL] = "beul",
1962f713d6adSRichard Henderson     [MO_BESL] = "besl",
1963f713d6adSRichard Henderson     [MO_BEQ]  = "beq",
1964f713d6adSRichard Henderson };
1965f713d6adSRichard Henderson 
19661f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
196752bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY
19681f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
19691f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
19701f00b27fSSergey Sorokin #else
19711f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
19721f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
19731f00b27fSSergey Sorokin #endif
19741f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
19751f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
19761f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
19771f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
19781f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
19791f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
19801f00b27fSSergey Sorokin };
19811f00b27fSSergey Sorokin 
1982b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
1983b016486eSRichard Henderson {
1984b016486eSRichard Henderson     return (d & (d - 1)) == 0;
1985b016486eSRichard Henderson }
1986b016486eSRichard Henderson 
1987b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
1988b016486eSRichard Henderson {
1989b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
1990b016486eSRichard Henderson         return ctz32(d);
1991b016486eSRichard Henderson     } else {
1992b016486eSRichard Henderson         return ctz64(d);
1993b016486eSRichard Henderson     }
1994b016486eSRichard Henderson }
1995b016486eSRichard Henderson 
19961894f69aSRichard Henderson static void tcg_dump_ops(TCGContext *s, bool have_prefs)
1997c896fe29Sbellard {
1998c896fe29Sbellard     char buf[128];
1999c45cb8bbSRichard Henderson     TCGOp *op;
2000c896fe29Sbellard 
200115fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
2002c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
2003c45cb8bbSRichard Henderson         const TCGOpDef *def;
2004c45cb8bbSRichard Henderson         TCGOpcode c;
2005bdfb460eSRichard Henderson         int col = 0;
2006c45cb8bbSRichard Henderson 
2007c45cb8bbSRichard Henderson         c = op->opc;
2008c896fe29Sbellard         def = &tcg_op_defs[c];
2009c45cb8bbSRichard Henderson 
2010765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
2011b016486eSRichard Henderson             nb_oargs = 0;
201215fa08f8SRichard Henderson             col += qemu_log("\n ----");
20139aef40edSRichard Henderson 
20149aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
20159aef40edSRichard Henderson                 target_ulong a;
20167e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
2017efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
20187e4597d7Sbellard #else
2019efee3746SRichard Henderson                 a = op->args[i];
20207e4597d7Sbellard #endif
2021bdfb460eSRichard Henderson                 col += qemu_log(" " TARGET_FMT_lx, a);
2022eeacee4dSBlue Swirl             }
20237e4597d7Sbellard         } else if (c == INDEX_op_call) {
2024c896fe29Sbellard             /* variable number of arguments */
2025cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2026cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2027c896fe29Sbellard             nb_cargs = def->nb_cargs;
2028b03cce8eSbellard 
2029cf066674SRichard Henderson             /* function name, flags, out args */
2030bdfb460eSRichard Henderson             col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name,
2031efee3746SRichard Henderson                             tcg_find_helper(s, op->args[nb_oargs + nb_iargs]),
2032efee3746SRichard Henderson                             op->args[nb_oargs + nb_iargs + 1], nb_oargs);
2033b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
203443439139SRichard Henderson                 col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf),
2035efee3746SRichard Henderson                                                        op->args[i]));
2036b03cce8eSbellard             }
2037cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
2038efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
2039cf066674SRichard Henderson                 const char *t = "<dummy>";
2040cf066674SRichard Henderson                 if (arg != TCG_CALL_DUMMY_ARG) {
204143439139SRichard Henderson                     t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
2042b03cce8eSbellard                 }
2043bdfb460eSRichard Henderson                 col += qemu_log(",%s", t);
2044e8996ee0Sbellard             }
2045b03cce8eSbellard         } else {
2046bdfb460eSRichard Henderson             col += qemu_log(" %s ", def->name);
2047c45cb8bbSRichard Henderson 
2048c896fe29Sbellard             nb_oargs = def->nb_oargs;
2049c896fe29Sbellard             nb_iargs = def->nb_iargs;
2050c896fe29Sbellard             nb_cargs = def->nb_cargs;
2051c896fe29Sbellard 
2052d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
2053d2fd745fSRichard Henderson                 col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op),
2054d2fd745fSRichard Henderson                                 8 << TCGOP_VECE(op));
2055d2fd745fSRichard Henderson             }
2056d2fd745fSRichard Henderson 
2057c896fe29Sbellard             k = 0;
2058c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
2059eeacee4dSBlue Swirl                 if (k != 0) {
2060bdfb460eSRichard Henderson                     col += qemu_log(",");
2061eeacee4dSBlue Swirl                 }
206243439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2063efee3746SRichard Henderson                                                       op->args[k++]));
2064c896fe29Sbellard             }
2065c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
2066eeacee4dSBlue Swirl                 if (k != 0) {
2067bdfb460eSRichard Henderson                     col += qemu_log(",");
2068eeacee4dSBlue Swirl                 }
206943439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2070efee3746SRichard Henderson                                                       op->args[k++]));
2071c896fe29Sbellard             }
2072be210acbSRichard Henderson             switch (c) {
2073be210acbSRichard Henderson             case INDEX_op_brcond_i32:
2074ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
2075ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
2076be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
2077be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
2078ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
2079be210acbSRichard Henderson             case INDEX_op_setcond_i64:
2080ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
2081212be173SRichard Henderson             case INDEX_op_cmp_vec:
2082f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
2083efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
2084efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
2085efee3746SRichard Henderson                     col += qemu_log(",%s", cond_name[op->args[k++]]);
2086eeacee4dSBlue Swirl                 } else {
2087efee3746SRichard Henderson                     col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]);
2088eeacee4dSBlue Swirl                 }
2089f48f3edeSblueswir1                 i = 1;
2090be210acbSRichard Henderson                 break;
2091f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
2092f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
2093*07ce0b05SRichard Henderson             case INDEX_op_qemu_st8_i32:
2094f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
2095f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
209659227d5dSRichard Henderson                 {
2097efee3746SRichard Henderson                     TCGMemOpIdx oi = op->args[k++];
209814776ab5STony Nguyen                     MemOp op = get_memop(oi);
209959227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
210059227d5dSRichard Henderson 
210159c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
2102bdfb460eSRichard Henderson                         col += qemu_log(",$0x%x,%u", op, ix);
210359c4b7e8SRichard Henderson                     } else {
21041f00b27fSSergey Sorokin                         const char *s_al, *s_op;
21051f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
210659c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
2107bdfb460eSRichard Henderson                         col += qemu_log(",%s%s,%u", s_al, s_op, ix);
2108f713d6adSRichard Henderson                     }
2109f713d6adSRichard Henderson                     i = 1;
211059227d5dSRichard Henderson                 }
2111f713d6adSRichard Henderson                 break;
2112be210acbSRichard Henderson             default:
2113f48f3edeSblueswir1                 i = 0;
2114be210acbSRichard Henderson                 break;
2115be210acbSRichard Henderson             }
211651e3972cSRichard Henderson             switch (c) {
211751e3972cSRichard Henderson             case INDEX_op_set_label:
211851e3972cSRichard Henderson             case INDEX_op_br:
211951e3972cSRichard Henderson             case INDEX_op_brcond_i32:
212051e3972cSRichard Henderson             case INDEX_op_brcond_i64:
212151e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2122efee3746SRichard Henderson                 col += qemu_log("%s$L%d", k ? "," : "",
2123efee3746SRichard Henderson                                 arg_label(op->args[k])->id);
212451e3972cSRichard Henderson                 i++, k++;
212551e3972cSRichard Henderson                 break;
212651e3972cSRichard Henderson             default:
212751e3972cSRichard Henderson                 break;
2128eeacee4dSBlue Swirl             }
212951e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
2130efee3746SRichard Henderson                 col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]);
2131bdfb460eSRichard Henderson             }
2132bdfb460eSRichard Henderson         }
2133bdfb460eSRichard Henderson 
21341894f69aSRichard Henderson         if (have_prefs || op->life) {
21357606488cSRobert Foley 
21367606488cSRobert Foley             QemuLogFile *logfile;
21377606488cSRobert Foley 
21387606488cSRobert Foley             rcu_read_lock();
2139d73415a3SStefan Hajnoczi             logfile = qatomic_rcu_read(&qemu_logfile);
21407606488cSRobert Foley             if (logfile) {
21411894f69aSRichard Henderson                 for (; col < 40; ++col) {
21427606488cSRobert Foley                     putc(' ', logfile->fd);
2143bdfb460eSRichard Henderson                 }
21441894f69aSRichard Henderson             }
21457606488cSRobert Foley             rcu_read_unlock();
21467606488cSRobert Foley         }
21471894f69aSRichard Henderson 
21481894f69aSRichard Henderson         if (op->life) {
21491894f69aSRichard Henderson             unsigned life = op->life;
2150bdfb460eSRichard Henderson 
2151bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
2152bdfb460eSRichard Henderson                 qemu_log("  sync:");
2153bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
2154bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
2155bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2156bdfb460eSRichard Henderson                     }
2157bdfb460eSRichard Henderson                 }
2158bdfb460eSRichard Henderson             }
2159bdfb460eSRichard Henderson             life /= DEAD_ARG;
2160bdfb460eSRichard Henderson             if (life) {
2161bdfb460eSRichard Henderson                 qemu_log("  dead:");
2162bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
2163bdfb460eSRichard Henderson                     if (life & 1) {
2164bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2165bdfb460eSRichard Henderson                     }
2166bdfb460eSRichard Henderson                 }
2167c896fe29Sbellard             }
2168b03cce8eSbellard         }
21691894f69aSRichard Henderson 
21701894f69aSRichard Henderson         if (have_prefs) {
21711894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
21721894f69aSRichard Henderson                 TCGRegSet set = op->output_pref[i];
21731894f69aSRichard Henderson 
21741894f69aSRichard Henderson                 if (i == 0) {
21751894f69aSRichard Henderson                     qemu_log("  pref=");
21761894f69aSRichard Henderson                 } else {
21771894f69aSRichard Henderson                     qemu_log(",");
21781894f69aSRichard Henderson                 }
21791894f69aSRichard Henderson                 if (set == 0) {
21801894f69aSRichard Henderson                     qemu_log("none");
21811894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
21821894f69aSRichard Henderson                     qemu_log("all");
21831894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
21841894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
21851894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
21861894f69aSRichard Henderson                     qemu_log("%s", tcg_target_reg_names[reg]);
21871894f69aSRichard Henderson #endif
21881894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
21891894f69aSRichard Henderson                     qemu_log("%#x", (uint32_t)set);
21901894f69aSRichard Henderson                 } else {
21911894f69aSRichard Henderson                     qemu_log("%#" PRIx64, (uint64_t)set);
21921894f69aSRichard Henderson                 }
21931894f69aSRichard Henderson             }
21941894f69aSRichard Henderson         }
21951894f69aSRichard Henderson 
2196eeacee4dSBlue Swirl         qemu_log("\n");
2197c896fe29Sbellard     }
2198c896fe29Sbellard }
2199c896fe29Sbellard 
2200c896fe29Sbellard /* we give more priority to constraints with less registers */
2201c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2202c896fe29Sbellard {
220374a11790SRichard Henderson     const TCGArgConstraint *arg_ct = &def->args_ct[k];
220474a11790SRichard Henderson     int n;
2205c896fe29Sbellard 
2206bc2b17e6SRichard Henderson     if (arg_ct->oalias) {
2207c896fe29Sbellard         /* an alias is equivalent to a single register */
2208c896fe29Sbellard         n = 1;
2209c896fe29Sbellard     } else {
221074a11790SRichard Henderson         n = ctpop64(arg_ct->regs);
2211c896fe29Sbellard     }
2212c896fe29Sbellard     return TCG_TARGET_NB_REGS - n + 1;
2213c896fe29Sbellard }
2214c896fe29Sbellard 
2215c896fe29Sbellard /* sort from highest priority to lowest */
2216c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2217c896fe29Sbellard {
221866792f90SRichard Henderson     int i, j;
221966792f90SRichard Henderson     TCGArgConstraint *a = def->args_ct;
2220c896fe29Sbellard 
222166792f90SRichard Henderson     for (i = 0; i < n; i++) {
222266792f90SRichard Henderson         a[start + i].sort_index = start + i;
222366792f90SRichard Henderson     }
222466792f90SRichard Henderson     if (n <= 1) {
2225c896fe29Sbellard         return;
222666792f90SRichard Henderson     }
2227c896fe29Sbellard     for (i = 0; i < n - 1; i++) {
2228c896fe29Sbellard         for (j = i + 1; j < n; j++) {
222966792f90SRichard Henderson             int p1 = get_constraint_priority(def, a[start + i].sort_index);
223066792f90SRichard Henderson             int p2 = get_constraint_priority(def, a[start + j].sort_index);
2231c896fe29Sbellard             if (p1 < p2) {
223266792f90SRichard Henderson                 int tmp = a[start + i].sort_index;
223366792f90SRichard Henderson                 a[start + i].sort_index = a[start + j].sort_index;
223466792f90SRichard Henderson                 a[start + j].sort_index = tmp;
2235c896fe29Sbellard             }
2236c896fe29Sbellard         }
2237c896fe29Sbellard     }
2238c896fe29Sbellard }
2239c896fe29Sbellard 
2240f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2241c896fe29Sbellard {
2242a9751609SRichard Henderson     TCGOpcode op;
2243c896fe29Sbellard 
2244f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
2245f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
2246f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
2247069ea736SRichard Henderson         TCGType type;
2248069ea736SRichard Henderson         int i, nb_args;
2249f69d277eSRichard Henderson 
2250f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
2251f69d277eSRichard Henderson             continue;
2252f69d277eSRichard Henderson         }
2253f69d277eSRichard Henderson 
2254c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
2255f69d277eSRichard Henderson         if (nb_args == 0) {
2256f69d277eSRichard Henderson             continue;
2257f69d277eSRichard Henderson         }
2258f69d277eSRichard Henderson 
2259f69d277eSRichard Henderson         tdefs = tcg_target_op_def(op);
2260f69d277eSRichard Henderson         /* Missing TCGTargetOpDef entry. */
2261f69d277eSRichard Henderson         tcg_debug_assert(tdefs != NULL);
2262f69d277eSRichard Henderson 
2263069ea736SRichard Henderson         type = (def->flags & TCG_OPF_64BIT ? TCG_TYPE_I64 : TCG_TYPE_I32);
2264c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2265f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
2266f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2267eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2268f69d277eSRichard Henderson 
226917280ff4SRichard Henderson             while (*ct_str != '\0') {
227017280ff4SRichard Henderson                 switch(*ct_str) {
227117280ff4SRichard Henderson                 case '0' ... '9':
227217280ff4SRichard Henderson                     {
227317280ff4SRichard Henderson                         int oarg = *ct_str - '0';
227417280ff4SRichard Henderson                         tcg_debug_assert(ct_str == tdefs->args_ct_str[i]);
2275eabb7b91SAurelien Jarno                         tcg_debug_assert(oarg < def->nb_oargs);
227674a11790SRichard Henderson                         tcg_debug_assert(def->args_ct[oarg].regs != 0);
2277c896fe29Sbellard                         def->args_ct[i] = def->args_ct[oarg];
2278bc2b17e6SRichard Henderson                         /* The output sets oalias.  */
2279bc2b17e6SRichard Henderson                         def->args_ct[oarg].oalias = true;
22805ff9d6a4Sbellard                         def->args_ct[oarg].alias_index = i;
2281bc2b17e6SRichard Henderson                         /* The input sets ialias. */
2282bc2b17e6SRichard Henderson                         def->args_ct[i].ialias = true;
22835ff9d6a4Sbellard                         def->args_ct[i].alias_index = oarg;
228417280ff4SRichard Henderson                     }
228517280ff4SRichard Henderson                     ct_str++;
2286c896fe29Sbellard                     break;
228782790a87SRichard Henderson                 case '&':
2288bc2b17e6SRichard Henderson                     def->args_ct[i].newreg = true;
228982790a87SRichard Henderson                     ct_str++;
229082790a87SRichard Henderson                     break;
2291c896fe29Sbellard                 case 'i':
2292c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2293c896fe29Sbellard                     ct_str++;
2294c896fe29Sbellard                     break;
2295c896fe29Sbellard                 default:
2296069ea736SRichard Henderson                     ct_str = target_parse_constraint(&def->args_ct[i],
2297069ea736SRichard Henderson                                                      ct_str, type);
2298f69d277eSRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2299069ea736SRichard Henderson                     tcg_debug_assert(ct_str != NULL);
2300c896fe29Sbellard                 }
2301c896fe29Sbellard             }
2302c896fe29Sbellard         }
2303c896fe29Sbellard 
2304c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2305eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2306c68aaa18SStefan Weil 
2307c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
2308c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
2309c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
2310c896fe29Sbellard     }
2311c896fe29Sbellard }
2312c896fe29Sbellard 
23130c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
23140c627cdcSRichard Henderson {
2315d88a117eSRichard Henderson     TCGLabel *label;
2316d88a117eSRichard Henderson 
2317d88a117eSRichard Henderson     switch (op->opc) {
2318d88a117eSRichard Henderson     case INDEX_op_br:
2319d88a117eSRichard Henderson         label = arg_label(op->args[0]);
2320d88a117eSRichard Henderson         label->refs--;
2321d88a117eSRichard Henderson         break;
2322d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
2323d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
2324d88a117eSRichard Henderson         label = arg_label(op->args[3]);
2325d88a117eSRichard Henderson         label->refs--;
2326d88a117eSRichard Henderson         break;
2327d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
2328d88a117eSRichard Henderson         label = arg_label(op->args[5]);
2329d88a117eSRichard Henderson         label->refs--;
2330d88a117eSRichard Henderson         break;
2331d88a117eSRichard Henderson     default:
2332d88a117eSRichard Henderson         break;
2333d88a117eSRichard Henderson     }
2334d88a117eSRichard Henderson 
233515fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
233615fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
2337abebf925SRichard Henderson     s->nb_ops--;
23380c627cdcSRichard Henderson 
23390c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
2340d73415a3SStefan Hajnoczi     qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
23410c627cdcSRichard Henderson #endif
23420c627cdcSRichard Henderson }
23430c627cdcSRichard Henderson 
234415fa08f8SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc)
234515fa08f8SRichard Henderson {
234615fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
234715fa08f8SRichard Henderson     TCGOp *op;
234815fa08f8SRichard Henderson 
234915fa08f8SRichard Henderson     if (likely(QTAILQ_EMPTY(&s->free_ops))) {
235015fa08f8SRichard Henderson         op = tcg_malloc(sizeof(TCGOp));
235115fa08f8SRichard Henderson     } else {
235215fa08f8SRichard Henderson         op = QTAILQ_FIRST(&s->free_ops);
235315fa08f8SRichard Henderson         QTAILQ_REMOVE(&s->free_ops, op, link);
235415fa08f8SRichard Henderson     }
235515fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
235615fa08f8SRichard Henderson     op->opc = opc;
2357abebf925SRichard Henderson     s->nb_ops++;
235815fa08f8SRichard Henderson 
235915fa08f8SRichard Henderson     return op;
236015fa08f8SRichard Henderson }
236115fa08f8SRichard Henderson 
236215fa08f8SRichard Henderson TCGOp *tcg_emit_op(TCGOpcode opc)
236315fa08f8SRichard Henderson {
236415fa08f8SRichard Henderson     TCGOp *op = tcg_op_alloc(opc);
236515fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
236615fa08f8SRichard Henderson     return op;
236715fa08f8SRichard Henderson }
236815fa08f8SRichard Henderson 
2369ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
23705a18407fSRichard Henderson {
237115fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
237215fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
23735a18407fSRichard Henderson     return new_op;
23745a18407fSRichard Henderson }
23755a18407fSRichard Henderson 
2376ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
23775a18407fSRichard Henderson {
237815fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
237915fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
23805a18407fSRichard Henderson     return new_op;
23815a18407fSRichard Henderson }
23825a18407fSRichard Henderson 
2383b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
2384b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s)
2385b4fc67c7SRichard Henderson {
2386b4fc67c7SRichard Henderson     TCGOp *op, *op_next;
2387b4fc67c7SRichard Henderson     bool dead = false;
2388b4fc67c7SRichard Henderson 
2389b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
2390b4fc67c7SRichard Henderson         bool remove = dead;
2391b4fc67c7SRichard Henderson         TCGLabel *label;
2392b4fc67c7SRichard Henderson         int call_flags;
2393b4fc67c7SRichard Henderson 
2394b4fc67c7SRichard Henderson         switch (op->opc) {
2395b4fc67c7SRichard Henderson         case INDEX_op_set_label:
2396b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
2397b4fc67c7SRichard Henderson             if (label->refs == 0) {
2398b4fc67c7SRichard Henderson                 /*
2399b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
2400b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
2401b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
2402b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
2403b4fc67c7SRichard Henderson                  * little to be gained by iterating.
2404b4fc67c7SRichard Henderson                  */
2405b4fc67c7SRichard Henderson                 remove = true;
2406b4fc67c7SRichard Henderson             } else {
2407b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
2408b4fc67c7SRichard Henderson                 dead = false;
2409b4fc67c7SRichard Henderson                 remove = false;
2410b4fc67c7SRichard Henderson 
2411b4fc67c7SRichard Henderson                 /*
2412b4fc67c7SRichard Henderson                  * Optimization can fold conditional branches to unconditional.
2413b4fc67c7SRichard Henderson                  * If we find a label with one reference which is preceded by
2414b4fc67c7SRichard Henderson                  * an unconditional branch to it, remove both.  This needed to
2415b4fc67c7SRichard Henderson                  * wait until the dead code in between them was removed.
2416b4fc67c7SRichard Henderson                  */
2417b4fc67c7SRichard Henderson                 if (label->refs == 1) {
2418eae3eb3eSPaolo Bonzini                     TCGOp *op_prev = QTAILQ_PREV(op, link);
2419b4fc67c7SRichard Henderson                     if (op_prev->opc == INDEX_op_br &&
2420b4fc67c7SRichard Henderson                         label == arg_label(op_prev->args[0])) {
2421b4fc67c7SRichard Henderson                         tcg_op_remove(s, op_prev);
2422b4fc67c7SRichard Henderson                         remove = true;
2423b4fc67c7SRichard Henderson                     }
2424b4fc67c7SRichard Henderson                 }
2425b4fc67c7SRichard Henderson             }
2426b4fc67c7SRichard Henderson             break;
2427b4fc67c7SRichard Henderson 
2428b4fc67c7SRichard Henderson         case INDEX_op_br:
2429b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
2430b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
2431b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
2432b4fc67c7SRichard Henderson             dead = true;
2433b4fc67c7SRichard Henderson             break;
2434b4fc67c7SRichard Henderson 
2435b4fc67c7SRichard Henderson         case INDEX_op_call:
2436b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
2437b4fc67c7SRichard Henderson             call_flags = op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1];
2438b4fc67c7SRichard Henderson             if (call_flags & TCG_CALL_NO_RETURN) {
2439b4fc67c7SRichard Henderson                 dead = true;
2440b4fc67c7SRichard Henderson             }
2441b4fc67c7SRichard Henderson             break;
2442b4fc67c7SRichard Henderson 
2443b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
2444b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
2445b4fc67c7SRichard Henderson             remove = false;
2446b4fc67c7SRichard Henderson             break;
2447b4fc67c7SRichard Henderson 
2448b4fc67c7SRichard Henderson         default:
2449b4fc67c7SRichard Henderson             break;
2450b4fc67c7SRichard Henderson         }
2451b4fc67c7SRichard Henderson 
2452b4fc67c7SRichard Henderson         if (remove) {
2453b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
2454b4fc67c7SRichard Henderson         }
2455b4fc67c7SRichard Henderson     }
2456b4fc67c7SRichard Henderson }
2457b4fc67c7SRichard Henderson 
2458c70fbf0aSRichard Henderson #define TS_DEAD  1
2459c70fbf0aSRichard Henderson #define TS_MEM   2
2460c70fbf0aSRichard Henderson 
24615a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
24625a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
24635a18407fSRichard Henderson 
246425f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
246525f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
246625f49c5fSRichard Henderson {
246725f49c5fSRichard Henderson     return ts->state_ptr;
246825f49c5fSRichard Henderson }
246925f49c5fSRichard Henderson 
247025f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
247125f49c5fSRichard Henderson  * maximal regset for its type.
247225f49c5fSRichard Henderson  */
247325f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
247425f49c5fSRichard Henderson {
247525f49c5fSRichard Henderson     *la_temp_pref(ts)
247625f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
247725f49c5fSRichard Henderson }
247825f49c5fSRichard Henderson 
24799c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
24809c43b68dSAurelien Jarno    should be in memory. */
24812616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
2482c896fe29Sbellard {
2483b83eabeaSRichard Henderson     int i;
2484b83eabeaSRichard Henderson 
2485b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2486b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
248725f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2488b83eabeaSRichard Henderson     }
2489b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2490b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
249125f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2492b83eabeaSRichard Henderson     }
2493c896fe29Sbellard }
2494c896fe29Sbellard 
24959c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
24969c43b68dSAurelien Jarno    and local temps should be in memory. */
24972616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
2498641d5fbeSbellard {
2499b83eabeaSRichard Henderson     int i;
2500641d5fbeSbellard 
2501b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2502b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
250325f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2504c70fbf0aSRichard Henderson     }
2505b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2506b83eabeaSRichard Henderson         s->temps[i].state = (s->temps[i].temp_local
2507b83eabeaSRichard Henderson                              ? TS_DEAD | TS_MEM
2508b83eabeaSRichard Henderson                              : TS_DEAD);
250925f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2510641d5fbeSbellard     }
2511641d5fbeSbellard }
2512641d5fbeSbellard 
2513f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
2514f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
2515f65a061cSRichard Henderson {
2516f65a061cSRichard Henderson     int i;
2517f65a061cSRichard Henderson 
2518f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
251925f49c5fSRichard Henderson         int state = s->temps[i].state;
252025f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
252125f49c5fSRichard Henderson         if (state == TS_DEAD) {
252225f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
252325f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
252425f49c5fSRichard Henderson         }
2525f65a061cSRichard Henderson     }
2526f65a061cSRichard Henderson }
2527f65a061cSRichard Henderson 
2528b4cb76e6SRichard Henderson /*
2529b4cb76e6SRichard Henderson  * liveness analysis: conditional branch: all temps are dead,
2530b4cb76e6SRichard Henderson  * globals and local temps should be synced.
2531b4cb76e6SRichard Henderson  */
2532b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
2533b4cb76e6SRichard Henderson {
2534b4cb76e6SRichard Henderson     la_global_sync(s, ng);
2535b4cb76e6SRichard Henderson 
2536b4cb76e6SRichard Henderson     for (int i = ng; i < nt; ++i) {
2537b4cb76e6SRichard Henderson         if (s->temps[i].temp_local) {
2538b4cb76e6SRichard Henderson             int state = s->temps[i].state;
2539b4cb76e6SRichard Henderson             s->temps[i].state = state | TS_MEM;
2540b4cb76e6SRichard Henderson             if (state != TS_DEAD) {
2541b4cb76e6SRichard Henderson                 continue;
2542b4cb76e6SRichard Henderson             }
2543b4cb76e6SRichard Henderson         } else {
2544b4cb76e6SRichard Henderson             s->temps[i].state = TS_DEAD;
2545b4cb76e6SRichard Henderson         }
2546b4cb76e6SRichard Henderson         la_reset_pref(&s->temps[i]);
2547b4cb76e6SRichard Henderson     }
2548b4cb76e6SRichard Henderson }
2549b4cb76e6SRichard Henderson 
2550f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
2551f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
2552f65a061cSRichard Henderson {
2553f65a061cSRichard Henderson     int i;
2554f65a061cSRichard Henderson 
2555f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
2556f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
255725f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
255825f49c5fSRichard Henderson     }
255925f49c5fSRichard Henderson }
256025f49c5fSRichard Henderson 
256125f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
256225f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
256325f49c5fSRichard Henderson {
256425f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
256525f49c5fSRichard Henderson     int i;
256625f49c5fSRichard Henderson 
256725f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
256825f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
256925f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
257025f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
257125f49c5fSRichard Henderson             TCGRegSet set = *pset;
257225f49c5fSRichard Henderson 
257325f49c5fSRichard Henderson             set &= mask;
257425f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
257525f49c5fSRichard Henderson             if (set == 0) {
257625f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
257725f49c5fSRichard Henderson             }
257825f49c5fSRichard Henderson             *pset = set;
257925f49c5fSRichard Henderson         }
2580f65a061cSRichard Henderson     }
2581f65a061cSRichard Henderson }
2582f65a061cSRichard Henderson 
2583a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
2584c896fe29Sbellard    given input arguments is dead. Instructions updating dead
2585c896fe29Sbellard    temporaries are removed. */
2586b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s)
2587c896fe29Sbellard {
2588c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
25892616c808SRichard Henderson     int nb_temps = s->nb_temps;
259015fa08f8SRichard Henderson     TCGOp *op, *op_prev;
259125f49c5fSRichard Henderson     TCGRegSet *prefs;
259225f49c5fSRichard Henderson     int i;
259325f49c5fSRichard Henderson 
259425f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
259525f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
259625f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
259725f49c5fSRichard Henderson     }
2598c896fe29Sbellard 
2599ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
26002616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
2601c896fe29Sbellard 
2602eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
260325f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
2604c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
2605c45cb8bbSRichard Henderson         bool have_opc_new2;
2606a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
260725f49c5fSRichard Henderson         TCGTemp *ts;
2608c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2609c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2610c45cb8bbSRichard Henderson 
2611c45cb8bbSRichard Henderson         switch (opc) {
2612c896fe29Sbellard         case INDEX_op_call:
2613c6e113f5Sbellard             {
2614c6e113f5Sbellard                 int call_flags;
261525f49c5fSRichard Henderson                 int nb_call_regs;
2616c6e113f5Sbellard 
2617cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
2618cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
2619efee3746SRichard Henderson                 call_flags = op->args[nb_oargs + nb_iargs + 1];
2620c6e113f5Sbellard 
2621c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
262278505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
2623c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
262425f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
262525f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
2626c6e113f5Sbellard                             goto do_not_remove_call;
2627c6e113f5Sbellard                         }
26289c43b68dSAurelien Jarno                     }
2629c45cb8bbSRichard Henderson                     goto do_remove;
2630152c35aaSRichard Henderson                 }
2631c6e113f5Sbellard             do_not_remove_call:
2632c896fe29Sbellard 
263325f49c5fSRichard Henderson                 /* Output args are dead.  */
2634c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
263525f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
263625f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
2637a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
26386b64b624SAurelien Jarno                     }
263925f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
2640a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
26419c43b68dSAurelien Jarno                     }
264225f49c5fSRichard Henderson                     ts->state = TS_DEAD;
264325f49c5fSRichard Henderson                     la_reset_pref(ts);
264425f49c5fSRichard Henderson 
264525f49c5fSRichard Henderson                     /* Not used -- it will be tcg_target_call_oarg_regs[i].  */
264625f49c5fSRichard Henderson                     op->output_pref[i] = 0;
2647c896fe29Sbellard                 }
2648c896fe29Sbellard 
264978505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
265078505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
2651f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
2652c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
2653f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
2654b9c18f56Saurel32                 }
2655c896fe29Sbellard 
265625f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
2657866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
265825f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
265925f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
2660a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
2661c896fe29Sbellard                     }
2662c896fe29Sbellard                 }
266325f49c5fSRichard Henderson 
266425f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
266525f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
266625f49c5fSRichard Henderson 
266725f49c5fSRichard Henderson                 nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
266825f49c5fSRichard Henderson 
266925f49c5fSRichard Henderson                 /* Input arguments are live for preceding opcodes.  */
267025f49c5fSRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
267125f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
267225f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
267325f49c5fSRichard Henderson                         /* For those arguments that die, and will be allocated
267425f49c5fSRichard Henderson                          * in registers, clear the register set for that arg,
267525f49c5fSRichard Henderson                          * to be filled in below.  For args that will be on
267625f49c5fSRichard Henderson                          * the stack, reset to any available reg.
267725f49c5fSRichard Henderson                          */
267825f49c5fSRichard Henderson                         *la_temp_pref(ts)
267925f49c5fSRichard Henderson                             = (i < nb_call_regs ? 0 :
268025f49c5fSRichard Henderson                                tcg_target_available_regs[ts->type]);
268125f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
268225f49c5fSRichard Henderson                     }
268325f49c5fSRichard Henderson                 }
268425f49c5fSRichard Henderson 
268525f49c5fSRichard Henderson                 /* For each input argument, add its input register to prefs.
268625f49c5fSRichard Henderson                    If a temp is used once, this produces a single set bit.  */
268725f49c5fSRichard Henderson                 for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) {
268825f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
268925f49c5fSRichard Henderson                     if (ts) {
269025f49c5fSRichard Henderson                         tcg_regset_set_reg(*la_temp_pref(ts),
269125f49c5fSRichard Henderson                                            tcg_target_call_iarg_regs[i]);
2692c70fbf0aSRichard Henderson                     }
2693c19f47bfSAurelien Jarno                 }
2694c6e113f5Sbellard             }
2695c896fe29Sbellard             break;
2696765b842aSRichard Henderson         case INDEX_op_insn_start:
2697c896fe29Sbellard             break;
26985ff9d6a4Sbellard         case INDEX_op_discard:
26995ff9d6a4Sbellard             /* mark the temporary as dead */
270025f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
270125f49c5fSRichard Henderson             ts->state = TS_DEAD;
270225f49c5fSRichard Henderson             la_reset_pref(ts);
27035ff9d6a4Sbellard             break;
27041305c451SRichard Henderson 
27051305c451SRichard Henderson         case INDEX_op_add2_i32:
2706c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
2707f1fae40cSRichard Henderson             goto do_addsub2;
27081305c451SRichard Henderson         case INDEX_op_sub2_i32:
2709c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
2710f1fae40cSRichard Henderson             goto do_addsub2;
2711f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
2712c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
2713f1fae40cSRichard Henderson             goto do_addsub2;
2714f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
2715c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
2716f1fae40cSRichard Henderson         do_addsub2:
27171305c451SRichard Henderson             nb_iargs = 4;
27181305c451SRichard Henderson             nb_oargs = 2;
27191305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
27201305c451SRichard Henderson                the low part.  The result can be optimized to a simple
27211305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
27221305c451SRichard Henderson                cpu mode is set to 32 bit.  */
2723b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2724b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
27251305c451SRichard Henderson                     goto do_remove;
27261305c451SRichard Henderson                 }
2727c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
2728c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
2729c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2730efee3746SRichard Henderson                 op->args[1] = op->args[2];
2731efee3746SRichard Henderson                 op->args[2] = op->args[4];
27321305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
27331305c451SRichard Henderson                 nb_iargs = 2;
27341305c451SRichard Henderson                 nb_oargs = 1;
27351305c451SRichard Henderson             }
27361305c451SRichard Henderson             goto do_not_remove;
27371305c451SRichard Henderson 
27381414968aSRichard Henderson         case INDEX_op_mulu2_i32:
2739c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2740c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
2741c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
274203271524SRichard Henderson             goto do_mul2;
2743f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
2744c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2745c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
2746c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
2747f1fae40cSRichard Henderson             goto do_mul2;
2748f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
2749c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2750c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
2751c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
275203271524SRichard Henderson             goto do_mul2;
2753f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
2754c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2755c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
2756c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
275703271524SRichard Henderson             goto do_mul2;
2758f1fae40cSRichard Henderson         do_mul2:
27591414968aSRichard Henderson             nb_iargs = 2;
27601414968aSRichard Henderson             nb_oargs = 2;
2761b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2762b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
276303271524SRichard Henderson                     /* Both parts of the operation are dead.  */
27641414968aSRichard Henderson                     goto do_remove;
27651414968aSRichard Henderson                 }
276603271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
2767c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2768efee3746SRichard Henderson                 op->args[1] = op->args[2];
2769efee3746SRichard Henderson                 op->args[2] = op->args[3];
2770b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
277103271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
2772c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
2773efee3746SRichard Henderson                 op->args[0] = op->args[1];
2774efee3746SRichard Henderson                 op->args[1] = op->args[2];
2775efee3746SRichard Henderson                 op->args[2] = op->args[3];
277603271524SRichard Henderson             } else {
277703271524SRichard Henderson                 goto do_not_remove;
277803271524SRichard Henderson             }
277903271524SRichard Henderson             /* Mark the single-word operation live.  */
27801414968aSRichard Henderson             nb_oargs = 1;
27811414968aSRichard Henderson             goto do_not_remove;
27821414968aSRichard Henderson 
2783c896fe29Sbellard         default:
27841305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
2785c896fe29Sbellard             nb_iargs = def->nb_iargs;
2786c896fe29Sbellard             nb_oargs = def->nb_oargs;
2787c896fe29Sbellard 
2788c896fe29Sbellard             /* Test if the operation can be removed because all
27895ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
27905ff9d6a4Sbellard                implies side effects */
27915ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
2792c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
2793b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
2794c896fe29Sbellard                         goto do_not_remove;
2795c896fe29Sbellard                     }
27969c43b68dSAurelien Jarno                 }
2797152c35aaSRichard Henderson                 goto do_remove;
2798152c35aaSRichard Henderson             }
2799152c35aaSRichard Henderson             goto do_not_remove;
2800152c35aaSRichard Henderson 
28011305c451SRichard Henderson         do_remove:
28020c627cdcSRichard Henderson             tcg_op_remove(s, op);
2803152c35aaSRichard Henderson             break;
2804152c35aaSRichard Henderson 
2805c896fe29Sbellard         do_not_remove:
2806c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
280725f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
280825f49c5fSRichard Henderson 
280925f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
281025f49c5fSRichard Henderson                 op->output_pref[i] = *la_temp_pref(ts);
281125f49c5fSRichard Henderson 
281225f49c5fSRichard Henderson                 /* Output args are dead.  */
281325f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2814a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
28156b64b624SAurelien Jarno                 }
281625f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
2817a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
28189c43b68dSAurelien Jarno                 }
281925f49c5fSRichard Henderson                 ts->state = TS_DEAD;
282025f49c5fSRichard Henderson                 la_reset_pref(ts);
2821c896fe29Sbellard             }
2822c896fe29Sbellard 
282325f49c5fSRichard Henderson             /* If end of basic block, update.  */
2824ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
2825ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
2826b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_COND_BRANCH) {
2827b4cb76e6SRichard Henderson                 la_bb_sync(s, nb_globals, nb_temps);
2828ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
28292616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
28303d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
2831f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
283225f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
283325f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
283425f49c5fSRichard Henderson                 }
2835c896fe29Sbellard             }
2836c896fe29Sbellard 
283725f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
2838866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
283925f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
284025f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2841a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
2842c896fe29Sbellard                 }
2843c19f47bfSAurelien Jarno             }
284425f49c5fSRichard Henderson 
284525f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
2846c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
284725f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
284825f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
284925f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
285025f49c5fSRichard Henderson                        all regs for the type.  */
285125f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
285225f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
285325f49c5fSRichard Henderson                 }
285425f49c5fSRichard Henderson             }
285525f49c5fSRichard Henderson 
285625f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
285725f49c5fSRichard Henderson             switch (opc) {
285825f49c5fSRichard Henderson             case INDEX_op_mov_i32:
285925f49c5fSRichard Henderson             case INDEX_op_mov_i64:
286025f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
286125f49c5fSRichard Henderson                    have proper constraints.  That said, special case
286225f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
286325f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
286425f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
286525f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
286625f49c5fSRichard Henderson                 }
286725f49c5fSRichard Henderson                 break;
286825f49c5fSRichard Henderson 
286925f49c5fSRichard Henderson             default:
287025f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
287125f49c5fSRichard Henderson                     const TCGArgConstraint *ct = &def->args_ct[i];
287225f49c5fSRichard Henderson                     TCGRegSet set, *pset;
287325f49c5fSRichard Henderson 
287425f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
287525f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
287625f49c5fSRichard Henderson                     set = *pset;
287725f49c5fSRichard Henderson 
28789be0d080SRichard Henderson                     set &= ct->regs;
2879bc2b17e6SRichard Henderson                     if (ct->ialias) {
288025f49c5fSRichard Henderson                         set &= op->output_pref[ct->alias_index];
288125f49c5fSRichard Henderson                     }
288225f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
288325f49c5fSRichard Henderson                     if (set == 0) {
28849be0d080SRichard Henderson                         set = ct->regs;
288525f49c5fSRichard Henderson                     }
288625f49c5fSRichard Henderson                     *pset = set;
288725f49c5fSRichard Henderson                 }
288825f49c5fSRichard Henderson                 break;
2889c896fe29Sbellard             }
2890c896fe29Sbellard             break;
2891c896fe29Sbellard         }
2892bee158cbSRichard Henderson         op->life = arg_life;
2893c896fe29Sbellard     }
28941ff0a2c5SEvgeny Voevodin }
2895c896fe29Sbellard 
28965a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
2897b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s)
28985a18407fSRichard Henderson {
28995a18407fSRichard Henderson     int nb_globals = s->nb_globals;
290015fa08f8SRichard Henderson     int nb_temps, i;
29015a18407fSRichard Henderson     bool changes = false;
290215fa08f8SRichard Henderson     TCGOp *op, *op_next;
29035a18407fSRichard Henderson 
29045a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
29055a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
29065a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
29075a18407fSRichard Henderson         if (its->indirect_reg) {
29085a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
29095a18407fSRichard Henderson             dts->type = its->type;
29105a18407fSRichard Henderson             dts->base_type = its->base_type;
2911b83eabeaSRichard Henderson             its->state_ptr = dts;
2912b83eabeaSRichard Henderson         } else {
2913b83eabeaSRichard Henderson             its->state_ptr = NULL;
29145a18407fSRichard Henderson         }
2915b83eabeaSRichard Henderson         /* All globals begin dead.  */
2916b83eabeaSRichard Henderson         its->state = TS_DEAD;
29175a18407fSRichard Henderson     }
2918b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
2919b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
2920b83eabeaSRichard Henderson         its->state_ptr = NULL;
2921b83eabeaSRichard Henderson         its->state = TS_DEAD;
2922b83eabeaSRichard Henderson     }
29235a18407fSRichard Henderson 
292415fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
29255a18407fSRichard Henderson         TCGOpcode opc = op->opc;
29265a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
29275a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
29285a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
2929b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
29305a18407fSRichard Henderson 
29315a18407fSRichard Henderson         if (opc == INDEX_op_call) {
2932cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2933cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2934efee3746SRichard Henderson             call_flags = op->args[nb_oargs + nb_iargs + 1];
29355a18407fSRichard Henderson         } else {
29365a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
29375a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
29385a18407fSRichard Henderson 
29395a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
2940b4cb76e6SRichard Henderson             if (def->flags & TCG_OPF_COND_BRANCH) {
2941b4cb76e6SRichard Henderson                 /* Like reading globals: sync_globals */
2942b4cb76e6SRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
2943b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
29445a18407fSRichard Henderson                 /* Like writing globals: save_globals */
29455a18407fSRichard Henderson                 call_flags = 0;
29465a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
29475a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
29485a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
29495a18407fSRichard Henderson             } else {
29505a18407fSRichard Henderson                 /* No effect on globals.  */
29515a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
29525a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
29535a18407fSRichard Henderson             }
29545a18407fSRichard Henderson         }
29555a18407fSRichard Henderson 
29565a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
29575a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2958b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2959b83eabeaSRichard Henderson             if (arg_ts) {
2960b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
2961b83eabeaSRichard Henderson                 if (dir_ts && arg_ts->state == TS_DEAD) {
2962b83eabeaSRichard Henderson                     TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
29635a18407fSRichard Henderson                                       ? INDEX_op_ld_i32
29645a18407fSRichard Henderson                                       : INDEX_op_ld_i64);
2965ac1043f6SEmilio G. Cota                     TCGOp *lop = tcg_op_insert_before(s, op, lopc);
29665a18407fSRichard Henderson 
2967b83eabeaSRichard Henderson                     lop->args[0] = temp_arg(dir_ts);
2968b83eabeaSRichard Henderson                     lop->args[1] = temp_arg(arg_ts->mem_base);
2969b83eabeaSRichard Henderson                     lop->args[2] = arg_ts->mem_offset;
29705a18407fSRichard Henderson 
29715a18407fSRichard Henderson                     /* Loaded, but synced with memory.  */
2972b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
29735a18407fSRichard Henderson                 }
29745a18407fSRichard Henderson             }
29755a18407fSRichard Henderson         }
29765a18407fSRichard Henderson 
29775a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
29785a18407fSRichard Henderson            No action is required except keeping temp_state up to date
29795a18407fSRichard Henderson            so that we reload when needed.  */
29805a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2981b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2982b83eabeaSRichard Henderson             if (arg_ts) {
2983b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
2984b83eabeaSRichard Henderson                 if (dir_ts) {
2985b83eabeaSRichard Henderson                     op->args[i] = temp_arg(dir_ts);
29865a18407fSRichard Henderson                     changes = true;
29875a18407fSRichard Henderson                     if (IS_DEAD_ARG(i)) {
2988b83eabeaSRichard Henderson                         arg_ts->state = TS_DEAD;
29895a18407fSRichard Henderson                     }
29905a18407fSRichard Henderson                 }
29915a18407fSRichard Henderson             }
29925a18407fSRichard Henderson         }
29935a18407fSRichard Henderson 
29945a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
29955a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
29965a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
29975a18407fSRichard Henderson             /* Nothing to do */
29985a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
29995a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
30005a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
30015a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
3002b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3003b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3004b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
30055a18407fSRichard Henderson             }
30065a18407fSRichard Henderson         } else {
30075a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
30085a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
30095a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
3010b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3011b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3012b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
30135a18407fSRichard Henderson             }
30145a18407fSRichard Henderson         }
30155a18407fSRichard Henderson 
30165a18407fSRichard Henderson         /* Outputs become available.  */
301761f15c48SRichard Henderson         if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) {
301861f15c48SRichard Henderson             arg_ts = arg_temp(op->args[0]);
301961f15c48SRichard Henderson             dir_ts = arg_ts->state_ptr;
302061f15c48SRichard Henderson             if (dir_ts) {
302161f15c48SRichard Henderson                 op->args[0] = temp_arg(dir_ts);
302261f15c48SRichard Henderson                 changes = true;
302361f15c48SRichard Henderson 
302461f15c48SRichard Henderson                 /* The output is now live and modified.  */
302561f15c48SRichard Henderson                 arg_ts->state = 0;
302661f15c48SRichard Henderson 
302761f15c48SRichard Henderson                 if (NEED_SYNC_ARG(0)) {
302861f15c48SRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
302961f15c48SRichard Henderson                                       ? INDEX_op_st_i32
303061f15c48SRichard Henderson                                       : INDEX_op_st_i64);
303161f15c48SRichard Henderson                     TCGOp *sop = tcg_op_insert_after(s, op, sopc);
303261f15c48SRichard Henderson                     TCGTemp *out_ts = dir_ts;
303361f15c48SRichard Henderson 
303461f15c48SRichard Henderson                     if (IS_DEAD_ARG(0)) {
303561f15c48SRichard Henderson                         out_ts = arg_temp(op->args[1]);
303661f15c48SRichard Henderson                         arg_ts->state = TS_DEAD;
303761f15c48SRichard Henderson                         tcg_op_remove(s, op);
303861f15c48SRichard Henderson                     } else {
303961f15c48SRichard Henderson                         arg_ts->state = TS_MEM;
304061f15c48SRichard Henderson                     }
304161f15c48SRichard Henderson 
304261f15c48SRichard Henderson                     sop->args[0] = temp_arg(out_ts);
304361f15c48SRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
304461f15c48SRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
304561f15c48SRichard Henderson                 } else {
304661f15c48SRichard Henderson                     tcg_debug_assert(!IS_DEAD_ARG(0));
304761f15c48SRichard Henderson                 }
304861f15c48SRichard Henderson             }
304961f15c48SRichard Henderson         } else {
30505a18407fSRichard Henderson             for (i = 0; i < nb_oargs; i++) {
3051b83eabeaSRichard Henderson                 arg_ts = arg_temp(op->args[i]);
3052b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3053b83eabeaSRichard Henderson                 if (!dir_ts) {
30545a18407fSRichard Henderson                     continue;
30555a18407fSRichard Henderson                 }
3056b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
30575a18407fSRichard Henderson                 changes = true;
30585a18407fSRichard Henderson 
30595a18407fSRichard Henderson                 /* The output is now live and modified.  */
3060b83eabeaSRichard Henderson                 arg_ts->state = 0;
30615a18407fSRichard Henderson 
30625a18407fSRichard Henderson                 /* Sync outputs upon their last write.  */
30635a18407fSRichard Henderson                 if (NEED_SYNC_ARG(i)) {
3064b83eabeaSRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
30655a18407fSRichard Henderson                                       ? INDEX_op_st_i32
30665a18407fSRichard Henderson                                       : INDEX_op_st_i64);
3067ac1043f6SEmilio G. Cota                     TCGOp *sop = tcg_op_insert_after(s, op, sopc);
30685a18407fSRichard Henderson 
3069b83eabeaSRichard Henderson                     sop->args[0] = temp_arg(dir_ts);
3070b83eabeaSRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
3071b83eabeaSRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
30725a18407fSRichard Henderson 
3073b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
30745a18407fSRichard Henderson                 }
30755a18407fSRichard Henderson                 /* Drop outputs that are dead.  */
30765a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3077b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
30785a18407fSRichard Henderson                 }
30795a18407fSRichard Henderson             }
30805a18407fSRichard Henderson         }
308161f15c48SRichard Henderson     }
30825a18407fSRichard Henderson 
30835a18407fSRichard Henderson     return changes;
30845a18407fSRichard Henderson }
30855a18407fSRichard Henderson 
30868d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
3087c896fe29Sbellard static void dump_regs(TCGContext *s)
3088c896fe29Sbellard {
3089c896fe29Sbellard     TCGTemp *ts;
3090c896fe29Sbellard     int i;
3091c896fe29Sbellard     char buf[64];
3092c896fe29Sbellard 
3093c896fe29Sbellard     for(i = 0; i < s->nb_temps; i++) {
3094c896fe29Sbellard         ts = &s->temps[i];
309543439139SRichard Henderson         printf("  %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3096c896fe29Sbellard         switch(ts->val_type) {
3097c896fe29Sbellard         case TEMP_VAL_REG:
3098c896fe29Sbellard             printf("%s", tcg_target_reg_names[ts->reg]);
3099c896fe29Sbellard             break;
3100c896fe29Sbellard         case TEMP_VAL_MEM:
3101b3a62939SRichard Henderson             printf("%d(%s)", (int)ts->mem_offset,
3102b3a62939SRichard Henderson                    tcg_target_reg_names[ts->mem_base->reg]);
3103c896fe29Sbellard             break;
3104c896fe29Sbellard         case TEMP_VAL_CONST:
3105c896fe29Sbellard             printf("$0x%" TCG_PRIlx, ts->val);
3106c896fe29Sbellard             break;
3107c896fe29Sbellard         case TEMP_VAL_DEAD:
3108c896fe29Sbellard             printf("D");
3109c896fe29Sbellard             break;
3110c896fe29Sbellard         default:
3111c896fe29Sbellard             printf("???");
3112c896fe29Sbellard             break;
3113c896fe29Sbellard         }
3114c896fe29Sbellard         printf("\n");
3115c896fe29Sbellard     }
3116c896fe29Sbellard 
3117c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
3118f8b2f202SRichard Henderson         if (s->reg_to_temp[i] != NULL) {
3119c896fe29Sbellard             printf("%s: %s\n",
3120c896fe29Sbellard                    tcg_target_reg_names[i],
3121f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i]));
3122c896fe29Sbellard         }
3123c896fe29Sbellard     }
3124c896fe29Sbellard }
3125c896fe29Sbellard 
3126c896fe29Sbellard static void check_regs(TCGContext *s)
3127c896fe29Sbellard {
3128869938aeSRichard Henderson     int reg;
3129b6638662SRichard Henderson     int k;
3130c896fe29Sbellard     TCGTemp *ts;
3131c896fe29Sbellard     char buf[64];
3132c896fe29Sbellard 
3133c896fe29Sbellard     for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
3134f8b2f202SRichard Henderson         ts = s->reg_to_temp[reg];
3135f8b2f202SRichard Henderson         if (ts != NULL) {
3136f8b2f202SRichard Henderson             if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) {
3137c896fe29Sbellard                 printf("Inconsistency for register %s:\n",
3138c896fe29Sbellard                        tcg_target_reg_names[reg]);
3139b03cce8eSbellard                 goto fail;
3140c896fe29Sbellard             }
3141c896fe29Sbellard         }
3142c896fe29Sbellard     }
3143c896fe29Sbellard     for (k = 0; k < s->nb_temps; k++) {
3144c896fe29Sbellard         ts = &s->temps[k];
3145f8b2f202SRichard Henderson         if (ts->val_type == TEMP_VAL_REG && !ts->fixed_reg
3146f8b2f202SRichard Henderson             && s->reg_to_temp[ts->reg] != ts) {
3147c896fe29Sbellard             printf("Inconsistency for temp %s:\n",
3148f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3149b03cce8eSbellard         fail:
3150c896fe29Sbellard             printf("reg state:\n");
3151c896fe29Sbellard             dump_regs(s);
3152c896fe29Sbellard             tcg_abort();
3153c896fe29Sbellard         }
3154c896fe29Sbellard     }
3155c896fe29Sbellard }
3156c896fe29Sbellard #endif
3157c896fe29Sbellard 
31582272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
3159c896fe29Sbellard {
31609b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64)
31619b9c37c3SRichard Henderson     /* Sparc64 stack is accessed with offset of 2047 */
3162b591dc59SBlue Swirl     s->current_frame_offset = (s->current_frame_offset +
3163b591dc59SBlue Swirl                                (tcg_target_long)sizeof(tcg_target_long) - 1) &
3164b591dc59SBlue Swirl         ~(sizeof(tcg_target_long) - 1);
3165f44c9960SBlue Swirl #endif
3166b591dc59SBlue Swirl     if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
3167b591dc59SBlue Swirl         s->frame_end) {
31685ff9d6a4Sbellard         tcg_abort();
3169b591dc59SBlue Swirl     }
3170c896fe29Sbellard     ts->mem_offset = s->current_frame_offset;
3171b3a62939SRichard Henderson     ts->mem_base = s->frame_temp;
3172c896fe29Sbellard     ts->mem_allocated = 1;
3173e2c6d1b4SRichard Henderson     s->current_frame_offset += sizeof(tcg_target_long);
3174c896fe29Sbellard }
3175c896fe29Sbellard 
3176b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
3177b3915dbbSRichard Henderson 
317859d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
317959d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
318059d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
3181c896fe29Sbellard {
318259d7c14eSRichard Henderson     if (ts->fixed_reg) {
318359d7c14eSRichard Henderson         return;
318459d7c14eSRichard Henderson     }
318559d7c14eSRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
318659d7c14eSRichard Henderson         s->reg_to_temp[ts->reg] = NULL;
318759d7c14eSRichard Henderson     }
318859d7c14eSRichard Henderson     ts->val_type = (free_or_dead < 0
318959d7c14eSRichard Henderson                     || ts->temp_local
3190fa477d25SRichard Henderson                     || ts->temp_global
319159d7c14eSRichard Henderson                     ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
319259d7c14eSRichard Henderson }
3193c896fe29Sbellard 
319459d7c14eSRichard Henderson /* Mark a temporary as dead.  */
319559d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
319659d7c14eSRichard Henderson {
319759d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
319859d7c14eSRichard Henderson }
319959d7c14eSRichard Henderson 
320059d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
320159d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
320259d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
320359d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
320498b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
320598b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
320659d7c14eSRichard Henderson {
320759d7c14eSRichard Henderson     if (ts->fixed_reg) {
320859d7c14eSRichard Henderson         return;
320959d7c14eSRichard Henderson     }
321059d7c14eSRichard Henderson     if (!ts->mem_coherent) {
32117f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
32122272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
321359d7c14eSRichard Henderson         }
321459d7c14eSRichard Henderson         switch (ts->val_type) {
321559d7c14eSRichard Henderson         case TEMP_VAL_CONST:
321659d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
321759d7c14eSRichard Henderson                require it later in a register, so attempt to store the
321859d7c14eSRichard Henderson                constant to memory directly.  */
321959d7c14eSRichard Henderson             if (free_or_dead
322059d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
322159d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
322259d7c14eSRichard Henderson                 break;
322359d7c14eSRichard Henderson             }
322459d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
322598b4e186SRichard Henderson                       allocated_regs, preferred_regs);
322659d7c14eSRichard Henderson             /* fallthrough */
322759d7c14eSRichard Henderson 
322859d7c14eSRichard Henderson         case TEMP_VAL_REG:
322959d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
323059d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
323159d7c14eSRichard Henderson             break;
323259d7c14eSRichard Henderson 
323359d7c14eSRichard Henderson         case TEMP_VAL_MEM:
323459d7c14eSRichard Henderson             break;
323559d7c14eSRichard Henderson 
323659d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
323759d7c14eSRichard Henderson         default:
323859d7c14eSRichard Henderson             tcg_abort();
3239c896fe29Sbellard         }
32407f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
32417f6ceedfSAurelien Jarno     }
324259d7c14eSRichard Henderson     if (free_or_dead) {
324359d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
324459d7c14eSRichard Henderson     }
324559d7c14eSRichard Henderson }
32467f6ceedfSAurelien Jarno 
32477f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
3248b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
32497f6ceedfSAurelien Jarno {
3250f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
3251f8b2f202SRichard Henderson     if (ts != NULL) {
325298b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
3253c896fe29Sbellard     }
3254c896fe29Sbellard }
3255c896fe29Sbellard 
3256b016486eSRichard Henderson /**
3257b016486eSRichard Henderson  * tcg_reg_alloc:
3258b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
3259b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
3260b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
3261b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
3262b016486eSRichard Henderson  *
3263b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
3264b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
3265b016486eSRichard Henderson  */
3266b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
3267b016486eSRichard Henderson                             TCGRegSet allocated_regs,
3268b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
3269c896fe29Sbellard {
3270b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
3271b016486eSRichard Henderson     TCGRegSet reg_ct[2];
327291478cefSRichard Henderson     const int *order;
3273c896fe29Sbellard 
3274b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
3275b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
3276b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
3277b016486eSRichard Henderson 
3278b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
3279b016486eSRichard Henderson        or if the preference made no difference.  */
3280b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
3281b016486eSRichard Henderson 
328291478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
3283c896fe29Sbellard 
3284b016486eSRichard Henderson     /* Try free registers, preferences first.  */
3285b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3286b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3287b016486eSRichard Henderson 
3288b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3289b016486eSRichard Henderson             /* One register in the set.  */
3290b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3291b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
3292c896fe29Sbellard                 return reg;
3293c896fe29Sbellard             }
3294b016486eSRichard Henderson         } else {
329591478cefSRichard Henderson             for (i = 0; i < n; i++) {
3296b016486eSRichard Henderson                 TCGReg reg = order[i];
3297b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
3298b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
3299b016486eSRichard Henderson                     return reg;
3300b016486eSRichard Henderson                 }
3301b016486eSRichard Henderson             }
3302b016486eSRichard Henderson         }
3303b016486eSRichard Henderson     }
3304b016486eSRichard Henderson 
3305b016486eSRichard Henderson     /* We must spill something.  */
3306b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3307b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3308b016486eSRichard Henderson 
3309b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3310b016486eSRichard Henderson             /* One register in the set.  */
3311b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3312b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
3313c896fe29Sbellard             return reg;
3314b016486eSRichard Henderson         } else {
3315b016486eSRichard Henderson             for (i = 0; i < n; i++) {
3316b016486eSRichard Henderson                 TCGReg reg = order[i];
3317b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
3318b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
3319b016486eSRichard Henderson                     return reg;
3320b016486eSRichard Henderson                 }
3321b016486eSRichard Henderson             }
3322c896fe29Sbellard         }
3323c896fe29Sbellard     }
3324c896fe29Sbellard 
3325c896fe29Sbellard     tcg_abort();
3326c896fe29Sbellard }
3327c896fe29Sbellard 
332840ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
332940ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
333040ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
3331b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
333240ae5c62SRichard Henderson {
333340ae5c62SRichard Henderson     TCGReg reg;
333440ae5c62SRichard Henderson 
333540ae5c62SRichard Henderson     switch (ts->val_type) {
333640ae5c62SRichard Henderson     case TEMP_VAL_REG:
333740ae5c62SRichard Henderson         return;
333840ae5c62SRichard Henderson     case TEMP_VAL_CONST:
3339b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3340b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
334140ae5c62SRichard Henderson         tcg_out_movi(s, ts->type, reg, ts->val);
334240ae5c62SRichard Henderson         ts->mem_coherent = 0;
334340ae5c62SRichard Henderson         break;
334440ae5c62SRichard Henderson     case TEMP_VAL_MEM:
3345b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3346b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
334740ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
334840ae5c62SRichard Henderson         ts->mem_coherent = 1;
334940ae5c62SRichard Henderson         break;
335040ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
335140ae5c62SRichard Henderson     default:
335240ae5c62SRichard Henderson         tcg_abort();
335340ae5c62SRichard Henderson     }
335440ae5c62SRichard Henderson     ts->reg = reg;
335540ae5c62SRichard Henderson     ts->val_type = TEMP_VAL_REG;
335640ae5c62SRichard Henderson     s->reg_to_temp[reg] = ts;
335740ae5c62SRichard Henderson }
335840ae5c62SRichard Henderson 
335959d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
3360e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
336159d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
33621ad80729SAurelien Jarno {
33632c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
3364eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
3365f8bf00f1SRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg);
33661ad80729SAurelien Jarno }
33671ad80729SAurelien Jarno 
33689814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
3369641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
3370641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
3371641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
3372641d5fbeSbellard {
3373ac3b8891SRichard Henderson     int i, n;
3374641d5fbeSbellard 
3375ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
3376b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
3377641d5fbeSbellard     }
3378e5097dc8Sbellard }
3379e5097dc8Sbellard 
33803d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
33813d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
33823d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
33833d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
33843d5c5f87SAurelien Jarno {
3385ac3b8891SRichard Henderson     int i, n;
33863d5c5f87SAurelien Jarno 
3387ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
338812b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
338912b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
339012b9b11aSRichard Henderson                          || ts->fixed_reg
339112b9b11aSRichard Henderson                          || ts->mem_coherent);
33923d5c5f87SAurelien Jarno     }
33933d5c5f87SAurelien Jarno }
33943d5c5f87SAurelien Jarno 
3395e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
3396e8996ee0Sbellard    all globals are stored at their canonical location. */
3397e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
3398e5097dc8Sbellard {
3399e5097dc8Sbellard     int i;
3400e5097dc8Sbellard 
3401c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
3402b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
3403641d5fbeSbellard         if (ts->temp_local) {
3404b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
3405641d5fbeSbellard         } else {
34062c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
3407eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
3408eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3409c896fe29Sbellard         }
3410641d5fbeSbellard     }
3411e8996ee0Sbellard 
3412e8996ee0Sbellard     save_globals(s, allocated_regs);
3413c896fe29Sbellard }
3414c896fe29Sbellard 
3415bab1671fSRichard Henderson /*
3416b4cb76e6SRichard Henderson  * At a conditional branch, we assume all temporaries are dead and
3417b4cb76e6SRichard Henderson  * all globals and local temps are synced to their location.
3418b4cb76e6SRichard Henderson  */
3419b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
3420b4cb76e6SRichard Henderson {
3421b4cb76e6SRichard Henderson     sync_globals(s, allocated_regs);
3422b4cb76e6SRichard Henderson 
3423b4cb76e6SRichard Henderson     for (int i = s->nb_globals; i < s->nb_temps; i++) {
3424b4cb76e6SRichard Henderson         TCGTemp *ts = &s->temps[i];
3425b4cb76e6SRichard Henderson         /*
3426b4cb76e6SRichard Henderson          * The liveness analysis already ensures that temps are dead.
3427b4cb76e6SRichard Henderson          * Keep tcg_debug_asserts for safety.
3428b4cb76e6SRichard Henderson          */
3429b4cb76e6SRichard Henderson         if (ts->temp_local) {
3430b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
3431b4cb76e6SRichard Henderson         } else {
3432b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3433b4cb76e6SRichard Henderson         }
3434b4cb76e6SRichard Henderson     }
3435b4cb76e6SRichard Henderson }
3436b4cb76e6SRichard Henderson 
3437b4cb76e6SRichard Henderson /*
3438bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_movi_*.
3439bab1671fSRichard Henderson  */
34400fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
3441ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
3442ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
3443e8996ee0Sbellard {
3444d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3445d63e3b6eSRichard Henderson     tcg_debug_assert(!ots->fixed_reg);
344659d7c14eSRichard Henderson 
344759d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
3448f8b2f202SRichard Henderson     if (ots->val_type == TEMP_VAL_REG) {
3449f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = NULL;
3450f8b2f202SRichard Henderson     }
3451e8996ee0Sbellard     ots->val_type = TEMP_VAL_CONST;
3452e8996ee0Sbellard     ots->val = val;
345359d7c14eSRichard Henderson     ots->mem_coherent = 0;
3454ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
3455ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
345659d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
3457f8bf00f1SRichard Henderson         temp_dead(s, ots);
34584c4e1ab2SAurelien Jarno     }
3459e8996ee0Sbellard }
3460e8996ee0Sbellard 
3461dd186292SRichard Henderson static void tcg_reg_alloc_movi(TCGContext *s, const TCGOp *op)
34620fe4fca4SPaolo Bonzini {
346343439139SRichard Henderson     TCGTemp *ots = arg_temp(op->args[0]);
3464dd186292SRichard Henderson     tcg_target_ulong val = op->args[1];
34650fe4fca4SPaolo Bonzini 
346669e3706dSRichard Henderson     tcg_reg_alloc_do_movi(s, ots, val, op->life, op->output_pref[0]);
34670fe4fca4SPaolo Bonzini }
34680fe4fca4SPaolo Bonzini 
3469bab1671fSRichard Henderson /*
3470bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
3471bab1671fSRichard Henderson  */
3472dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
3473c896fe29Sbellard {
3474dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
347569e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
3476c896fe29Sbellard     TCGTemp *ts, *ots;
3477450445d5SRichard Henderson     TCGType otype, itype;
3478c896fe29Sbellard 
3479d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
348069e3706dSRichard Henderson     preferred_regs = op->output_pref[0];
348143439139SRichard Henderson     ots = arg_temp(op->args[0]);
348243439139SRichard Henderson     ts = arg_temp(op->args[1]);
3483450445d5SRichard Henderson 
3484d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3485d63e3b6eSRichard Henderson     tcg_debug_assert(!ots->fixed_reg);
3486d63e3b6eSRichard Henderson 
3487450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
3488450445d5SRichard Henderson     otype = ots->type;
3489450445d5SRichard Henderson     itype = ts->type;
3490c896fe29Sbellard 
34910fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
34920fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
34930fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
34940fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
34950fe4fca4SPaolo Bonzini             temp_dead(s, ts);
34960fe4fca4SPaolo Bonzini         }
349769e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
34980fe4fca4SPaolo Bonzini         return;
34990fe4fca4SPaolo Bonzini     }
35000fe4fca4SPaolo Bonzini 
35010fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
35020fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
35030fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
35040fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
35050fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
350669e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
350769e3706dSRichard Henderson                   allocated_regs, preferred_regs);
3508c29c1d7eSAurelien Jarno     }
3509c29c1d7eSAurelien Jarno 
35100fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
3511d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
3512c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
3513c29c1d7eSAurelien Jarno            liveness analysis disabled). */
3514eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
3515c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
35162272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
3517c29c1d7eSAurelien Jarno         }
3518b3a62939SRichard Henderson         tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset);
3519c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
3520f8bf00f1SRichard Henderson             temp_dead(s, ts);
3521c29c1d7eSAurelien Jarno         }
3522f8bf00f1SRichard Henderson         temp_dead(s, ots);
3523e8996ee0Sbellard     } else {
3524d63e3b6eSRichard Henderson         if (IS_DEAD_ARG(1) && !ts->fixed_reg) {
3525c29c1d7eSAurelien Jarno             /* the mov can be suppressed */
3526c29c1d7eSAurelien Jarno             if (ots->val_type == TEMP_VAL_REG) {
3527f8b2f202SRichard Henderson                 s->reg_to_temp[ots->reg] = NULL;
3528c896fe29Sbellard             }
3529c29c1d7eSAurelien Jarno             ots->reg = ts->reg;
3530f8bf00f1SRichard Henderson             temp_dead(s, ts);
3531c29c1d7eSAurelien Jarno         } else {
3532c29c1d7eSAurelien Jarno             if (ots->val_type != TEMP_VAL_REG) {
3533c29c1d7eSAurelien Jarno                 /* When allocating a new register, make sure to not spill the
3534c29c1d7eSAurelien Jarno                    input one. */
3535c29c1d7eSAurelien Jarno                 tcg_regset_set_reg(allocated_regs, ts->reg);
3536450445d5SRichard Henderson                 ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
353769e3706dSRichard Henderson                                          allocated_regs, preferred_regs,
3538b016486eSRichard Henderson                                          ots->indirect_base);
3539c29c1d7eSAurelien Jarno             }
354078113e83SRichard Henderson             if (!tcg_out_mov(s, otype, ots->reg, ts->reg)) {
3541240c08d0SRichard Henderson                 /*
3542240c08d0SRichard Henderson                  * Cross register class move not supported.
3543240c08d0SRichard Henderson                  * Store the source register into the destination slot
3544240c08d0SRichard Henderson                  * and leave the destination temp as TEMP_VAL_MEM.
3545240c08d0SRichard Henderson                  */
3546240c08d0SRichard Henderson                 assert(!ots->fixed_reg);
3547240c08d0SRichard Henderson                 if (!ts->mem_allocated) {
3548240c08d0SRichard Henderson                     temp_allocate_frame(s, ots);
3549240c08d0SRichard Henderson                 }
3550240c08d0SRichard Henderson                 tcg_out_st(s, ts->type, ts->reg,
3551240c08d0SRichard Henderson                            ots->mem_base->reg, ots->mem_offset);
3552240c08d0SRichard Henderson                 ots->mem_coherent = 1;
3553240c08d0SRichard Henderson                 temp_free_or_dead(s, ots, -1);
3554240c08d0SRichard Henderson                 return;
355578113e83SRichard Henderson             }
3556c29c1d7eSAurelien Jarno         }
3557c896fe29Sbellard         ots->val_type = TEMP_VAL_REG;
3558c896fe29Sbellard         ots->mem_coherent = 0;
3559f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3560ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(0)) {
356198b4e186SRichard Henderson             temp_sync(s, ots, allocated_regs, 0, 0);
3562c29c1d7eSAurelien Jarno         }
3563ec7a869dSAurelien Jarno     }
3564c896fe29Sbellard }
3565c896fe29Sbellard 
3566bab1671fSRichard Henderson /*
3567bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
3568bab1671fSRichard Henderson  */
3569bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
3570bab1671fSRichard Henderson {
3571bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
3572bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
3573bab1671fSRichard Henderson     TCGTemp *its, *ots;
3574bab1671fSRichard Henderson     TCGType itype, vtype;
3575d6ecb4a9SRichard Henderson     intptr_t endian_fixup;
3576bab1671fSRichard Henderson     unsigned vece;
3577bab1671fSRichard Henderson     bool ok;
3578bab1671fSRichard Henderson 
3579bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
3580bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
3581bab1671fSRichard Henderson 
3582bab1671fSRichard Henderson     /* ENV should not be modified.  */
3583bab1671fSRichard Henderson     tcg_debug_assert(!ots->fixed_reg);
3584bab1671fSRichard Henderson 
3585bab1671fSRichard Henderson     itype = its->type;
3586bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
3587bab1671fSRichard Henderson     vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
3588bab1671fSRichard Henderson 
3589bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
3590bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
3591bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
3592bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
3593bab1671fSRichard Henderson             temp_dead(s, its);
3594bab1671fSRichard Henderson         }
3595bab1671fSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, op->output_pref[0]);
3596bab1671fSRichard Henderson         return;
3597bab1671fSRichard Henderson     }
3598bab1671fSRichard Henderson 
35999be0d080SRichard Henderson     dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
36009be0d080SRichard Henderson     dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs;
3601bab1671fSRichard Henderson 
3602bab1671fSRichard Henderson     /* Allocate the output register now.  */
3603bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
3604bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
3605bab1671fSRichard Henderson 
3606bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
3607bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
3608bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
3609bab1671fSRichard Henderson         }
3610bab1671fSRichard Henderson         ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
3611bab1671fSRichard Henderson                                  op->output_pref[0], ots->indirect_base);
3612bab1671fSRichard Henderson         ots->val_type = TEMP_VAL_REG;
3613bab1671fSRichard Henderson         ots->mem_coherent = 0;
3614bab1671fSRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3615bab1671fSRichard Henderson     }
3616bab1671fSRichard Henderson 
3617bab1671fSRichard Henderson     switch (its->val_type) {
3618bab1671fSRichard Henderson     case TEMP_VAL_REG:
3619bab1671fSRichard Henderson         /*
3620bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
3621bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
3622bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
3623bab1671fSRichard Henderson          */
3624bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
3625bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
3626bab1671fSRichard Henderson                 goto done;
3627bab1671fSRichard Henderson             }
3628bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
3629bab1671fSRichard Henderson         }
3630bab1671fSRichard Henderson         if (!its->mem_coherent) {
3631bab1671fSRichard Henderson             /*
3632bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
3633bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
3634bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
3635bab1671fSRichard Henderson              */
3636bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
3637bab1671fSRichard Henderson                 break;
3638bab1671fSRichard Henderson             }
3639bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
3640bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
3641bab1671fSRichard Henderson         }
3642bab1671fSRichard Henderson         /* fall through */
3643bab1671fSRichard Henderson 
3644bab1671fSRichard Henderson     case TEMP_VAL_MEM:
3645d6ecb4a9SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
3646d6ecb4a9SRichard Henderson         endian_fixup = itype == TCG_TYPE_I32 ? 4 : 8;
3647d6ecb4a9SRichard Henderson         endian_fixup -= 1 << vece;
3648d6ecb4a9SRichard Henderson #else
3649d6ecb4a9SRichard Henderson         endian_fixup = 0;
3650d6ecb4a9SRichard Henderson #endif
3651d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
3652d6ecb4a9SRichard Henderson                              its->mem_offset + endian_fixup)) {
3653d6ecb4a9SRichard Henderson             goto done;
3654d6ecb4a9SRichard Henderson         }
3655bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
3656bab1671fSRichard Henderson         break;
3657bab1671fSRichard Henderson 
3658bab1671fSRichard Henderson     default:
3659bab1671fSRichard Henderson         g_assert_not_reached();
3660bab1671fSRichard Henderson     }
3661bab1671fSRichard Henderson 
3662bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
3663bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
3664bab1671fSRichard Henderson     tcg_debug_assert(ok);
3665bab1671fSRichard Henderson 
3666bab1671fSRichard Henderson  done:
3667bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
3668bab1671fSRichard Henderson         temp_dead(s, its);
3669bab1671fSRichard Henderson     }
3670bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
3671bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
3672bab1671fSRichard Henderson     }
3673bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
3674bab1671fSRichard Henderson         temp_dead(s, ots);
3675bab1671fSRichard Henderson     }
3676bab1671fSRichard Henderson }
3677bab1671fSRichard Henderson 
3678dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
3679c896fe29Sbellard {
3680dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3681dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
368282790a87SRichard Henderson     TCGRegSet i_allocated_regs;
368382790a87SRichard Henderson     TCGRegSet o_allocated_regs;
3684b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
3685b6638662SRichard Henderson     TCGReg reg;
3686c896fe29Sbellard     TCGArg arg;
3687c896fe29Sbellard     const TCGArgConstraint *arg_ct;
3688c896fe29Sbellard     TCGTemp *ts;
3689c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
3690c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
3691c896fe29Sbellard 
3692c896fe29Sbellard     nb_oargs = def->nb_oargs;
3693c896fe29Sbellard     nb_iargs = def->nb_iargs;
3694c896fe29Sbellard 
3695c896fe29Sbellard     /* copy constants */
3696c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
3697dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
3698c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
3699c896fe29Sbellard 
3700d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
3701d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
370282790a87SRichard Henderson 
3703c896fe29Sbellard     /* satisfy input constraints */
3704c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
3705d62816f2SRichard Henderson         TCGRegSet i_preferred_regs, o_preferred_regs;
3706d62816f2SRichard Henderson 
370766792f90SRichard Henderson         i = def->args_ct[nb_oargs + k].sort_index;
3708dd186292SRichard Henderson         arg = op->args[i];
3709c896fe29Sbellard         arg_ct = &def->args_ct[i];
371043439139SRichard Henderson         ts = arg_temp(arg);
371140ae5c62SRichard Henderson 
371240ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
371340ae5c62SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct)) {
3714c896fe29Sbellard             /* constant is OK for instruction */
3715c896fe29Sbellard             const_args[i] = 1;
3716c896fe29Sbellard             new_args[i] = ts->val;
3717d62816f2SRichard Henderson             continue;
3718c896fe29Sbellard         }
371940ae5c62SRichard Henderson 
3720d62816f2SRichard Henderson         i_preferred_regs = o_preferred_regs = 0;
3721bc2b17e6SRichard Henderson         if (arg_ct->ialias) {
3722d62816f2SRichard Henderson             o_preferred_regs = op->output_pref[arg_ct->alias_index];
37235ff9d6a4Sbellard             if (ts->fixed_reg) {
37245ff9d6a4Sbellard                 /* if fixed register, we must allocate a new register
37255ff9d6a4Sbellard                    if the alias is not the same register */
3726d62816f2SRichard Henderson                 if (arg != op->args[arg_ct->alias_index]) {
37275ff9d6a4Sbellard                     goto allocate_in_reg;
3728d62816f2SRichard Henderson                 }
37295ff9d6a4Sbellard             } else {
3730c896fe29Sbellard                 /* if the input is aliased to an output and if it is
3731c896fe29Sbellard                    not dead after the instruction, we must allocate
3732c896fe29Sbellard                    a new register and move it */
3733866cb6cbSAurelien Jarno                 if (!IS_DEAD_ARG(i)) {
3734c896fe29Sbellard                     goto allocate_in_reg;
3735c896fe29Sbellard                 }
3736d62816f2SRichard Henderson 
37377e1df267SAurelien Jarno                 /* check if the current register has already been allocated
37387e1df267SAurelien Jarno                    for another input aliased to an output */
3739d62816f2SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG) {
37407e1df267SAurelien Jarno                     int k2, i2;
3741d62816f2SRichard Henderson                     reg = ts->reg;
37427e1df267SAurelien Jarno                     for (k2 = 0 ; k2 < k ; k2++) {
374366792f90SRichard Henderson                         i2 = def->args_ct[nb_oargs + k2].sort_index;
3744bc2b17e6SRichard Henderson                         if (def->args_ct[i2].ialias && reg == new_args[i2]) {
37457e1df267SAurelien Jarno                             goto allocate_in_reg;
37467e1df267SAurelien Jarno                         }
37477e1df267SAurelien Jarno                     }
37485ff9d6a4Sbellard                 }
3749d62816f2SRichard Henderson                 i_preferred_regs = o_preferred_regs;
3750866cb6cbSAurelien Jarno             }
3751d62816f2SRichard Henderson         }
3752d62816f2SRichard Henderson 
37539be0d080SRichard Henderson         temp_load(s, ts, arg_ct->regs, i_allocated_regs, i_preferred_regs);
3754c896fe29Sbellard         reg = ts->reg;
3755d62816f2SRichard Henderson 
37569be0d080SRichard Henderson         if (tcg_regset_test_reg(arg_ct->regs, reg)) {
3757c896fe29Sbellard             /* nothing to do : the constraint is satisfied */
3758c896fe29Sbellard         } else {
3759c896fe29Sbellard         allocate_in_reg:
3760c896fe29Sbellard             /* allocate a new register matching the constraint
3761c896fe29Sbellard                and move the temporary register into it */
3762d62816f2SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
3763d62816f2SRichard Henderson                       i_allocated_regs, 0);
37649be0d080SRichard Henderson             reg = tcg_reg_alloc(s, arg_ct->regs, i_allocated_regs,
3765d62816f2SRichard Henderson                                 o_preferred_regs, ts->indirect_base);
376678113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
3767240c08d0SRichard Henderson                 /*
3768240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
3769240c08d0SRichard Henderson                  * temp back to its slot and load from there.
3770240c08d0SRichard Henderson                  */
3771240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
3772240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
3773240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
377478113e83SRichard Henderson             }
3775c896fe29Sbellard         }
3776c896fe29Sbellard         new_args[i] = reg;
3777c896fe29Sbellard         const_args[i] = 0;
377882790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
3779c896fe29Sbellard     }
3780c896fe29Sbellard 
3781c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
3782866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
3783866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
378443439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
3785c896fe29Sbellard         }
3786c896fe29Sbellard     }
3787c896fe29Sbellard 
3788b4cb76e6SRichard Henderson     if (def->flags & TCG_OPF_COND_BRANCH) {
3789b4cb76e6SRichard Henderson         tcg_reg_alloc_cbranch(s, i_allocated_regs);
3790b4cb76e6SRichard Henderson     } else if (def->flags & TCG_OPF_BB_END) {
379182790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
3792a52ad07eSAurelien Jarno     } else {
3793c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
3794b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
3795c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
3796c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
379782790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
3798c896fe29Sbellard                 }
3799c896fe29Sbellard             }
38003d5c5f87SAurelien Jarno         }
38013d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
38023d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
38033d5c5f87SAurelien Jarno                an exception. */
380482790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
3805c896fe29Sbellard         }
3806c896fe29Sbellard 
3807c896fe29Sbellard         /* satisfy the output constraints */
3808c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
380966792f90SRichard Henderson             i = def->args_ct[k].sort_index;
3810dd186292SRichard Henderson             arg = op->args[i];
3811c896fe29Sbellard             arg_ct = &def->args_ct[i];
381243439139SRichard Henderson             ts = arg_temp(arg);
3813d63e3b6eSRichard Henderson 
3814d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
3815d63e3b6eSRichard Henderson             tcg_debug_assert(!ts->fixed_reg);
3816d63e3b6eSRichard Henderson 
3817bc2b17e6SRichard Henderson             if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
38185ff9d6a4Sbellard                 reg = new_args[arg_ct->alias_index];
3819bc2b17e6SRichard Henderson             } else if (arg_ct->newreg) {
38209be0d080SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->regs,
382182790a87SRichard Henderson                                     i_allocated_regs | o_allocated_regs,
382269e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
3823c896fe29Sbellard             } else {
38249be0d080SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
382569e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
3826c896fe29Sbellard             }
382782790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
3828639368ddSAurelien Jarno             if (ts->val_type == TEMP_VAL_REG) {
3829f8b2f202SRichard Henderson                 s->reg_to_temp[ts->reg] = NULL;
3830639368ddSAurelien Jarno             }
3831c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
3832c896fe29Sbellard             ts->reg = reg;
3833d63e3b6eSRichard Henderson             /*
3834d63e3b6eSRichard Henderson              * Temp value is modified, so the value kept in memory is
3835d63e3b6eSRichard Henderson              * potentially not the same.
3836d63e3b6eSRichard Henderson              */
3837c896fe29Sbellard             ts->mem_coherent = 0;
3838f8b2f202SRichard Henderson             s->reg_to_temp[reg] = ts;
3839c896fe29Sbellard             new_args[i] = reg;
3840c896fe29Sbellard         }
3841e8996ee0Sbellard     }
3842c896fe29Sbellard 
3843c896fe29Sbellard     /* emit instruction */
3844d2fd745fSRichard Henderson     if (def->flags & TCG_OPF_VECTOR) {
3845d2fd745fSRichard Henderson         tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
3846d2fd745fSRichard Henderson                        new_args, const_args);
3847d2fd745fSRichard Henderson     } else {
3848dd186292SRichard Henderson         tcg_out_op(s, op->opc, new_args, const_args);
3849d2fd745fSRichard Henderson     }
3850c896fe29Sbellard 
3851c896fe29Sbellard     /* move the outputs in the correct register if needed */
3852c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
385343439139SRichard Henderson         ts = arg_temp(op->args[i]);
3854d63e3b6eSRichard Henderson 
3855d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
3856d63e3b6eSRichard Henderson         tcg_debug_assert(!ts->fixed_reg);
3857d63e3b6eSRichard Henderson 
3858ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
385998b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
386059d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
3861f8bf00f1SRichard Henderson             temp_dead(s, ts);
3862ec7a869dSAurelien Jarno         }
3863c896fe29Sbellard     }
3864c896fe29Sbellard }
3865c896fe29Sbellard 
3866b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP
3867b03cce8eSbellard #define STACK_DIR(x) (-(x))
3868b03cce8eSbellard #else
3869b03cce8eSbellard #define STACK_DIR(x) (x)
3870b03cce8eSbellard #endif
3871b03cce8eSbellard 
3872dd186292SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
3873c896fe29Sbellard {
3874cd9090aaSRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
3875cd9090aaSRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
3876dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3877b6638662SRichard Henderson     int flags, nb_regs, i;
3878b6638662SRichard Henderson     TCGReg reg;
3879cf066674SRichard Henderson     TCGArg arg;
3880c896fe29Sbellard     TCGTemp *ts;
3881d3452f1fSRichard Henderson     intptr_t stack_offset;
3882d3452f1fSRichard Henderson     size_t call_stack_size;
3883cf066674SRichard Henderson     tcg_insn_unit *func_addr;
3884cf066674SRichard Henderson     int allocate_args;
3885c896fe29Sbellard     TCGRegSet allocated_regs;
3886c896fe29Sbellard 
3887dd186292SRichard Henderson     func_addr = (tcg_insn_unit *)(intptr_t)op->args[nb_oargs + nb_iargs];
3888dd186292SRichard Henderson     flags = op->args[nb_oargs + nb_iargs + 1];
3889c896fe29Sbellard 
38906e17d0c5SStefan Weil     nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
3891c45cb8bbSRichard Henderson     if (nb_regs > nb_iargs) {
3892c45cb8bbSRichard Henderson         nb_regs = nb_iargs;
3893cf066674SRichard Henderson     }
3894c896fe29Sbellard 
3895c896fe29Sbellard     /* assign stack slots first */
3896c45cb8bbSRichard Henderson     call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long);
3897c896fe29Sbellard     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
3898c896fe29Sbellard         ~(TCG_TARGET_STACK_ALIGN - 1);
3899b03cce8eSbellard     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
3900b03cce8eSbellard     if (allocate_args) {
3901345649c0SBlue Swirl         /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
3902345649c0SBlue Swirl            preallocate call stack */
3903345649c0SBlue Swirl         tcg_abort();
3904b03cce8eSbellard     }
390539cf05d3Sbellard 
390639cf05d3Sbellard     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
3907c45cb8bbSRichard Henderson     for (i = nb_regs; i < nb_iargs; i++) {
3908dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
390939cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP
391039cf05d3Sbellard         stack_offset -= sizeof(tcg_target_long);
391139cf05d3Sbellard #endif
391239cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
391343439139SRichard Henderson             ts = arg_temp(arg);
391440ae5c62SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
3915b722452aSRichard Henderson                       s->reserved_regs, 0);
3916e4d5434cSblueswir1             tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
391739cf05d3Sbellard         }
391839cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP
391939cf05d3Sbellard         stack_offset += sizeof(tcg_target_long);
392039cf05d3Sbellard #endif
3921c896fe29Sbellard     }
3922c896fe29Sbellard 
3923c896fe29Sbellard     /* assign input registers */
3924d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
3925c896fe29Sbellard     for (i = 0; i < nb_regs; i++) {
3926dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
392739cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
392843439139SRichard Henderson             ts = arg_temp(arg);
3929c896fe29Sbellard             reg = tcg_target_call_iarg_regs[i];
393040ae5c62SRichard Henderson 
3931c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
3932c896fe29Sbellard                 if (ts->reg != reg) {
39334250da10SRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
393478113e83SRichard Henderson                     if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
3935240c08d0SRichard Henderson                         /*
3936240c08d0SRichard Henderson                          * Cross register class move not supported.  Sync the
3937240c08d0SRichard Henderson                          * temp back to its slot and load from there.
3938240c08d0SRichard Henderson                          */
3939240c08d0SRichard Henderson                         temp_sync(s, ts, allocated_regs, 0, 0);
3940240c08d0SRichard Henderson                         tcg_out_ld(s, ts->type, reg,
3941240c08d0SRichard Henderson                                    ts->mem_base->reg, ts->mem_offset);
394278113e83SRichard Henderson                     }
3943c896fe29Sbellard                 }
3944c896fe29Sbellard             } else {
3945ccb1bb66SRichard Henderson                 TCGRegSet arg_set = 0;
394640ae5c62SRichard Henderson 
39474250da10SRichard Henderson                 tcg_reg_free(s, reg, allocated_regs);
394840ae5c62SRichard Henderson                 tcg_regset_set_reg(arg_set, reg);
3949b722452aSRichard Henderson                 temp_load(s, ts, arg_set, allocated_regs, 0);
3950c896fe29Sbellard             }
395140ae5c62SRichard Henderson 
3952c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
3953c896fe29Sbellard         }
395439cf05d3Sbellard     }
3955c896fe29Sbellard 
3956c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
3957866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3958866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
395943439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
3960c896fe29Sbellard         }
3961c896fe29Sbellard     }
3962c896fe29Sbellard 
3963c896fe29Sbellard     /* clobber call registers */
3964c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
3965c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
3966b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
3967c896fe29Sbellard         }
3968c896fe29Sbellard     }
3969c896fe29Sbellard 
397078505279SAurelien Jarno     /* Save globals if they might be written by the helper, sync them if
397178505279SAurelien Jarno        they might be read. */
397278505279SAurelien Jarno     if (flags & TCG_CALL_NO_READ_GLOBALS) {
397378505279SAurelien Jarno         /* Nothing to do */
397478505279SAurelien Jarno     } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) {
397578505279SAurelien Jarno         sync_globals(s, allocated_regs);
397678505279SAurelien Jarno     } else {
3977e8996ee0Sbellard         save_globals(s, allocated_regs);
3978b9c18f56Saurel32     }
3979c896fe29Sbellard 
3980cf066674SRichard Henderson     tcg_out_call(s, func_addr);
3981c896fe29Sbellard 
3982c896fe29Sbellard     /* assign output registers and emit moves if needed */
3983c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
3984dd186292SRichard Henderson         arg = op->args[i];
398543439139SRichard Henderson         ts = arg_temp(arg);
3986d63e3b6eSRichard Henderson 
3987d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
3988d63e3b6eSRichard Henderson         tcg_debug_assert(!ts->fixed_reg);
3989d63e3b6eSRichard Henderson 
3990c896fe29Sbellard         reg = tcg_target_call_oarg_regs[i];
3991eabb7b91SAurelien Jarno         tcg_debug_assert(s->reg_to_temp[reg] == NULL);
3992639368ddSAurelien Jarno         if (ts->val_type == TEMP_VAL_REG) {
3993f8b2f202SRichard Henderson             s->reg_to_temp[ts->reg] = NULL;
3994639368ddSAurelien Jarno         }
3995c896fe29Sbellard         ts->val_type = TEMP_VAL_REG;
3996c896fe29Sbellard         ts->reg = reg;
3997c896fe29Sbellard         ts->mem_coherent = 0;
3998f8b2f202SRichard Henderson         s->reg_to_temp[reg] = ts;
3999ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
400098b4e186SRichard Henderson             temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i));
400159d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4002f8bf00f1SRichard Henderson             temp_dead(s, ts);
4003c896fe29Sbellard         }
4004c896fe29Sbellard     }
40058c11ad25SAurelien Jarno }
4006c896fe29Sbellard 
4007c896fe29Sbellard #ifdef CONFIG_PROFILER
4008c896fe29Sbellard 
4009c3fac113SEmilio G. Cota /* avoid copy/paste errors */
4010c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field)                       \
4011c3fac113SEmilio G. Cota     do {                                                \
4012d73415a3SStefan Hajnoczi         (to)->field += qatomic_read(&((from)->field));  \
4013c3fac113SEmilio G. Cota     } while (0)
4014c896fe29Sbellard 
4015c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field)                                       \
4016c3fac113SEmilio G. Cota     do {                                                                \
4017d73415a3SStefan Hajnoczi         typeof((from)->field) val__ = qatomic_read(&((from)->field));   \
4018c3fac113SEmilio G. Cota         if (val__ > (to)->field) {                                      \
4019c3fac113SEmilio G. Cota             (to)->field = val__;                                        \
4020c3fac113SEmilio G. Cota         }                                                               \
4021c3fac113SEmilio G. Cota     } while (0)
4022c3fac113SEmilio G. Cota 
4023c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */
4024c3fac113SEmilio G. Cota static inline
4025c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
4026c896fe29Sbellard {
4027d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
4028c3fac113SEmilio G. Cota     unsigned int i;
4029c3fac113SEmilio G. Cota 
40303468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4031d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
40323468b59eSEmilio G. Cota         const TCGProfile *orig = &s->prof;
4033c3fac113SEmilio G. Cota 
4034c3fac113SEmilio G. Cota         if (counters) {
403572fd2efbSEmilio G. Cota             PROF_ADD(prof, orig, cpu_exec_time);
4036c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count1);
4037c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count);
4038c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, op_count);
4039c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, op_count_max);
4040c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, temp_count);
4041c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, temp_count_max);
4042c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, del_op_count);
4043c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_in_len);
4044c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_out_len);
4045c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, search_out_len);
4046c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, interm_time);
4047c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_time);
4048c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, la_time);
4049c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, opt_time);
4050c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_count);
4051c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_time);
4052c3fac113SEmilio G. Cota         }
4053c3fac113SEmilio G. Cota         if (table) {
4054c896fe29Sbellard             int i;
4055d70724ceSzhanghailiang 
405615fc7daaSRichard Henderson             for (i = 0; i < NB_OPS; i++) {
4057c3fac113SEmilio G. Cota                 PROF_ADD(prof, orig, table_op_count[i]);
4058c3fac113SEmilio G. Cota             }
4059c3fac113SEmilio G. Cota         }
4060c3fac113SEmilio G. Cota     }
4061c3fac113SEmilio G. Cota }
4062c3fac113SEmilio G. Cota 
4063c3fac113SEmilio G. Cota #undef PROF_ADD
4064c3fac113SEmilio G. Cota #undef PROF_MAX
4065c3fac113SEmilio G. Cota 
4066c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof)
4067c3fac113SEmilio G. Cota {
4068c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, true, false);
4069c3fac113SEmilio G. Cota }
4070c3fac113SEmilio G. Cota 
4071c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof)
4072c3fac113SEmilio G. Cota {
4073c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, false, true);
4074c3fac113SEmilio G. Cota }
4075c3fac113SEmilio G. Cota 
4076d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
4077c3fac113SEmilio G. Cota {
4078c3fac113SEmilio G. Cota     TCGProfile prof = {};
4079c3fac113SEmilio G. Cota     int i;
4080c3fac113SEmilio G. Cota 
4081c3fac113SEmilio G. Cota     tcg_profile_snapshot_table(&prof);
4082c3fac113SEmilio G. Cota     for (i = 0; i < NB_OPS; i++) {
4083d4c51a0aSMarkus Armbruster         qemu_printf("%s %" PRId64 "\n", tcg_op_defs[i].name,
4084c3fac113SEmilio G. Cota                     prof.table_op_count[i]);
4085c896fe29Sbellard     }
4086c896fe29Sbellard }
408772fd2efbSEmilio G. Cota 
408872fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
408972fd2efbSEmilio G. Cota {
4090d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
409172fd2efbSEmilio G. Cota     unsigned int i;
409272fd2efbSEmilio G. Cota     int64_t ret = 0;
409372fd2efbSEmilio G. Cota 
409472fd2efbSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4095d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
409672fd2efbSEmilio G. Cota         const TCGProfile *prof = &s->prof;
409772fd2efbSEmilio G. Cota 
4098d73415a3SStefan Hajnoczi         ret += qatomic_read(&prof->cpu_exec_time);
409972fd2efbSEmilio G. Cota     }
410072fd2efbSEmilio G. Cota     return ret;
410172fd2efbSEmilio G. Cota }
4102246ae24dSMax Filippov #else
4103d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
4104246ae24dSMax Filippov {
4105d4c51a0aSMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4106246ae24dSMax Filippov }
410772fd2efbSEmilio G. Cota 
410872fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
410972fd2efbSEmilio G. Cota {
411072fd2efbSEmilio G. Cota     error_report("%s: TCG profiler not compiled", __func__);
411172fd2efbSEmilio G. Cota     exit(EXIT_FAILURE);
411272fd2efbSEmilio G. Cota }
4113c896fe29Sbellard #endif
4114c896fe29Sbellard 
4115c896fe29Sbellard 
41165bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
4117c896fe29Sbellard {
4118c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER
4119c3fac113SEmilio G. Cota     TCGProfile *prof = &s->prof;
4120c3fac113SEmilio G. Cota #endif
412115fa08f8SRichard Henderson     int i, num_insns;
412215fa08f8SRichard Henderson     TCGOp *op;
4123c896fe29Sbellard 
412404fe6400SRichard Henderson #ifdef CONFIG_PROFILER
412504fe6400SRichard Henderson     {
4126c1f543b7SEmilio G. Cota         int n = 0;
412704fe6400SRichard Henderson 
412815fa08f8SRichard Henderson         QTAILQ_FOREACH(op, &s->ops, link) {
412915fa08f8SRichard Henderson             n++;
413015fa08f8SRichard Henderson         }
4131d73415a3SStefan Hajnoczi         qatomic_set(&prof->op_count, prof->op_count + n);
4132c3fac113SEmilio G. Cota         if (n > prof->op_count_max) {
4133d73415a3SStefan Hajnoczi             qatomic_set(&prof->op_count_max, n);
413404fe6400SRichard Henderson         }
413504fe6400SRichard Henderson 
413604fe6400SRichard Henderson         n = s->nb_temps;
4137d73415a3SStefan Hajnoczi         qatomic_set(&prof->temp_count, prof->temp_count + n);
4138c3fac113SEmilio G. Cota         if (n > prof->temp_count_max) {
4139d73415a3SStefan Hajnoczi             qatomic_set(&prof->temp_count_max, n);
414004fe6400SRichard Henderson         }
414104fe6400SRichard Henderson     }
414204fe6400SRichard Henderson #endif
414304fe6400SRichard Henderson 
4144c896fe29Sbellard #ifdef DEBUG_DISAS
4145d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
4146d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
4147fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
414893fcfe39Saliguori         qemu_log("OP:\n");
41491894f69aSRichard Henderson         tcg_dump_ops(s, false);
415093fcfe39Saliguori         qemu_log("\n");
4151fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
4152c896fe29Sbellard     }
4153c896fe29Sbellard #endif
4154c896fe29Sbellard 
4155bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
4156bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
4157bef16ab4SRichard Henderson     {
4158bef16ab4SRichard Henderson         TCGLabel *l;
4159bef16ab4SRichard Henderson         bool error = false;
4160bef16ab4SRichard Henderson 
4161bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
4162bef16ab4SRichard Henderson             if (unlikely(!l->present) && l->refs) {
4163bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
4164bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
4165bef16ab4SRichard Henderson                 error = true;
4166bef16ab4SRichard Henderson             }
4167bef16ab4SRichard Henderson         }
4168bef16ab4SRichard Henderson         assert(!error);
4169bef16ab4SRichard Henderson     }
4170bef16ab4SRichard Henderson #endif
4171bef16ab4SRichard Henderson 
4172c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
4173d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
4174c5cc28ffSAurelien Jarno #endif
4175c5cc28ffSAurelien Jarno 
41768f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
4177c45cb8bbSRichard Henderson     tcg_optimize(s);
41788f2e8c07SKirill Batuzov #endif
41798f2e8c07SKirill Batuzov 
4180a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4181d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
4182d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time - profile_getclock());
4183a23a9ec6Sbellard #endif
4184c5cc28ffSAurelien Jarno 
4185b4fc67c7SRichard Henderson     reachable_code_pass(s);
4186b83eabeaSRichard Henderson     liveness_pass_1(s);
41875a18407fSRichard Henderson 
41885a18407fSRichard Henderson     if (s->nb_indirects > 0) {
41895a18407fSRichard Henderson #ifdef DEBUG_DISAS
41905a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
41915a18407fSRichard Henderson                      && qemu_log_in_addr_range(tb->pc))) {
4192fc59d2d8SRobert Foley             FILE *logfile = qemu_log_lock();
41935a18407fSRichard Henderson             qemu_log("OP before indirect lowering:\n");
41941894f69aSRichard Henderson             tcg_dump_ops(s, false);
41955a18407fSRichard Henderson             qemu_log("\n");
4196fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
41975a18407fSRichard Henderson         }
41985a18407fSRichard Henderson #endif
41995a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
4200b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
42015a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
4202b83eabeaSRichard Henderson             liveness_pass_1(s);
42035a18407fSRichard Henderson         }
42045a18407fSRichard Henderson     }
4205c5cc28ffSAurelien Jarno 
4206a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4207d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time + profile_getclock());
4208a23a9ec6Sbellard #endif
4209c896fe29Sbellard 
4210c896fe29Sbellard #ifdef DEBUG_DISAS
4211d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
4212d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
4213fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
4214c5cc28ffSAurelien Jarno         qemu_log("OP after optimization and liveness analysis:\n");
42151894f69aSRichard Henderson         tcg_dump_ops(s, true);
421693fcfe39Saliguori         qemu_log("\n");
4217fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
4218c896fe29Sbellard     }
4219c896fe29Sbellard #endif
4220c896fe29Sbellard 
4221c896fe29Sbellard     tcg_reg_alloc_start(s);
4222c896fe29Sbellard 
4223e7e168f4SEmilio G. Cota     s->code_buf = tb->tc.ptr;
4224e7e168f4SEmilio G. Cota     s->code_ptr = tb->tc.ptr;
4225c896fe29Sbellard 
4226659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
42276001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
4228659ef5cbSRichard Henderson #endif
422957a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
423057a26946SRichard Henderson     s->pool_labels = NULL;
423157a26946SRichard Henderson #endif
42329ecefc84SRichard Henderson 
4233fca8a500SRichard Henderson     num_insns = -1;
423415fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
4235c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
4236b3db8758Sblueswir1 
4237c896fe29Sbellard #ifdef CONFIG_PROFILER
4238d73415a3SStefan Hajnoczi         qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
4239c896fe29Sbellard #endif
4240c45cb8bbSRichard Henderson 
4241c896fe29Sbellard         switch (opc) {
4242c896fe29Sbellard         case INDEX_op_mov_i32:
4243c896fe29Sbellard         case INDEX_op_mov_i64:
4244d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
4245dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
4246c896fe29Sbellard             break;
4247e8996ee0Sbellard         case INDEX_op_movi_i32:
4248e8996ee0Sbellard         case INDEX_op_movi_i64:
4249d2fd745fSRichard Henderson         case INDEX_op_dupi_vec:
4250dd186292SRichard Henderson             tcg_reg_alloc_movi(s, op);
4251e8996ee0Sbellard             break;
4252bab1671fSRichard Henderson         case INDEX_op_dup_vec:
4253bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
4254bab1671fSRichard Henderson             break;
4255765b842aSRichard Henderson         case INDEX_op_insn_start:
4256fca8a500SRichard Henderson             if (num_insns >= 0) {
42579f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
42589f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
42599f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
42609f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
4261fca8a500SRichard Henderson             }
4262fca8a500SRichard Henderson             num_insns++;
4263bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
4264bad729e2SRichard Henderson                 target_ulong a;
4265bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
4266efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
4267bad729e2SRichard Henderson #else
4268efee3746SRichard Henderson                 a = op->args[i];
4269bad729e2SRichard Henderson #endif
4270fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
4271bad729e2SRichard Henderson             }
4272c896fe29Sbellard             break;
42735ff9d6a4Sbellard         case INDEX_op_discard:
427443439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
42755ff9d6a4Sbellard             break;
4276c896fe29Sbellard         case INDEX_op_set_label:
4277e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
4278efee3746SRichard Henderson             tcg_out_label(s, arg_label(op->args[0]), s->code_ptr);
4279c896fe29Sbellard             break;
4280c896fe29Sbellard         case INDEX_op_call:
4281dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
4282c45cb8bbSRichard Henderson             break;
4283c896fe29Sbellard         default:
428425c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
4285be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
4286c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
4287c896fe29Sbellard                faster to have specialized register allocator functions for
4288c896fe29Sbellard                some common argument patterns */
4289dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
4290c896fe29Sbellard             break;
4291c896fe29Sbellard         }
42928d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
4293c896fe29Sbellard         check_regs(s);
4294c896fe29Sbellard #endif
4295b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
4296b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
4297b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
4298b125f9dcSRichard Henderson            generating code without having to check during generation.  */
4299644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
4300b125f9dcSRichard Henderson             return -1;
4301b125f9dcSRichard Henderson         }
43026e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
43036e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
43046e6c4efeSRichard Henderson             return -2;
43056e6c4efeSRichard Henderson         }
4306c896fe29Sbellard     }
4307fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
4308fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
4309c45cb8bbSRichard Henderson 
4310b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
4311659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
4312aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
4313aeee05f5SRichard Henderson     if (i < 0) {
4314aeee05f5SRichard Henderson         return i;
431523dceda6SRichard Henderson     }
4316659ef5cbSRichard Henderson #endif
431757a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
43181768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
43191768987bSRichard Henderson     if (i < 0) {
43201768987bSRichard Henderson         return i;
432157a26946SRichard Henderson     }
432257a26946SRichard Henderson #endif
43237ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
43247ecd02a0SRichard Henderson         return -2;
43257ecd02a0SRichard Henderson     }
4326c896fe29Sbellard 
4327c896fe29Sbellard     /* flush instruction cache */
43281813e175SRichard Henderson     flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr);
43292aeabc08SStefan Weil 
43301813e175SRichard Henderson     return tcg_current_code_size(s);
4331c896fe29Sbellard }
4332c896fe29Sbellard 
4333a23a9ec6Sbellard #ifdef CONFIG_PROFILER
43343de2faa9SMarkus Armbruster void tcg_dump_info(void)
4335a23a9ec6Sbellard {
4336c3fac113SEmilio G. Cota     TCGProfile prof = {};
4337c3fac113SEmilio G. Cota     const TCGProfile *s;
4338c3fac113SEmilio G. Cota     int64_t tb_count;
4339c3fac113SEmilio G. Cota     int64_t tb_div_count;
4340c3fac113SEmilio G. Cota     int64_t tot;
4341c3fac113SEmilio G. Cota 
4342c3fac113SEmilio G. Cota     tcg_profile_snapshot_counters(&prof);
4343c3fac113SEmilio G. Cota     s = &prof;
4344c3fac113SEmilio G. Cota     tb_count = s->tb_count;
4345c3fac113SEmilio G. Cota     tb_div_count = tb_count ? tb_count : 1;
4346c3fac113SEmilio G. Cota     tot = s->interm_time + s->code_time;
4347a23a9ec6Sbellard 
43483de2faa9SMarkus Armbruster     qemu_printf("JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
4349a23a9ec6Sbellard                 tot, tot / 2.4e9);
43503de2faa9SMarkus Armbruster     qemu_printf("translated TBs      %" PRId64 " (aborted=%" PRId64
43513de2faa9SMarkus Armbruster                 " %0.1f%%)\n",
4352fca8a500SRichard Henderson                 tb_count, s->tb_count1 - tb_count,
4353fca8a500SRichard Henderson                 (double)(s->tb_count1 - s->tb_count)
4354fca8a500SRichard Henderson                 / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
43553de2faa9SMarkus Armbruster     qemu_printf("avg ops/TB          %0.1f max=%d\n",
4356fca8a500SRichard Henderson                 (double)s->op_count / tb_div_count, s->op_count_max);
43573de2faa9SMarkus Armbruster     qemu_printf("deleted ops/TB      %0.2f\n",
4358fca8a500SRichard Henderson                 (double)s->del_op_count / tb_div_count);
43593de2faa9SMarkus Armbruster     qemu_printf("avg temps/TB        %0.2f max=%d\n",
4360fca8a500SRichard Henderson                 (double)s->temp_count / tb_div_count, s->temp_count_max);
43613de2faa9SMarkus Armbruster     qemu_printf("avg host code/TB    %0.1f\n",
4362fca8a500SRichard Henderson                 (double)s->code_out_len / tb_div_count);
43633de2faa9SMarkus Armbruster     qemu_printf("avg search data/TB  %0.1f\n",
4364fca8a500SRichard Henderson                 (double)s->search_out_len / tb_div_count);
4365a23a9ec6Sbellard 
43663de2faa9SMarkus Armbruster     qemu_printf("cycles/op           %0.1f\n",
4367a23a9ec6Sbellard                 s->op_count ? (double)tot / s->op_count : 0);
43683de2faa9SMarkus Armbruster     qemu_printf("cycles/in byte      %0.1f\n",
4369a23a9ec6Sbellard                 s->code_in_len ? (double)tot / s->code_in_len : 0);
43703de2faa9SMarkus Armbruster     qemu_printf("cycles/out byte     %0.1f\n",
4371a23a9ec6Sbellard                 s->code_out_len ? (double)tot / s->code_out_len : 0);
43723de2faa9SMarkus Armbruster     qemu_printf("cycles/search byte     %0.1f\n",
4373fca8a500SRichard Henderson                 s->search_out_len ? (double)tot / s->search_out_len : 0);
4374fca8a500SRichard Henderson     if (tot == 0) {
4375a23a9ec6Sbellard         tot = 1;
4376fca8a500SRichard Henderson     }
43773de2faa9SMarkus Armbruster     qemu_printf("  gen_interm time   %0.1f%%\n",
4378a23a9ec6Sbellard                 (double)s->interm_time / tot * 100.0);
43793de2faa9SMarkus Armbruster     qemu_printf("  gen_code time     %0.1f%%\n",
4380a23a9ec6Sbellard                 (double)s->code_time / tot * 100.0);
43813de2faa9SMarkus Armbruster     qemu_printf("optim./code time    %0.1f%%\n",
4382c5cc28ffSAurelien Jarno                 (double)s->opt_time / (s->code_time ? s->code_time : 1)
4383c5cc28ffSAurelien Jarno                 * 100.0);
43843de2faa9SMarkus Armbruster     qemu_printf("liveness/code time  %0.1f%%\n",
4385a23a9ec6Sbellard                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
43863de2faa9SMarkus Armbruster     qemu_printf("cpu_restore count   %" PRId64 "\n",
4387a23a9ec6Sbellard                 s->restore_count);
43883de2faa9SMarkus Armbruster     qemu_printf("  avg cycles        %0.1f\n",
4389a23a9ec6Sbellard                 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
4390a23a9ec6Sbellard }
4391a23a9ec6Sbellard #else
43923de2faa9SMarkus Armbruster void tcg_dump_info(void)
4393a23a9ec6Sbellard {
43943de2faa9SMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4395a23a9ec6Sbellard }
4396a23a9ec6Sbellard #endif
4397813da627SRichard Henderson 
4398813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
43995872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
44005872bbf2SRichard Henderson 
44015872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
44025872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
44035872bbf2SRichard Henderson 
44045872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
44055872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
44065872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
44075872bbf2SRichard Henderson 
44085872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
44095872bbf2SRichard Henderson */
4410813da627SRichard Henderson 
4411813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
4412813da627SRichard Henderson typedef enum {
4413813da627SRichard Henderson     JIT_NOACTION = 0,
4414813da627SRichard Henderson     JIT_REGISTER_FN,
4415813da627SRichard Henderson     JIT_UNREGISTER_FN
4416813da627SRichard Henderson } jit_actions_t;
4417813da627SRichard Henderson 
4418813da627SRichard Henderson struct jit_code_entry {
4419813da627SRichard Henderson     struct jit_code_entry *next_entry;
4420813da627SRichard Henderson     struct jit_code_entry *prev_entry;
4421813da627SRichard Henderson     const void *symfile_addr;
4422813da627SRichard Henderson     uint64_t symfile_size;
4423813da627SRichard Henderson };
4424813da627SRichard Henderson 
4425813da627SRichard Henderson struct jit_descriptor {
4426813da627SRichard Henderson     uint32_t version;
4427813da627SRichard Henderson     uint32_t action_flag;
4428813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
4429813da627SRichard Henderson     struct jit_code_entry *first_entry;
4430813da627SRichard Henderson };
4431813da627SRichard Henderson 
4432813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
4433813da627SRichard Henderson void __jit_debug_register_code(void)
4434813da627SRichard Henderson {
4435813da627SRichard Henderson     asm("");
4436813da627SRichard Henderson }
4437813da627SRichard Henderson 
4438813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
4439813da627SRichard Henderson    the version before we can set it.  */
4440813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
4441813da627SRichard Henderson 
4442813da627SRichard Henderson /* End GDB interface.  */
4443813da627SRichard Henderson 
4444813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
4445813da627SRichard Henderson {
4446813da627SRichard Henderson     const char *p = strtab + 1;
4447813da627SRichard Henderson 
4448813da627SRichard Henderson     while (1) {
4449813da627SRichard Henderson         if (strcmp(p, str) == 0) {
4450813da627SRichard Henderson             return p - strtab;
4451813da627SRichard Henderson         }
4452813da627SRichard Henderson         p += strlen(p) + 1;
4453813da627SRichard Henderson     }
4454813da627SRichard Henderson }
4455813da627SRichard Henderson 
44565872bbf2SRichard Henderson static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
44572c90784aSRichard Henderson                                  const void *debug_frame,
44582c90784aSRichard Henderson                                  size_t debug_frame_size)
4459813da627SRichard Henderson {
44605872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
44615872bbf2SRichard Henderson         uint32_t  len;
44625872bbf2SRichard Henderson         uint16_t  version;
44635872bbf2SRichard Henderson         uint32_t  abbrev;
44645872bbf2SRichard Henderson         uint8_t   ptr_size;
44655872bbf2SRichard Henderson         uint8_t   cu_die;
44665872bbf2SRichard Henderson         uint16_t  cu_lang;
44675872bbf2SRichard Henderson         uintptr_t cu_low_pc;
44685872bbf2SRichard Henderson         uintptr_t cu_high_pc;
44695872bbf2SRichard Henderson         uint8_t   fn_die;
44705872bbf2SRichard Henderson         char      fn_name[16];
44715872bbf2SRichard Henderson         uintptr_t fn_low_pc;
44725872bbf2SRichard Henderson         uintptr_t fn_high_pc;
44735872bbf2SRichard Henderson         uint8_t   cu_eoc;
44745872bbf2SRichard Henderson     };
4475813da627SRichard Henderson 
4476813da627SRichard Henderson     struct ElfImage {
4477813da627SRichard Henderson         ElfW(Ehdr) ehdr;
4478813da627SRichard Henderson         ElfW(Phdr) phdr;
44795872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
44805872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
44815872bbf2SRichard Henderson         struct DebugInfo di;
44825872bbf2SRichard Henderson         uint8_t    da[24];
44835872bbf2SRichard Henderson         char       str[80];
44845872bbf2SRichard Henderson     };
44855872bbf2SRichard Henderson 
44865872bbf2SRichard Henderson     struct ElfImage *img;
44875872bbf2SRichard Henderson 
44885872bbf2SRichard Henderson     static const struct ElfImage img_template = {
44895872bbf2SRichard Henderson         .ehdr = {
44905872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
44915872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
44925872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
44935872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
44945872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
44955872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
44965872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
44975872bbf2SRichard Henderson             .e_type = ET_EXEC,
44985872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
44995872bbf2SRichard Henderson             .e_version = EV_CURRENT,
45005872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
45015872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
45025872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
45035872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
45045872bbf2SRichard Henderson             .e_phnum = 1,
45055872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
45065872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
45075872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
4508abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
4509abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
4510abbb3eaeSRichard Henderson #endif
4511abbb3eaeSRichard Henderson #ifdef ELF_OSABI
4512abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
4513abbb3eaeSRichard Henderson #endif
45145872bbf2SRichard Henderson         },
45155872bbf2SRichard Henderson         .phdr = {
45165872bbf2SRichard Henderson             .p_type = PT_LOAD,
45175872bbf2SRichard Henderson             .p_flags = PF_X,
45185872bbf2SRichard Henderson         },
45195872bbf2SRichard Henderson         .shdr = {
45205872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
45215872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
45225872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
45235872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
45245872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
45255872bbf2SRichard Henderson             [1] = { /* .text */
45265872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
45275872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
45285872bbf2SRichard Henderson             },
45295872bbf2SRichard Henderson             [2] = { /* .debug_info */
45305872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
45315872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
45325872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
45335872bbf2SRichard Henderson             },
45345872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
45355872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
45365872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
45375872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
45385872bbf2SRichard Henderson             },
45395872bbf2SRichard Henderson             [4] = { /* .debug_frame */
45405872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
45415872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
45425872bbf2SRichard Henderson             },
45435872bbf2SRichard Henderson             [5] = { /* .symtab */
45445872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
45455872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
45465872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
45475872bbf2SRichard Henderson                 .sh_info = 1,
45485872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
45495872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
45505872bbf2SRichard Henderson             },
45515872bbf2SRichard Henderson             [6] = { /* .strtab */
45525872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
45535872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
45545872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
45555872bbf2SRichard Henderson             }
45565872bbf2SRichard Henderson         },
45575872bbf2SRichard Henderson         .sym = {
45585872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
45595872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
45605872bbf2SRichard Henderson                 .st_shndx = 1,
45615872bbf2SRichard Henderson             }
45625872bbf2SRichard Henderson         },
45635872bbf2SRichard Henderson         .di = {
45645872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
45655872bbf2SRichard Henderson             .version = 2,
45665872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
45675872bbf2SRichard Henderson             .cu_die = 1,
45685872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
45695872bbf2SRichard Henderson             .fn_die = 2,
45705872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
45715872bbf2SRichard Henderson         },
45725872bbf2SRichard Henderson         .da = {
45735872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
45745872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
45755872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
45765872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
45775872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
45785872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
45795872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
45805872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
45815872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
45825872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
45835872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
45845872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
45855872bbf2SRichard Henderson             0           /* no more abbrev */
45865872bbf2SRichard Henderson         },
45875872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
45885872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
4589813da627SRichard Henderson     };
4590813da627SRichard Henderson 
4591813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
4592813da627SRichard Henderson     static struct jit_code_entry one_entry;
4593813da627SRichard Henderson 
45945872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
4595813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
45962c90784aSRichard Henderson     DebugFrameHeader *dfh;
4597813da627SRichard Henderson 
45985872bbf2SRichard Henderson     img = g_malloc(img_size);
45995872bbf2SRichard Henderson     *img = img_template;
4600813da627SRichard Henderson 
46015872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
46025872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
46035872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
4604813da627SRichard Henderson 
46055872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
46065872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
46075872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
4608813da627SRichard Henderson 
46095872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
46105872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
46115872bbf2SRichard Henderson 
46125872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
46135872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
46145872bbf2SRichard Henderson 
46155872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
46165872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
46175872bbf2SRichard Henderson 
46185872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
46195872bbf2SRichard Henderson     img->sym[1].st_value = buf;
46205872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
46215872bbf2SRichard Henderson 
46225872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
462345aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
46245872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
462545aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
4626813da627SRichard Henderson 
46272c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
46282c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
46292c90784aSRichard Henderson     dfh->fde.func_start = buf;
46302c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
46312c90784aSRichard Henderson 
4632813da627SRichard Henderson #ifdef DEBUG_JIT
4633813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
4634813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
4635813da627SRichard Henderson     {
4636813da627SRichard Henderson         FILE *f = fopen("/tmp/qemu.jit", "w+b");
4637813da627SRichard Henderson         if (f) {
46385872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
4639813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
4640813da627SRichard Henderson             }
4641813da627SRichard Henderson             fclose(f);
4642813da627SRichard Henderson         }
4643813da627SRichard Henderson     }
4644813da627SRichard Henderson #endif
4645813da627SRichard Henderson 
4646813da627SRichard Henderson     one_entry.symfile_addr = img;
4647813da627SRichard Henderson     one_entry.symfile_size = img_size;
4648813da627SRichard Henderson 
4649813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
4650813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
4651813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
4652813da627SRichard Henderson     __jit_debug_register_code();
4653813da627SRichard Henderson }
4654813da627SRichard Henderson #else
46555872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
46565872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
4657813da627SRichard Henderson 
4658813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size,
46592c90784aSRichard Henderson                                  const void *debug_frame,
46602c90784aSRichard Henderson                                  size_t debug_frame_size)
4661813da627SRichard Henderson {
4662813da627SRichard Henderson }
4663813da627SRichard Henderson 
4664813da627SRichard Henderson void tcg_register_jit(void *buf, size_t buf_size)
4665813da627SRichard Henderson {
4666813da627SRichard Henderson }
4667813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
4668db432672SRichard Henderson 
4669db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
4670db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
4671db432672SRichard Henderson {
4672db432672SRichard Henderson     g_assert_not_reached();
4673db432672SRichard Henderson }
4674db432672SRichard Henderson #endif
4675