xref: /qemu/tcg/tcg.c (revision 5cc8767d05708f590eea926a2f7a2c1a80021fa7)
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"
38c896fe29Sbellard 
39c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU
40c896fe29Sbellard    CPU definitions. Currently they are used for qemu_ld/st
41c896fe29Sbellard    instructions */
42c896fe29Sbellard #define NO_CPU_IO_DEFS
43c896fe29Sbellard #include "cpu.h"
44c896fe29Sbellard 
4563c91552SPaolo Bonzini #include "exec/cpu-common.h"
4663c91552SPaolo Bonzini #include "exec/exec-all.h"
4763c91552SPaolo Bonzini 
48*5cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY)
49*5cc8767dSLike Xu #include "hw/boards.h"
50*5cc8767dSLike Xu #endif
51*5cc8767dSLike Xu 
52c896fe29Sbellard #include "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 
69ce151109SPeter Maydell /* Forward declarations for functions declared in tcg-target.inc.c 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 
105ce151109SPeter Maydell /* Forward declarations for functions declared and used in tcg-target.inc.c. */
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 {
3399f754620SRichard Henderson     size_t off = tcg_current_code_size(s);
3409f754620SRichard Henderson     s->tb_jmp_reset_offset[which] = off;
3419f754620SRichard Henderson     /* Make sure that we didn't overflow the stored offset.  */
3429f754620SRichard Henderson     assert(s->tb_jmp_reset_offset[which] == off);
3439f754620SRichard Henderson }
3449f754620SRichard Henderson 
345ce151109SPeter Maydell #include "tcg-target.inc.c"
346c896fe29Sbellard 
347be2cdc5eSEmilio G. Cota /* compare a pointer @ptr and a tb_tc @s */
348be2cdc5eSEmilio G. Cota static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s)
349be2cdc5eSEmilio G. Cota {
350be2cdc5eSEmilio G. Cota     if (ptr >= s->ptr + s->size) {
351be2cdc5eSEmilio G. Cota         return 1;
352be2cdc5eSEmilio G. Cota     } else if (ptr < s->ptr) {
353be2cdc5eSEmilio G. Cota         return -1;
354be2cdc5eSEmilio G. Cota     }
355be2cdc5eSEmilio G. Cota     return 0;
356be2cdc5eSEmilio G. Cota }
357be2cdc5eSEmilio G. Cota 
358be2cdc5eSEmilio G. Cota static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp)
359be2cdc5eSEmilio G. Cota {
360be2cdc5eSEmilio G. Cota     const struct tb_tc *a = ap;
361be2cdc5eSEmilio G. Cota     const struct tb_tc *b = bp;
362be2cdc5eSEmilio G. Cota 
363be2cdc5eSEmilio G. Cota     /*
364be2cdc5eSEmilio G. Cota      * When both sizes are set, we know this isn't a lookup.
365be2cdc5eSEmilio G. Cota      * This is the most likely case: every TB must be inserted; lookups
366be2cdc5eSEmilio G. Cota      * are a lot less frequent.
367be2cdc5eSEmilio G. Cota      */
368be2cdc5eSEmilio G. Cota     if (likely(a->size && b->size)) {
369be2cdc5eSEmilio G. Cota         if (a->ptr > b->ptr) {
370be2cdc5eSEmilio G. Cota             return 1;
371be2cdc5eSEmilio G. Cota         } else if (a->ptr < b->ptr) {
372be2cdc5eSEmilio G. Cota             return -1;
373be2cdc5eSEmilio G. Cota         }
374be2cdc5eSEmilio G. Cota         /* a->ptr == b->ptr should happen only on deletions */
375be2cdc5eSEmilio G. Cota         g_assert(a->size == b->size);
376be2cdc5eSEmilio G. Cota         return 0;
377be2cdc5eSEmilio G. Cota     }
378be2cdc5eSEmilio G. Cota     /*
379be2cdc5eSEmilio G. Cota      * All lookups have either .size field set to 0.
380be2cdc5eSEmilio G. Cota      * From the glib sources we see that @ap is always the lookup key. However
381be2cdc5eSEmilio G. Cota      * the docs provide no guarantee, so we just mark this case as likely.
382be2cdc5eSEmilio G. Cota      */
383be2cdc5eSEmilio G. Cota     if (likely(a->size == 0)) {
384be2cdc5eSEmilio G. Cota         return ptr_cmp_tb_tc(a->ptr, b);
385be2cdc5eSEmilio G. Cota     }
386be2cdc5eSEmilio G. Cota     return ptr_cmp_tb_tc(b->ptr, a);
387be2cdc5eSEmilio G. Cota }
388be2cdc5eSEmilio G. Cota 
389be2cdc5eSEmilio G. Cota static void tcg_region_trees_init(void)
390be2cdc5eSEmilio G. Cota {
391be2cdc5eSEmilio G. Cota     size_t i;
392be2cdc5eSEmilio G. Cota 
393be2cdc5eSEmilio G. Cota     tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize);
394be2cdc5eSEmilio G. Cota     region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size);
395be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
396be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
397be2cdc5eSEmilio G. Cota 
398be2cdc5eSEmilio G. Cota         qemu_mutex_init(&rt->lock);
399be2cdc5eSEmilio G. Cota         rt->tree = g_tree_new(tb_tc_cmp);
400be2cdc5eSEmilio G. Cota     }
401be2cdc5eSEmilio G. Cota }
402be2cdc5eSEmilio G. Cota 
403be2cdc5eSEmilio G. Cota static struct tcg_region_tree *tc_ptr_to_region_tree(void *p)
404be2cdc5eSEmilio G. Cota {
405be2cdc5eSEmilio G. Cota     size_t region_idx;
406be2cdc5eSEmilio G. Cota 
407be2cdc5eSEmilio G. Cota     if (p < region.start_aligned) {
408be2cdc5eSEmilio G. Cota         region_idx = 0;
409be2cdc5eSEmilio G. Cota     } else {
410be2cdc5eSEmilio G. Cota         ptrdiff_t offset = p - region.start_aligned;
411be2cdc5eSEmilio G. Cota 
412be2cdc5eSEmilio G. Cota         if (offset > region.stride * (region.n - 1)) {
413be2cdc5eSEmilio G. Cota             region_idx = region.n - 1;
414be2cdc5eSEmilio G. Cota         } else {
415be2cdc5eSEmilio G. Cota             region_idx = offset / region.stride;
416be2cdc5eSEmilio G. Cota         }
417be2cdc5eSEmilio G. Cota     }
418be2cdc5eSEmilio G. Cota     return region_trees + region_idx * tree_size;
419be2cdc5eSEmilio G. Cota }
420be2cdc5eSEmilio G. Cota 
421be2cdc5eSEmilio G. Cota void tcg_tb_insert(TranslationBlock *tb)
422be2cdc5eSEmilio G. Cota {
423be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
424be2cdc5eSEmilio G. Cota 
425be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
426be2cdc5eSEmilio G. Cota     g_tree_insert(rt->tree, &tb->tc, tb);
427be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
428be2cdc5eSEmilio G. Cota }
429be2cdc5eSEmilio G. Cota 
430be2cdc5eSEmilio G. Cota void tcg_tb_remove(TranslationBlock *tb)
431be2cdc5eSEmilio G. Cota {
432be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
433be2cdc5eSEmilio G. Cota 
434be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
435be2cdc5eSEmilio G. Cota     g_tree_remove(rt->tree, &tb->tc);
436be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
437be2cdc5eSEmilio G. Cota }
438be2cdc5eSEmilio G. Cota 
439be2cdc5eSEmilio G. Cota /*
440be2cdc5eSEmilio G. Cota  * Find the TB 'tb' such that
441be2cdc5eSEmilio G. Cota  * tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size
442be2cdc5eSEmilio G. Cota  * Return NULL if not found.
443be2cdc5eSEmilio G. Cota  */
444be2cdc5eSEmilio G. Cota TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr)
445be2cdc5eSEmilio G. Cota {
446be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr);
447be2cdc5eSEmilio G. Cota     TranslationBlock *tb;
448be2cdc5eSEmilio G. Cota     struct tb_tc s = { .ptr = (void *)tc_ptr };
449be2cdc5eSEmilio G. Cota 
450be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
451be2cdc5eSEmilio G. Cota     tb = g_tree_lookup(rt->tree, &s);
452be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
453be2cdc5eSEmilio G. Cota     return tb;
454be2cdc5eSEmilio G. Cota }
455be2cdc5eSEmilio G. Cota 
456be2cdc5eSEmilio G. Cota static void tcg_region_tree_lock_all(void)
457be2cdc5eSEmilio G. Cota {
458be2cdc5eSEmilio G. Cota     size_t i;
459be2cdc5eSEmilio G. Cota 
460be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
461be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
462be2cdc5eSEmilio G. Cota 
463be2cdc5eSEmilio G. Cota         qemu_mutex_lock(&rt->lock);
464be2cdc5eSEmilio G. Cota     }
465be2cdc5eSEmilio G. Cota }
466be2cdc5eSEmilio G. Cota 
467be2cdc5eSEmilio G. Cota static void tcg_region_tree_unlock_all(void)
468be2cdc5eSEmilio G. Cota {
469be2cdc5eSEmilio G. Cota     size_t i;
470be2cdc5eSEmilio G. Cota 
471be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
472be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
473be2cdc5eSEmilio G. Cota 
474be2cdc5eSEmilio G. Cota         qemu_mutex_unlock(&rt->lock);
475be2cdc5eSEmilio G. Cota     }
476be2cdc5eSEmilio G. Cota }
477be2cdc5eSEmilio G. Cota 
478be2cdc5eSEmilio G. Cota void tcg_tb_foreach(GTraverseFunc func, gpointer user_data)
479be2cdc5eSEmilio G. Cota {
480be2cdc5eSEmilio G. Cota     size_t i;
481be2cdc5eSEmilio G. Cota 
482be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
483be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
484be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
485be2cdc5eSEmilio G. Cota 
486be2cdc5eSEmilio G. Cota         g_tree_foreach(rt->tree, func, user_data);
487be2cdc5eSEmilio G. Cota     }
488be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
489be2cdc5eSEmilio G. Cota }
490be2cdc5eSEmilio G. Cota 
491be2cdc5eSEmilio G. Cota size_t tcg_nb_tbs(void)
492be2cdc5eSEmilio G. Cota {
493be2cdc5eSEmilio G. Cota     size_t nb_tbs = 0;
494be2cdc5eSEmilio G. Cota     size_t i;
495be2cdc5eSEmilio G. Cota 
496be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
497be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
498be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
499be2cdc5eSEmilio G. Cota 
500be2cdc5eSEmilio G. Cota         nb_tbs += g_tree_nnodes(rt->tree);
501be2cdc5eSEmilio G. Cota     }
502be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
503be2cdc5eSEmilio G. Cota     return nb_tbs;
504be2cdc5eSEmilio G. Cota }
505be2cdc5eSEmilio G. Cota 
506be2cdc5eSEmilio G. Cota static void tcg_region_tree_reset_all(void)
507be2cdc5eSEmilio G. Cota {
508be2cdc5eSEmilio G. Cota     size_t i;
509be2cdc5eSEmilio G. Cota 
510be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
511be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
512be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
513be2cdc5eSEmilio G. Cota 
514be2cdc5eSEmilio G. Cota         /* Increment the refcount first so that destroy acts as a reset */
515be2cdc5eSEmilio G. Cota         g_tree_ref(rt->tree);
516be2cdc5eSEmilio G. Cota         g_tree_destroy(rt->tree);
517be2cdc5eSEmilio G. Cota     }
518be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
519be2cdc5eSEmilio G. Cota }
520be2cdc5eSEmilio G. Cota 
521e8feb96fSEmilio G. Cota static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend)
522e8feb96fSEmilio G. Cota {
523e8feb96fSEmilio G. Cota     void *start, *end;
524e8feb96fSEmilio G. Cota 
525e8feb96fSEmilio G. Cota     start = region.start_aligned + curr_region * region.stride;
526e8feb96fSEmilio G. Cota     end = start + region.size;
527e8feb96fSEmilio G. Cota 
528e8feb96fSEmilio G. Cota     if (curr_region == 0) {
529e8feb96fSEmilio G. Cota         start = region.start;
530e8feb96fSEmilio G. Cota     }
531e8feb96fSEmilio G. Cota     if (curr_region == region.n - 1) {
532e8feb96fSEmilio G. Cota         end = region.end;
533e8feb96fSEmilio G. Cota     }
534e8feb96fSEmilio G. Cota 
535e8feb96fSEmilio G. Cota     *pstart = start;
536e8feb96fSEmilio G. Cota     *pend = end;
537e8feb96fSEmilio G. Cota }
538e8feb96fSEmilio G. Cota 
539e8feb96fSEmilio G. Cota static void tcg_region_assign(TCGContext *s, size_t curr_region)
540e8feb96fSEmilio G. Cota {
541e8feb96fSEmilio G. Cota     void *start, *end;
542e8feb96fSEmilio G. Cota 
543e8feb96fSEmilio G. Cota     tcg_region_bounds(curr_region, &start, &end);
544e8feb96fSEmilio G. Cota 
545e8feb96fSEmilio G. Cota     s->code_gen_buffer = start;
546e8feb96fSEmilio G. Cota     s->code_gen_ptr = start;
547e8feb96fSEmilio G. Cota     s->code_gen_buffer_size = end - start;
548e8feb96fSEmilio G. Cota     s->code_gen_highwater = end - TCG_HIGHWATER;
549e8feb96fSEmilio G. Cota }
550e8feb96fSEmilio G. Cota 
551e8feb96fSEmilio G. Cota static bool tcg_region_alloc__locked(TCGContext *s)
552e8feb96fSEmilio G. Cota {
553e8feb96fSEmilio G. Cota     if (region.current == region.n) {
554e8feb96fSEmilio G. Cota         return true;
555e8feb96fSEmilio G. Cota     }
556e8feb96fSEmilio G. Cota     tcg_region_assign(s, region.current);
557e8feb96fSEmilio G. Cota     region.current++;
558e8feb96fSEmilio G. Cota     return false;
559e8feb96fSEmilio G. Cota }
560e8feb96fSEmilio G. Cota 
561e8feb96fSEmilio G. Cota /*
562e8feb96fSEmilio G. Cota  * Request a new region once the one in use has filled up.
563e8feb96fSEmilio G. Cota  * Returns true on error.
564e8feb96fSEmilio G. Cota  */
565e8feb96fSEmilio G. Cota static bool tcg_region_alloc(TCGContext *s)
566e8feb96fSEmilio G. Cota {
567e8feb96fSEmilio G. Cota     bool err;
568e8feb96fSEmilio G. Cota     /* read the region size now; alloc__locked will overwrite it on success */
569e8feb96fSEmilio G. Cota     size_t size_full = s->code_gen_buffer_size;
570e8feb96fSEmilio G. Cota 
571e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
572e8feb96fSEmilio G. Cota     err = tcg_region_alloc__locked(s);
573e8feb96fSEmilio G. Cota     if (!err) {
574e8feb96fSEmilio G. Cota         region.agg_size_full += size_full - TCG_HIGHWATER;
575e8feb96fSEmilio G. Cota     }
576e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
577e8feb96fSEmilio G. Cota     return err;
578e8feb96fSEmilio G. Cota }
579e8feb96fSEmilio G. Cota 
580e8feb96fSEmilio G. Cota /*
581e8feb96fSEmilio G. Cota  * Perform a context's first region allocation.
582e8feb96fSEmilio G. Cota  * This function does _not_ increment region.agg_size_full.
583e8feb96fSEmilio G. Cota  */
584e8feb96fSEmilio G. Cota static inline bool tcg_region_initial_alloc__locked(TCGContext *s)
585e8feb96fSEmilio G. Cota {
586e8feb96fSEmilio G. Cota     return tcg_region_alloc__locked(s);
587e8feb96fSEmilio G. Cota }
588e8feb96fSEmilio G. Cota 
589e8feb96fSEmilio G. Cota /* Call from a safe-work context */
590e8feb96fSEmilio G. Cota void tcg_region_reset_all(void)
591e8feb96fSEmilio G. Cota {
5923468b59eSEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
593e8feb96fSEmilio G. Cota     unsigned int i;
594e8feb96fSEmilio G. Cota 
595e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
596e8feb96fSEmilio G. Cota     region.current = 0;
597e8feb96fSEmilio G. Cota     region.agg_size_full = 0;
598e8feb96fSEmilio G. Cota 
5993468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
6003468b59eSEmilio G. Cota         TCGContext *s = atomic_read(&tcg_ctxs[i]);
6013468b59eSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(s);
602e8feb96fSEmilio G. Cota 
603e8feb96fSEmilio G. Cota         g_assert(!err);
604e8feb96fSEmilio G. Cota     }
605e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
606be2cdc5eSEmilio G. Cota 
607be2cdc5eSEmilio G. Cota     tcg_region_tree_reset_all();
608e8feb96fSEmilio G. Cota }
609e8feb96fSEmilio G. Cota 
6103468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
6113468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
6123468b59eSEmilio G. Cota {
6133468b59eSEmilio G. Cota     return 1;
6143468b59eSEmilio G. Cota }
6153468b59eSEmilio G. Cota #else
6163468b59eSEmilio G. Cota /*
6173468b59eSEmilio G. Cota  * It is likely that some vCPUs will translate more code than others, so we
6183468b59eSEmilio G. Cota  * first try to set more regions than max_cpus, with those regions being of
6193468b59eSEmilio G. Cota  * reasonable size. If that's not possible we make do by evenly dividing
6203468b59eSEmilio G. Cota  * the code_gen_buffer among the vCPUs.
6213468b59eSEmilio G. Cota  */
6223468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
6233468b59eSEmilio G. Cota {
6243468b59eSEmilio G. Cota     size_t i;
6253468b59eSEmilio G. Cota 
6263468b59eSEmilio G. Cota     /* Use a single region if all we have is one vCPU thread */
627*5cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY)
628*5cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
629*5cc8767dSLike Xu     unsigned int max_cpus = ms->smp.max_cpus;
630*5cc8767dSLike Xu #endif
6313468b59eSEmilio G. Cota     if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) {
6323468b59eSEmilio G. Cota         return 1;
6333468b59eSEmilio G. Cota     }
6343468b59eSEmilio G. Cota 
6353468b59eSEmilio G. Cota     /* Try to have more regions than max_cpus, with each region being >= 2 MB */
6363468b59eSEmilio G. Cota     for (i = 8; i > 0; i--) {
6373468b59eSEmilio G. Cota         size_t regions_per_thread = i;
6383468b59eSEmilio G. Cota         size_t region_size;
6393468b59eSEmilio G. Cota 
6403468b59eSEmilio G. Cota         region_size = tcg_init_ctx.code_gen_buffer_size;
6413468b59eSEmilio G. Cota         region_size /= max_cpus * regions_per_thread;
6423468b59eSEmilio G. Cota 
6433468b59eSEmilio G. Cota         if (region_size >= 2 * 1024u * 1024) {
6443468b59eSEmilio G. Cota             return max_cpus * regions_per_thread;
6453468b59eSEmilio G. Cota         }
6463468b59eSEmilio G. Cota     }
6473468b59eSEmilio G. Cota     /* If we can't, then just allocate one region per vCPU thread */
6483468b59eSEmilio G. Cota     return max_cpus;
6493468b59eSEmilio G. Cota }
6503468b59eSEmilio G. Cota #endif
6513468b59eSEmilio G. Cota 
652e8feb96fSEmilio G. Cota /*
653e8feb96fSEmilio G. Cota  * Initializes region partitioning.
654e8feb96fSEmilio G. Cota  *
655e8feb96fSEmilio G. Cota  * Called at init time from the parent thread (i.e. the one calling
656e8feb96fSEmilio G. Cota  * tcg_context_init), after the target's TCG globals have been set.
6573468b59eSEmilio G. Cota  *
6583468b59eSEmilio G. Cota  * Region partitioning works by splitting code_gen_buffer into separate regions,
6593468b59eSEmilio G. Cota  * and then assigning regions to TCG threads so that the threads can translate
6603468b59eSEmilio G. Cota  * code in parallel without synchronization.
6613468b59eSEmilio G. Cota  *
6623468b59eSEmilio G. Cota  * In softmmu the number of TCG threads is bounded by max_cpus, so we use at
6633468b59eSEmilio G. Cota  * least max_cpus regions in MTTCG. In !MTTCG we use a single region.
6643468b59eSEmilio G. Cota  * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...])
6653468b59eSEmilio G. Cota  * must have been parsed before calling this function, since it calls
6663468b59eSEmilio G. Cota  * qemu_tcg_mttcg_enabled().
6673468b59eSEmilio G. Cota  *
6683468b59eSEmilio G. Cota  * In user-mode we use a single region.  Having multiple regions in user-mode
6693468b59eSEmilio G. Cota  * is not supported, because the number of vCPU threads (recall that each thread
6703468b59eSEmilio G. Cota  * spawned by the guest corresponds to a vCPU thread) is only bounded by the
6713468b59eSEmilio G. Cota  * OS, and usually this number is huge (tens of thousands is not uncommon).
6723468b59eSEmilio G. Cota  * Thus, given this large bound on the number of vCPU threads and the fact
6733468b59eSEmilio G. Cota  * that code_gen_buffer is allocated at compile-time, we cannot guarantee
6743468b59eSEmilio G. Cota  * that the availability of at least one region per vCPU thread.
6753468b59eSEmilio G. Cota  *
6763468b59eSEmilio G. Cota  * However, this user-mode limitation is unlikely to be a significant problem
6773468b59eSEmilio G. Cota  * in practice. Multi-threaded guests share most if not all of their translated
6783468b59eSEmilio G. Cota  * code, which makes parallel code generation less appealing than in softmmu.
679e8feb96fSEmilio G. Cota  */
680e8feb96fSEmilio G. Cota void tcg_region_init(void)
681e8feb96fSEmilio G. Cota {
682e8feb96fSEmilio G. Cota     void *buf = tcg_init_ctx.code_gen_buffer;
683e8feb96fSEmilio G. Cota     void *aligned;
684e8feb96fSEmilio G. Cota     size_t size = tcg_init_ctx.code_gen_buffer_size;
685e8feb96fSEmilio G. Cota     size_t page_size = qemu_real_host_page_size;
686e8feb96fSEmilio G. Cota     size_t region_size;
687e8feb96fSEmilio G. Cota     size_t n_regions;
688e8feb96fSEmilio G. Cota     size_t i;
689e8feb96fSEmilio G. Cota 
6903468b59eSEmilio G. Cota     n_regions = tcg_n_regions();
691e8feb96fSEmilio G. Cota 
692e8feb96fSEmilio G. Cota     /* The first region will be 'aligned - buf' bytes larger than the others */
693e8feb96fSEmilio G. Cota     aligned = QEMU_ALIGN_PTR_UP(buf, page_size);
694e8feb96fSEmilio G. Cota     g_assert(aligned < tcg_init_ctx.code_gen_buffer + size);
695e8feb96fSEmilio G. Cota     /*
696e8feb96fSEmilio G. Cota      * Make region_size a multiple of page_size, using aligned as the start.
697e8feb96fSEmilio G. Cota      * As a result of this we might end up with a few extra pages at the end of
698e8feb96fSEmilio G. Cota      * the buffer; we will assign those to the last region.
699e8feb96fSEmilio G. Cota      */
700e8feb96fSEmilio G. Cota     region_size = (size - (aligned - buf)) / n_regions;
701e8feb96fSEmilio G. Cota     region_size = QEMU_ALIGN_DOWN(region_size, page_size);
702e8feb96fSEmilio G. Cota 
703e8feb96fSEmilio G. Cota     /* A region must have at least 2 pages; one code, one guard */
704e8feb96fSEmilio G. Cota     g_assert(region_size >= 2 * page_size);
705e8feb96fSEmilio G. Cota 
706e8feb96fSEmilio G. Cota     /* init the region struct */
707e8feb96fSEmilio G. Cota     qemu_mutex_init(&region.lock);
708e8feb96fSEmilio G. Cota     region.n = n_regions;
709e8feb96fSEmilio G. Cota     region.size = region_size - page_size;
710e8feb96fSEmilio G. Cota     region.stride = region_size;
711e8feb96fSEmilio G. Cota     region.start = buf;
712e8feb96fSEmilio G. Cota     region.start_aligned = aligned;
713e8feb96fSEmilio G. Cota     /* page-align the end, since its last page will be a guard page */
714e8feb96fSEmilio G. Cota     region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size);
715e8feb96fSEmilio G. Cota     /* account for that last guard page */
716e8feb96fSEmilio G. Cota     region.end -= page_size;
717e8feb96fSEmilio G. Cota 
718e8feb96fSEmilio G. Cota     /* set guard pages */
719e8feb96fSEmilio G. Cota     for (i = 0; i < region.n; i++) {
720e8feb96fSEmilio G. Cota         void *start, *end;
721e8feb96fSEmilio G. Cota         int rc;
722e8feb96fSEmilio G. Cota 
723e8feb96fSEmilio G. Cota         tcg_region_bounds(i, &start, &end);
724e8feb96fSEmilio G. Cota         rc = qemu_mprotect_none(end, page_size);
725e8feb96fSEmilio G. Cota         g_assert(!rc);
726e8feb96fSEmilio G. Cota     }
727e8feb96fSEmilio G. Cota 
728be2cdc5eSEmilio G. Cota     tcg_region_trees_init();
729be2cdc5eSEmilio G. Cota 
7303468b59eSEmilio G. Cota     /* In user-mode we support only one ctx, so do the initial allocation now */
7313468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
732e8feb96fSEmilio G. Cota     {
733e8feb96fSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(tcg_ctx);
734e8feb96fSEmilio G. Cota 
735e8feb96fSEmilio G. Cota         g_assert(!err);
736e8feb96fSEmilio G. Cota     }
7373468b59eSEmilio G. Cota #endif
738e8feb96fSEmilio G. Cota }
739e8feb96fSEmilio G. Cota 
740e8feb96fSEmilio G. Cota /*
7413468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
7423468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
7433468b59eSEmilio G. Cota  * before initiating translation.
7443468b59eSEmilio G. Cota  *
7453468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
7463468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
7473468b59eSEmilio G. Cota  *
7483468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
7493468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
7503468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
7513468b59eSEmilio G. Cota  *
7523468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
7533468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
7543468b59eSEmilio G. Cota  */
7553468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
7563468b59eSEmilio G. Cota void tcg_register_thread(void)
7573468b59eSEmilio G. Cota {
7583468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
7593468b59eSEmilio G. Cota }
7603468b59eSEmilio G. Cota #else
7613468b59eSEmilio G. Cota void tcg_register_thread(void)
7623468b59eSEmilio G. Cota {
763*5cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
7643468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
7653468b59eSEmilio G. Cota     unsigned int i, n;
7663468b59eSEmilio G. Cota     bool err;
7673468b59eSEmilio G. Cota 
7683468b59eSEmilio G. Cota     *s = tcg_init_ctx;
7693468b59eSEmilio G. Cota 
7703468b59eSEmilio G. Cota     /* Relink mem_base.  */
7713468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
7723468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
7733468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
7743468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
7753468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
7763468b59eSEmilio G. Cota         }
7773468b59eSEmilio G. Cota     }
7783468b59eSEmilio G. Cota 
7793468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
7803468b59eSEmilio G. Cota     n = atomic_fetch_inc(&n_tcg_ctxs);
781*5cc8767dSLike Xu     g_assert(n < ms->smp.max_cpus);
7823468b59eSEmilio G. Cota     atomic_set(&tcg_ctxs[n], s);
7833468b59eSEmilio G. Cota 
7843468b59eSEmilio G. Cota     tcg_ctx = s;
7853468b59eSEmilio G. Cota     qemu_mutex_lock(&region.lock);
7863468b59eSEmilio G. Cota     err = tcg_region_initial_alloc__locked(tcg_ctx);
7873468b59eSEmilio G. Cota     g_assert(!err);
7883468b59eSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
7893468b59eSEmilio G. Cota }
7903468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
7913468b59eSEmilio G. Cota 
7923468b59eSEmilio G. Cota /*
793e8feb96fSEmilio G. Cota  * Returns the size (in bytes) of all translated code (i.e. from all regions)
794e8feb96fSEmilio G. Cota  * currently in the cache.
795e8feb96fSEmilio G. Cota  * See also: tcg_code_capacity()
796e8feb96fSEmilio G. Cota  * Do not confuse with tcg_current_code_size(); that one applies to a single
797e8feb96fSEmilio G. Cota  * TCG context.
798e8feb96fSEmilio G. Cota  */
799e8feb96fSEmilio G. Cota size_t tcg_code_size(void)
800e8feb96fSEmilio G. Cota {
8013468b59eSEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
802e8feb96fSEmilio G. Cota     unsigned int i;
803e8feb96fSEmilio G. Cota     size_t total;
804e8feb96fSEmilio G. Cota 
805e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
806e8feb96fSEmilio G. Cota     total = region.agg_size_full;
8073468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
8083468b59eSEmilio G. Cota         const TCGContext *s = atomic_read(&tcg_ctxs[i]);
809e8feb96fSEmilio G. Cota         size_t size;
810e8feb96fSEmilio G. Cota 
811e8feb96fSEmilio G. Cota         size = atomic_read(&s->code_gen_ptr) - s->code_gen_buffer;
812e8feb96fSEmilio G. Cota         g_assert(size <= s->code_gen_buffer_size);
813e8feb96fSEmilio G. Cota         total += size;
814e8feb96fSEmilio G. Cota     }
815e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
816e8feb96fSEmilio G. Cota     return total;
817e8feb96fSEmilio G. Cota }
818e8feb96fSEmilio G. Cota 
819e8feb96fSEmilio G. Cota /*
820e8feb96fSEmilio G. Cota  * Returns the code capacity (in bytes) of the entire cache, i.e. including all
821e8feb96fSEmilio G. Cota  * regions.
822e8feb96fSEmilio G. Cota  * See also: tcg_code_size()
823e8feb96fSEmilio G. Cota  */
824e8feb96fSEmilio G. Cota size_t tcg_code_capacity(void)
825e8feb96fSEmilio G. Cota {
826e8feb96fSEmilio G. Cota     size_t guard_size, capacity;
827e8feb96fSEmilio G. Cota 
828e8feb96fSEmilio G. Cota     /* no need for synchronization; these variables are set at init time */
829e8feb96fSEmilio G. Cota     guard_size = region.stride - region.size;
830e8feb96fSEmilio G. Cota     capacity = region.end + guard_size - region.start;
831e8feb96fSEmilio G. Cota     capacity -= region.n * (guard_size + TCG_HIGHWATER);
832e8feb96fSEmilio G. Cota     return capacity;
833e8feb96fSEmilio G. Cota }
834e8feb96fSEmilio G. Cota 
835128ed227SEmilio G. Cota size_t tcg_tb_phys_invalidate_count(void)
836128ed227SEmilio G. Cota {
837128ed227SEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
838128ed227SEmilio G. Cota     unsigned int i;
839128ed227SEmilio G. Cota     size_t total = 0;
840128ed227SEmilio G. Cota 
841128ed227SEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
842128ed227SEmilio G. Cota         const TCGContext *s = atomic_read(&tcg_ctxs[i]);
843128ed227SEmilio G. Cota 
844128ed227SEmilio G. Cota         total += atomic_read(&s->tb_phys_invalidate_count);
845128ed227SEmilio G. Cota     }
846128ed227SEmilio G. Cota     return total;
847128ed227SEmilio G. Cota }
848128ed227SEmilio G. Cota 
849c896fe29Sbellard /* pool based memory allocation */
850c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
851c896fe29Sbellard {
852c896fe29Sbellard     TCGPool *p;
853c896fe29Sbellard     int pool_size;
854c896fe29Sbellard 
855c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
856c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
8577267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
858c896fe29Sbellard         p->size = size;
8594055299eSKirill Batuzov         p->next = s->pool_first_large;
8604055299eSKirill Batuzov         s->pool_first_large = p;
8614055299eSKirill Batuzov         return p->data;
862c896fe29Sbellard     } else {
863c896fe29Sbellard         p = s->pool_current;
864c896fe29Sbellard         if (!p) {
865c896fe29Sbellard             p = s->pool_first;
866c896fe29Sbellard             if (!p)
867c896fe29Sbellard                 goto new_pool;
868c896fe29Sbellard         } else {
869c896fe29Sbellard             if (!p->next) {
870c896fe29Sbellard             new_pool:
871c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
8727267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
873c896fe29Sbellard                 p->size = pool_size;
874c896fe29Sbellard                 p->next = NULL;
875c896fe29Sbellard                 if (s->pool_current)
876c896fe29Sbellard                     s->pool_current->next = p;
877c896fe29Sbellard                 else
878c896fe29Sbellard                     s->pool_first = p;
879c896fe29Sbellard             } else {
880c896fe29Sbellard                 p = p->next;
881c896fe29Sbellard             }
882c896fe29Sbellard         }
883c896fe29Sbellard     }
884c896fe29Sbellard     s->pool_current = p;
885c896fe29Sbellard     s->pool_cur = p->data + size;
886c896fe29Sbellard     s->pool_end = p->data + p->size;
887c896fe29Sbellard     return p->data;
888c896fe29Sbellard }
889c896fe29Sbellard 
890c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
891c896fe29Sbellard {
8924055299eSKirill Batuzov     TCGPool *p, *t;
8934055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
8944055299eSKirill Batuzov         t = p->next;
8954055299eSKirill Batuzov         g_free(p);
8964055299eSKirill Batuzov     }
8974055299eSKirill Batuzov     s->pool_first_large = NULL;
898c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
899c896fe29Sbellard     s->pool_current = NULL;
900c896fe29Sbellard }
901c896fe29Sbellard 
902100b5e01SRichard Henderson typedef struct TCGHelperInfo {
903100b5e01SRichard Henderson     void *func;
904100b5e01SRichard Henderson     const char *name;
905afb49896SRichard Henderson     unsigned flags;
906afb49896SRichard Henderson     unsigned sizemask;
907100b5e01SRichard Henderson } TCGHelperInfo;
908100b5e01SRichard Henderson 
9092ef6175aSRichard Henderson #include "exec/helper-proto.h"
9102ef6175aSRichard Henderson 
911100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = {
9122ef6175aSRichard Henderson #include "exec/helper-tcg.h"
913100b5e01SRichard Henderson };
914619205fdSEmilio G. Cota static GHashTable *helper_table;
915100b5e01SRichard Henderson 
91691478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
917f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
9181c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
9191c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
92091478cefSRichard Henderson 
921c896fe29Sbellard void tcg_context_init(TCGContext *s)
922c896fe29Sbellard {
923100b5e01SRichard Henderson     int op, total_args, n, i;
924c896fe29Sbellard     TCGOpDef *def;
925c896fe29Sbellard     TCGArgConstraint *args_ct;
926c896fe29Sbellard     int *sorted_args;
9271c2adb95SRichard Henderson     TCGTemp *ts;
928c896fe29Sbellard 
929c896fe29Sbellard     memset(s, 0, sizeof(*s));
930c896fe29Sbellard     s->nb_globals = 0;
931c896fe29Sbellard 
932c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
933c896fe29Sbellard        space */
934c896fe29Sbellard     total_args = 0;
935c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
936c896fe29Sbellard         def = &tcg_op_defs[op];
937c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
938c896fe29Sbellard         total_args += n;
939c896fe29Sbellard     }
940c896fe29Sbellard 
9417267c094SAnthony Liguori     args_ct = g_malloc(sizeof(TCGArgConstraint) * total_args);
9427267c094SAnthony Liguori     sorted_args = g_malloc(sizeof(int) * total_args);
943c896fe29Sbellard 
944c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
945c896fe29Sbellard         def = &tcg_op_defs[op];
946c896fe29Sbellard         def->args_ct = args_ct;
947c896fe29Sbellard         def->sorted_args = sorted_args;
948c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
949c896fe29Sbellard         sorted_args += n;
950c896fe29Sbellard         args_ct += n;
951c896fe29Sbellard     }
952c896fe29Sbellard 
9535cd8f621SRichard Henderson     /* Register helpers.  */
95484fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
955619205fdSEmilio G. Cota     helper_table = g_hash_table_new(NULL, NULL);
95684fd9dd3SRichard Henderson 
957100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
95884fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
95972866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
960100b5e01SRichard Henderson     }
9615cd8f621SRichard Henderson 
962c896fe29Sbellard     tcg_target_init(s);
963f69d277eSRichard Henderson     process_op_defs(s);
96491478cefSRichard Henderson 
96591478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
96691478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
96791478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
96891478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
96991478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
97091478cefSRichard Henderson             break;
97191478cefSRichard Henderson         }
97291478cefSRichard Henderson     }
97391478cefSRichard Henderson     for (i = 0; i < n; ++i) {
97491478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
97591478cefSRichard Henderson     }
97691478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
97791478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
97891478cefSRichard Henderson     }
979b1311c4aSEmilio G. Cota 
980b1311c4aSEmilio G. Cota     tcg_ctx = s;
9813468b59eSEmilio G. Cota     /*
9823468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
9833468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
9843468b59eSEmilio G. Cota      * reasoning behind this.
9853468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
9863468b59eSEmilio G. Cota      */
9873468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
988df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
989df2cce29SEmilio G. Cota     n_tcg_ctxs = 1;
9903468b59eSEmilio G. Cota #else
991*5cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
992*5cc8767dSLike Xu     unsigned int max_cpus = ms->smp.max_cpus;
9933468b59eSEmilio G. Cota     tcg_ctxs = g_new(TCGContext *, max_cpus);
9943468b59eSEmilio G. Cota #endif
9951c2adb95SRichard Henderson 
9961c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
9971c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
9981c2adb95SRichard Henderson     cpu_env = temp_tcgv_ptr(ts);
9999002ec79SRichard Henderson }
1000b03cce8eSbellard 
10016e3b2bfdSEmilio G. Cota /*
10026e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
10036e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
10046e3b2bfdSEmilio G. Cota  */
10056e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
10066e3b2bfdSEmilio G. Cota {
10076e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
10086e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
10096e3b2bfdSEmilio G. Cota     void *next;
10106e3b2bfdSEmilio G. Cota 
1011e8feb96fSEmilio G. Cota  retry:
10126e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
10136e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
10146e3b2bfdSEmilio G. Cota 
10156e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
1016e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
10176e3b2bfdSEmilio G. Cota             return NULL;
10186e3b2bfdSEmilio G. Cota         }
1019e8feb96fSEmilio G. Cota         goto retry;
1020e8feb96fSEmilio G. Cota     }
1021e8feb96fSEmilio G. Cota     atomic_set(&s->code_gen_ptr, next);
102257a26946SRichard Henderson     s->data_gen_ptr = NULL;
10236e3b2bfdSEmilio G. Cota     return tb;
10246e3b2bfdSEmilio G. Cota }
10256e3b2bfdSEmilio G. Cota 
10269002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
10279002ec79SRichard Henderson {
10288163b749SRichard Henderson     size_t prologue_size, total_size;
10298163b749SRichard Henderson     void *buf0, *buf1;
10308163b749SRichard Henderson 
10318163b749SRichard Henderson     /* Put the prologue at the beginning of code_gen_buffer.  */
10328163b749SRichard Henderson     buf0 = s->code_gen_buffer;
10335b38ee31SRichard Henderson     total_size = s->code_gen_buffer_size;
10348163b749SRichard Henderson     s->code_ptr = buf0;
10358163b749SRichard Henderson     s->code_buf = buf0;
10365b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
10378163b749SRichard Henderson     s->code_gen_prologue = buf0;
10388163b749SRichard Henderson 
10395b38ee31SRichard Henderson     /* Compute a high-water mark, at which we voluntarily flush the buffer
10405b38ee31SRichard Henderson        and start over.  The size here is arbitrary, significantly larger
10415b38ee31SRichard Henderson        than we expect the code generation for any one opcode to require.  */
10425b38ee31SRichard Henderson     s->code_gen_highwater = s->code_gen_buffer + (total_size - TCG_HIGHWATER);
10435b38ee31SRichard Henderson 
10445b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
10455b38ee31SRichard Henderson     s->pool_labels = NULL;
10465b38ee31SRichard Henderson #endif
10475b38ee31SRichard Henderson 
10488163b749SRichard Henderson     /* Generate the prologue.  */
1049b03cce8eSbellard     tcg_target_qemu_prologue(s);
10505b38ee31SRichard Henderson 
10515b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
10525b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
10535b38ee31SRichard Henderson     {
10541768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
10551768987bSRichard Henderson         tcg_debug_assert(result == 0);
10565b38ee31SRichard Henderson     }
10575b38ee31SRichard Henderson #endif
10585b38ee31SRichard Henderson 
10598163b749SRichard Henderson     buf1 = s->code_ptr;
10608163b749SRichard Henderson     flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1);
10618163b749SRichard Henderson 
10628163b749SRichard Henderson     /* Deduct the prologue from the buffer.  */
10638163b749SRichard Henderson     prologue_size = tcg_current_code_size(s);
10648163b749SRichard Henderson     s->code_gen_ptr = buf1;
10658163b749SRichard Henderson     s->code_gen_buffer = buf1;
10668163b749SRichard Henderson     s->code_buf = buf1;
10675b38ee31SRichard Henderson     total_size -= prologue_size;
10688163b749SRichard Henderson     s->code_gen_buffer_size = total_size;
10698163b749SRichard Henderson 
10708163b749SRichard Henderson     tcg_register_jit(s->code_gen_buffer, total_size);
1071d6b64b2bSRichard Henderson 
1072d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
1073d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
10741ee73216SRichard Henderson         qemu_log_lock();
10758163b749SRichard Henderson         qemu_log("PROLOGUE: [size=%zu]\n", prologue_size);
10765b38ee31SRichard Henderson         if (s->data_gen_ptr) {
10775b38ee31SRichard Henderson             size_t code_size = s->data_gen_ptr - buf0;
10785b38ee31SRichard Henderson             size_t data_size = prologue_size - code_size;
10795b38ee31SRichard Henderson             size_t i;
10805b38ee31SRichard Henderson 
10815b38ee31SRichard Henderson             log_disas(buf0, code_size);
10825b38ee31SRichard Henderson 
10835b38ee31SRichard Henderson             for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
10845b38ee31SRichard Henderson                 if (sizeof(tcg_target_ulong) == 8) {
10855b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
10865b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
10875b38ee31SRichard Henderson                              *(uint64_t *)(s->data_gen_ptr + i));
10885b38ee31SRichard Henderson                 } else {
10895b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .long  0x%08x\n",
10905b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
10915b38ee31SRichard Henderson                              *(uint32_t *)(s->data_gen_ptr + i));
10925b38ee31SRichard Henderson                 }
10935b38ee31SRichard Henderson             }
10945b38ee31SRichard Henderson         } else {
10958163b749SRichard Henderson             log_disas(buf0, prologue_size);
10965b38ee31SRichard Henderson         }
1097d6b64b2bSRichard Henderson         qemu_log("\n");
1098d6b64b2bSRichard Henderson         qemu_log_flush();
10991ee73216SRichard Henderson         qemu_log_unlock();
1100d6b64b2bSRichard Henderson     }
1101d6b64b2bSRichard Henderson #endif
1102cedbcb01SEmilio G. Cota 
1103cedbcb01SEmilio G. Cota     /* Assert that goto_ptr is implemented completely.  */
1104cedbcb01SEmilio G. Cota     if (TCG_TARGET_HAS_goto_ptr) {
1105cedbcb01SEmilio G. Cota         tcg_debug_assert(s->code_gen_epilogue != NULL);
1106cedbcb01SEmilio G. Cota     }
1107c896fe29Sbellard }
1108c896fe29Sbellard 
1109c896fe29Sbellard void tcg_func_start(TCGContext *s)
1110c896fe29Sbellard {
1111c896fe29Sbellard     tcg_pool_reset(s);
1112c896fe29Sbellard     s->nb_temps = s->nb_globals;
11130ec9eabcSRichard Henderson 
11140ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
11150ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
11160ec9eabcSRichard Henderson 
1117abebf925SRichard Henderson     s->nb_ops = 0;
1118c896fe29Sbellard     s->nb_labels = 0;
1119c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1120c896fe29Sbellard 
11210a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
11220a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
11230a209d4bSRichard Henderson #endif
11240a209d4bSRichard Henderson 
112515fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
112615fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
1127bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
1128c896fe29Sbellard }
1129c896fe29Sbellard 
11307ca4b752SRichard Henderson static inline TCGTemp *tcg_temp_alloc(TCGContext *s)
11317ca4b752SRichard Henderson {
11327ca4b752SRichard Henderson     int n = s->nb_temps++;
11337ca4b752SRichard Henderson     tcg_debug_assert(n < TCG_MAX_TEMPS);
11347ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
11357ca4b752SRichard Henderson }
11367ca4b752SRichard Henderson 
11377ca4b752SRichard Henderson static inline TCGTemp *tcg_global_alloc(TCGContext *s)
11387ca4b752SRichard Henderson {
1139fa477d25SRichard Henderson     TCGTemp *ts;
1140fa477d25SRichard Henderson 
11417ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
11427ca4b752SRichard Henderson     s->nb_globals++;
1143fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1144fa477d25SRichard Henderson     ts->temp_global = 1;
1145fa477d25SRichard Henderson 
1146fa477d25SRichard Henderson     return ts;
1147c896fe29Sbellard }
1148c896fe29Sbellard 
1149085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1150b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1151c896fe29Sbellard {
1152c896fe29Sbellard     TCGTemp *ts;
1153c896fe29Sbellard 
1154b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
1155c896fe29Sbellard         tcg_abort();
1156b3a62939SRichard Henderson     }
11577ca4b752SRichard Henderson 
11587ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1159c896fe29Sbellard     ts->base_type = type;
1160c896fe29Sbellard     ts->type = type;
1161c896fe29Sbellard     ts->fixed_reg = 1;
1162c896fe29Sbellard     ts->reg = reg;
1163c896fe29Sbellard     ts->name = name;
1164c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
11657ca4b752SRichard Henderson 
1166085272b3SRichard Henderson     return ts;
1167a7812ae4Spbrook }
1168a7812ae4Spbrook 
1169b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1170a7812ae4Spbrook {
1171b3a62939SRichard Henderson     s->frame_start = start;
1172b3a62939SRichard Henderson     s->frame_end = start + size;
1173085272b3SRichard Henderson     s->frame_temp
1174085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1175b3a62939SRichard Henderson }
1176a7812ae4Spbrook 
1177085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
1178e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
1179c896fe29Sbellard {
1180b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1181dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
11827ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1183b3915dbbSRichard Henderson     int indirect_reg = 0, bigendian = 0;
11847ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
11857ca4b752SRichard Henderson     bigendian = 1;
11867ca4b752SRichard Henderson #endif
1187c896fe29Sbellard 
1188b3915dbbSRichard Henderson     if (!base_ts->fixed_reg) {
11895a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
11905a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1191b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
11925a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
11935a18407fSRichard Henderson                             ? 2 : 1);
11945a18407fSRichard Henderson         indirect_reg = 1;
1195b3915dbbSRichard Henderson     }
1196b3915dbbSRichard Henderson 
11977ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
11987ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1199c896fe29Sbellard         char buf[64];
12007ca4b752SRichard Henderson 
12017ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1202c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1203b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1204c896fe29Sbellard         ts->mem_allocated = 1;
1205b3a62939SRichard Henderson         ts->mem_base = base_ts;
12067ca4b752SRichard Henderson         ts->mem_offset = offset + bigendian * 4;
1207c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1208c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1209c896fe29Sbellard         ts->name = strdup(buf);
1210c896fe29Sbellard 
12117ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
12127ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
12137ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1214b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
12157ca4b752SRichard Henderson         ts2->mem_allocated = 1;
12167ca4b752SRichard Henderson         ts2->mem_base = base_ts;
12177ca4b752SRichard Henderson         ts2->mem_offset = offset + (1 - bigendian) * 4;
1218c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1219c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1220120c1084SRichard Henderson         ts2->name = strdup(buf);
12217ca4b752SRichard Henderson     } else {
1222c896fe29Sbellard         ts->base_type = type;
1223c896fe29Sbellard         ts->type = type;
1224b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1225c896fe29Sbellard         ts->mem_allocated = 1;
1226b3a62939SRichard Henderson         ts->mem_base = base_ts;
1227c896fe29Sbellard         ts->mem_offset = offset;
1228c896fe29Sbellard         ts->name = name;
1229c896fe29Sbellard     }
1230085272b3SRichard Henderson     return ts;
1231c896fe29Sbellard }
1232c896fe29Sbellard 
12335bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local)
1234c896fe29Sbellard {
1235b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1236c896fe29Sbellard     TCGTemp *ts;
1237641d5fbeSbellard     int idx, k;
1238c896fe29Sbellard 
12390ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
12400ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
12410ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
12420ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
12430ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
12440ec9eabcSRichard Henderson 
1245e8996ee0Sbellard         ts = &s->temps[idx];
1246e8996ee0Sbellard         ts->temp_allocated = 1;
12477ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
12487ca4b752SRichard Henderson         tcg_debug_assert(ts->temp_local == temp_local);
1249e8996ee0Sbellard     } else {
12507ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
12517ca4b752SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
12527ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
12537ca4b752SRichard Henderson 
1254c896fe29Sbellard             ts->base_type = type;
1255c896fe29Sbellard             ts->type = TCG_TYPE_I32;
1256e8996ee0Sbellard             ts->temp_allocated = 1;
1257641d5fbeSbellard             ts->temp_local = temp_local;
12587ca4b752SRichard Henderson 
12597ca4b752SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
12607ca4b752SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
12617ca4b752SRichard Henderson             ts2->type = TCG_TYPE_I32;
12627ca4b752SRichard Henderson             ts2->temp_allocated = 1;
12637ca4b752SRichard Henderson             ts2->temp_local = temp_local;
12647ca4b752SRichard Henderson         } else {
1265c896fe29Sbellard             ts->base_type = type;
1266c896fe29Sbellard             ts->type = type;
1267e8996ee0Sbellard             ts->temp_allocated = 1;
1268641d5fbeSbellard             ts->temp_local = temp_local;
1269c896fe29Sbellard         }
1270e8996ee0Sbellard     }
127127bfd83cSPeter Maydell 
127227bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
127327bfd83cSPeter Maydell     s->temps_in_use++;
127427bfd83cSPeter Maydell #endif
1275085272b3SRichard Henderson     return ts;
1276c896fe29Sbellard }
1277c896fe29Sbellard 
1278d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1279d2fd745fSRichard Henderson {
1280d2fd745fSRichard Henderson     TCGTemp *t;
1281d2fd745fSRichard Henderson 
1282d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1283d2fd745fSRichard Henderson     switch (type) {
1284d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1285d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1286d2fd745fSRichard Henderson         break;
1287d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1288d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1289d2fd745fSRichard Henderson         break;
1290d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1291d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1292d2fd745fSRichard Henderson         break;
1293d2fd745fSRichard Henderson     default:
1294d2fd745fSRichard Henderson         g_assert_not_reached();
1295d2fd745fSRichard Henderson     }
1296d2fd745fSRichard Henderson #endif
1297d2fd745fSRichard Henderson 
1298d2fd745fSRichard Henderson     t = tcg_temp_new_internal(type, 0);
1299d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1300d2fd745fSRichard Henderson }
1301d2fd745fSRichard Henderson 
1302d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1303d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1304d2fd745fSRichard Henderson {
1305d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1306d2fd745fSRichard Henderson 
1307d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1308d2fd745fSRichard Henderson 
1309d2fd745fSRichard Henderson     t = tcg_temp_new_internal(t->base_type, 0);
1310d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1311d2fd745fSRichard Henderson }
1312d2fd745fSRichard Henderson 
13135bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1314c896fe29Sbellard {
1315b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1316085272b3SRichard Henderson     int k, idx;
1317c896fe29Sbellard 
131827bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
131927bfd83cSPeter Maydell     s->temps_in_use--;
132027bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
132127bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
132227bfd83cSPeter Maydell     }
132327bfd83cSPeter Maydell #endif
132427bfd83cSPeter Maydell 
1325085272b3SRichard Henderson     tcg_debug_assert(ts->temp_global == 0);
1326eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
1327e8996ee0Sbellard     ts->temp_allocated = 0;
13280ec9eabcSRichard Henderson 
1329085272b3SRichard Henderson     idx = temp_idx(ts);
133018d13fa2SAlexander Graf     k = ts->base_type + (ts->temp_local ? TCG_TYPE_COUNT : 0);
13310ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
1332e8996ee0Sbellard }
1333e8996ee0Sbellard 
1334a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
1335a7812ae4Spbrook {
1336a7812ae4Spbrook     TCGv_i32 t0;
1337a7812ae4Spbrook     t0 = tcg_temp_new_i32();
1338e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
1339e8996ee0Sbellard     return t0;
1340c896fe29Sbellard }
1341c896fe29Sbellard 
1342a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
1343c896fe29Sbellard {
1344a7812ae4Spbrook     TCGv_i64 t0;
1345a7812ae4Spbrook     t0 = tcg_temp_new_i64();
1346e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
1347e8996ee0Sbellard     return t0;
1348c896fe29Sbellard }
1349c896fe29Sbellard 
1350a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
1351bdffd4a9Saurel32 {
1352a7812ae4Spbrook     TCGv_i32 t0;
1353a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
1354bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
1355bdffd4a9Saurel32     return t0;
1356bdffd4a9Saurel32 }
1357bdffd4a9Saurel32 
1358a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
1359bdffd4a9Saurel32 {
1360a7812ae4Spbrook     TCGv_i64 t0;
1361a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
1362bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
1363bdffd4a9Saurel32     return t0;
1364bdffd4a9Saurel32 }
1365bdffd4a9Saurel32 
136627bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
136727bfd83cSPeter Maydell void tcg_clear_temp_count(void)
136827bfd83cSPeter Maydell {
1369b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
137027bfd83cSPeter Maydell     s->temps_in_use = 0;
137127bfd83cSPeter Maydell }
137227bfd83cSPeter Maydell 
137327bfd83cSPeter Maydell int tcg_check_temp_count(void)
137427bfd83cSPeter Maydell {
1375b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
137627bfd83cSPeter Maydell     if (s->temps_in_use) {
137727bfd83cSPeter Maydell         /* Clear the count so that we don't give another
137827bfd83cSPeter Maydell          * warning immediately next time around.
137927bfd83cSPeter Maydell          */
138027bfd83cSPeter Maydell         s->temps_in_use = 0;
138127bfd83cSPeter Maydell         return 1;
138227bfd83cSPeter Maydell     }
138327bfd83cSPeter Maydell     return 0;
138427bfd83cSPeter Maydell }
138527bfd83cSPeter Maydell #endif
138627bfd83cSPeter Maydell 
1387be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1388be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1389be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1390be0f34b5SRichard Henderson {
1391d2fd745fSRichard Henderson     const bool have_vec
1392d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1393d2fd745fSRichard Henderson 
1394be0f34b5SRichard Henderson     switch (op) {
1395be0f34b5SRichard Henderson     case INDEX_op_discard:
1396be0f34b5SRichard Henderson     case INDEX_op_set_label:
1397be0f34b5SRichard Henderson     case INDEX_op_call:
1398be0f34b5SRichard Henderson     case INDEX_op_br:
1399be0f34b5SRichard Henderson     case INDEX_op_mb:
1400be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1401be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1402be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1403be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i32:
1404be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i32:
1405be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i64:
1406be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i64:
1407be0f34b5SRichard Henderson         return true;
1408be0f34b5SRichard Henderson 
1409be0f34b5SRichard Henderson     case INDEX_op_goto_ptr:
1410be0f34b5SRichard Henderson         return TCG_TARGET_HAS_goto_ptr;
1411be0f34b5SRichard Henderson 
1412be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1413be0f34b5SRichard Henderson     case INDEX_op_movi_i32:
1414be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1415be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1416be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1417be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1418be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1419be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1420be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1421be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1422be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1423be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1424be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1425be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1426be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1427be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1428be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1429be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1430be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1431be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1432be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1433be0f34b5SRichard Henderson         return true;
1434be0f34b5SRichard Henderson 
1435be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1436be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1437be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1438be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1439be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1440be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1441be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1442be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1443be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1444be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1445be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1446be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1447be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1448be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1449be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1450be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1451be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1452be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1453be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1454be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1455fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
1456fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
1457be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1458be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1459be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1460be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1461be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1462be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1463be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1464be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1465be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1466be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1467be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1468be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1469be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1470be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1471be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1472be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1473be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1474be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1475be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1476be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1477be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1478be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1479be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1480be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1481be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1482be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1483be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1484be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1485be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1486be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1487be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1488be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1489be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1490be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1491be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1492be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1493be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1494be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1495be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1496be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1497be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1498be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1499be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1500be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1501be0f34b5SRichard Henderson 
1502be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1503be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1504be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1505be0f34b5SRichard Henderson 
1506be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1507be0f34b5SRichard Henderson     case INDEX_op_movi_i64:
1508be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1509be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1510be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1511be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1512be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1513be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1514be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1515be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1516be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1517be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1518be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1519be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1520be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1521be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1522be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1523be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1524be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1525be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1526be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1527be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1528be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1529be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1530be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1531be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1532be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1533be0f34b5SRichard Henderson 
1534be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1535be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1536be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1537be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1538be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1539be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1540be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1541be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1542be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1543be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
1544be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
1545be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
1546be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
1547be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
1548be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
1549be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
1550be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
1551be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
1552be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
1553be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
1554fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
1555fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
1556be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
1557be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrl_i64_i32;
1558be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
1559be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrh_i64_i32;
1560be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
1561be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
1562be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
1563be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
1564be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
1565be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
1566be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
1567be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
1568be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
1569be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
1570be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
1571be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
1572be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
1573be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
1574be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
1575be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
1576be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
1577be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
1578be0f34b5SRichard Henderson     case INDEX_op_not_i64:
1579be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
1580be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
1581be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
1582be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
1583be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
1584be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
1585be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
1586be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
1587be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
1588be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
1589be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
1590be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
1591be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
1592be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
1593be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
1594be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
1595be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
1596be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
1597be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
1598be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
1599be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
1600be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
1601be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
1602be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
1603be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
1604be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
1605be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
1606be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
1607be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
1608be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
1609be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
1610be0f34b5SRichard Henderson 
1611d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
1612d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
1613d2fd745fSRichard Henderson     case INDEX_op_dupi_vec:
161437ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
1615d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
1616d2fd745fSRichard Henderson     case INDEX_op_st_vec:
1617d2fd745fSRichard Henderson     case INDEX_op_add_vec:
1618d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
1619d2fd745fSRichard Henderson     case INDEX_op_and_vec:
1620d2fd745fSRichard Henderson     case INDEX_op_or_vec:
1621d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
1622212be173SRichard Henderson     case INDEX_op_cmp_vec:
1623d2fd745fSRichard Henderson         return have_vec;
1624d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
1625d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
1626d2fd745fSRichard Henderson     case INDEX_op_not_vec:
1627d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
1628d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
1629d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
1630bcefc902SRichard Henderson     case INDEX_op_abs_vec:
1631bcefc902SRichard Henderson         return have_vec && TCG_TARGET_HAS_abs_vec;
1632d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
1633d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
1634d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
1635d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
16363774030aSRichard Henderson     case INDEX_op_mul_vec:
16373774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
1638d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
1639d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
1640d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
1641d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
1642d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
1643d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
1644d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
1645d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
1646d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
1647d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
1648d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
1649d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
16508afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
16518afaf050SRichard Henderson     case INDEX_op_usadd_vec:
16528afaf050SRichard Henderson     case INDEX_op_sssub_vec:
16538afaf050SRichard Henderson     case INDEX_op_ussub_vec:
16548afaf050SRichard Henderson         return have_vec && TCG_TARGET_HAS_sat_vec;
1655dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
1656dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
1657dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
1658dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
1659dd0a0fcdSRichard Henderson         return have_vec && TCG_TARGET_HAS_minmax_vec;
166038dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
166138dc1294SRichard Henderson         return have_vec && TCG_TARGET_HAS_bitsel_vec;
1662f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
1663f75da298SRichard Henderson         return have_vec && TCG_TARGET_HAS_cmpsel_vec;
1664d2fd745fSRichard Henderson 
1665db432672SRichard Henderson     default:
1666db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
1667db432672SRichard Henderson         return true;
1668be0f34b5SRichard Henderson     }
1669be0f34b5SRichard Henderson }
1670be0f34b5SRichard Henderson 
167139cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment
167239cf05d3Sbellard    and endian swap. Maybe it would be better to do the alignment
167339cf05d3Sbellard    and endian swap in tcg_reg_alloc_call(). */
1674ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
1675c896fe29Sbellard {
167675e8b9b7SRichard Henderson     int i, real_args, nb_rets, pi;
1677bbb8a1b4SRichard Henderson     unsigned sizemask, flags;
1678afb49896SRichard Henderson     TCGHelperInfo *info;
167975e8b9b7SRichard Henderson     TCGOp *op;
1680afb49896SRichard Henderson 
1681619205fdSEmilio G. Cota     info = g_hash_table_lookup(helper_table, (gpointer)func);
1682bbb8a1b4SRichard Henderson     flags = info->flags;
1683bbb8a1b4SRichard Henderson     sizemask = info->sizemask;
16842bece2c8SRichard Henderson 
168534b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
168634b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
168734b1a49cSRichard Henderson     /* We have 64-bit values in one register, but need to pass as two
168834b1a49cSRichard Henderson        separate parameters.  Split them.  */
168934b1a49cSRichard Henderson     int orig_sizemask = sizemask;
169034b1a49cSRichard Henderson     int orig_nargs = nargs;
169134b1a49cSRichard Henderson     TCGv_i64 retl, reth;
1692ae8b75dcSRichard Henderson     TCGTemp *split_args[MAX_OPC_PARAM];
169334b1a49cSRichard Henderson 
1694f764718dSRichard Henderson     retl = NULL;
1695f764718dSRichard Henderson     reth = NULL;
169634b1a49cSRichard Henderson     if (sizemask != 0) {
169734b1a49cSRichard Henderson         for (i = real_args = 0; i < nargs; ++i) {
169834b1a49cSRichard Henderson             int is_64bit = sizemask & (1 << (i+1)*2);
169934b1a49cSRichard Henderson             if (is_64bit) {
1700085272b3SRichard Henderson                 TCGv_i64 orig = temp_tcgv_i64(args[i]);
170134b1a49cSRichard Henderson                 TCGv_i32 h = tcg_temp_new_i32();
170234b1a49cSRichard Henderson                 TCGv_i32 l = tcg_temp_new_i32();
170334b1a49cSRichard Henderson                 tcg_gen_extr_i64_i32(l, h, orig);
1704ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(h);
1705ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(l);
170634b1a49cSRichard Henderson             } else {
170734b1a49cSRichard Henderson                 split_args[real_args++] = args[i];
170834b1a49cSRichard Henderson             }
170934b1a49cSRichard Henderson         }
171034b1a49cSRichard Henderson         nargs = real_args;
171134b1a49cSRichard Henderson         args = split_args;
171234b1a49cSRichard Henderson         sizemask = 0;
171334b1a49cSRichard Henderson     }
171434b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
17152bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
17162bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
17172bece2c8SRichard Henderson         int is_signed = sizemask & (2 << (i+1)*2);
17182bece2c8SRichard Henderson         if (!is_64bit) {
17192bece2c8SRichard Henderson             TCGv_i64 temp = tcg_temp_new_i64();
1720085272b3SRichard Henderson             TCGv_i64 orig = temp_tcgv_i64(args[i]);
17212bece2c8SRichard Henderson             if (is_signed) {
17222bece2c8SRichard Henderson                 tcg_gen_ext32s_i64(temp, orig);
17232bece2c8SRichard Henderson             } else {
17242bece2c8SRichard Henderson                 tcg_gen_ext32u_i64(temp, orig);
17252bece2c8SRichard Henderson             }
1726ae8b75dcSRichard Henderson             args[i] = tcgv_i64_temp(temp);
17272bece2c8SRichard Henderson         }
17282bece2c8SRichard Henderson     }
17292bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
17302bece2c8SRichard Henderson 
173115fa08f8SRichard Henderson     op = tcg_emit_op(INDEX_op_call);
173275e8b9b7SRichard Henderson 
173375e8b9b7SRichard Henderson     pi = 0;
1734ae8b75dcSRichard Henderson     if (ret != NULL) {
173534b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
173634b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
173734b1a49cSRichard Henderson         if (orig_sizemask & 1) {
173834b1a49cSRichard Henderson             /* The 32-bit ABI is going to return the 64-bit value in
173934b1a49cSRichard Henderson                the %o0/%o1 register pair.  Prepare for this by using
174034b1a49cSRichard Henderson                two return temporaries, and reassemble below.  */
174134b1a49cSRichard Henderson             retl = tcg_temp_new_i64();
174234b1a49cSRichard Henderson             reth = tcg_temp_new_i64();
1743ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(reth);
1744ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(retl);
174534b1a49cSRichard Henderson             nb_rets = 2;
174634b1a49cSRichard Henderson         } else {
1747ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
174834b1a49cSRichard Henderson             nb_rets = 1;
174934b1a49cSRichard Henderson         }
175034b1a49cSRichard Henderson #else
175134b1a49cSRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) {
175202eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
1753ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1754ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1755a7812ae4Spbrook #else
1756ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1757ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1758a7812ae4Spbrook #endif
1759a7812ae4Spbrook             nb_rets = 2;
176034b1a49cSRichard Henderson         } else {
1761ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1762a7812ae4Spbrook             nb_rets = 1;
1763a7812ae4Spbrook         }
176434b1a49cSRichard Henderson #endif
1765a7812ae4Spbrook     } else {
1766a7812ae4Spbrook         nb_rets = 0;
1767a7812ae4Spbrook     }
1768cd9090aaSRichard Henderson     TCGOP_CALLO(op) = nb_rets;
176975e8b9b7SRichard Henderson 
1770a7812ae4Spbrook     real_args = 0;
1771a7812ae4Spbrook     for (i = 0; i < nargs; i++) {
17722bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
1773bbb8a1b4SRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
177439cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS
177539cf05d3Sbellard             /* some targets want aligned 64 bit args */
1776ebd486d5Smalc             if (real_args & 1) {
177775e8b9b7SRichard Henderson                 op->args[pi++] = TCG_CALL_DUMMY_ARG;
1778ebd486d5Smalc                 real_args++;
177939cf05d3Sbellard             }
178039cf05d3Sbellard #endif
17813f90f252SRichard Henderson            /* If stack grows up, then we will be placing successive
17823f90f252SRichard Henderson               arguments at lower addresses, which means we need to
17833f90f252SRichard Henderson               reverse the order compared to how we would normally
17843f90f252SRichard Henderson               treat either big or little-endian.  For those arguments
17853f90f252SRichard Henderson               that will wind up in registers, this still works for
17863f90f252SRichard Henderson               HPPA (the only current STACK_GROWSUP target) since the
17873f90f252SRichard Henderson               argument registers are *also* allocated in decreasing
17883f90f252SRichard Henderson               order.  If another such target is added, this logic may
17893f90f252SRichard Henderson               have to get more complicated to differentiate between
17903f90f252SRichard Henderson               stack arguments and register arguments.  */
179102eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
1792ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1793ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1794c896fe29Sbellard #else
1795ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1796ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1797c896fe29Sbellard #endif
1798a7812ae4Spbrook             real_args += 2;
17992bece2c8SRichard Henderson             continue;
18002bece2c8SRichard Henderson         }
18012bece2c8SRichard Henderson 
1802ae8b75dcSRichard Henderson         op->args[pi++] = temp_arg(args[i]);
1803a7812ae4Spbrook         real_args++;
1804c896fe29Sbellard     }
180575e8b9b7SRichard Henderson     op->args[pi++] = (uintptr_t)func;
180675e8b9b7SRichard Henderson     op->args[pi++] = flags;
1807cd9090aaSRichard Henderson     TCGOP_CALLI(op) = real_args;
1808a7812ae4Spbrook 
180975e8b9b7SRichard Henderson     /* Make sure the fields didn't overflow.  */
1810cd9090aaSRichard Henderson     tcg_debug_assert(TCGOP_CALLI(op) == real_args);
181175e8b9b7SRichard Henderson     tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
18122bece2c8SRichard Henderson 
181334b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
181434b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
181534b1a49cSRichard Henderson     /* Free all of the parts we allocated above.  */
181634b1a49cSRichard Henderson     for (i = real_args = 0; i < orig_nargs; ++i) {
181734b1a49cSRichard Henderson         int is_64bit = orig_sizemask & (1 << (i+1)*2);
181834b1a49cSRichard Henderson         if (is_64bit) {
1819085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
1820085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
182134b1a49cSRichard Henderson         } else {
182234b1a49cSRichard Henderson             real_args++;
182334b1a49cSRichard Henderson         }
182434b1a49cSRichard Henderson     }
182534b1a49cSRichard Henderson     if (orig_sizemask & 1) {
182634b1a49cSRichard Henderson         /* The 32-bit ABI returned two 32-bit pieces.  Re-assemble them.
182734b1a49cSRichard Henderson            Note that describing these as TCGv_i64 eliminates an unnecessary
182834b1a49cSRichard Henderson            zero-extension that tcg_gen_concat_i32_i64 would create.  */
1829085272b3SRichard Henderson         tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth);
183034b1a49cSRichard Henderson         tcg_temp_free_i64(retl);
183134b1a49cSRichard Henderson         tcg_temp_free_i64(reth);
183234b1a49cSRichard Henderson     }
183334b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
18342bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
18352bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
18362bece2c8SRichard Henderson         if (!is_64bit) {
1837085272b3SRichard Henderson             tcg_temp_free_internal(args[i]);
18382bece2c8SRichard Henderson         }
18392bece2c8SRichard Henderson     }
18402bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
1841a7812ae4Spbrook }
1842c896fe29Sbellard 
18438fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
1844c896fe29Sbellard {
1845ac3b8891SRichard Henderson     int i, n;
1846c896fe29Sbellard     TCGTemp *ts;
1847ac3b8891SRichard Henderson 
1848ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
1849c896fe29Sbellard         ts = &s->temps[i];
1850ac3b8891SRichard Henderson         ts->val_type = (ts->fixed_reg ? TEMP_VAL_REG : TEMP_VAL_MEM);
1851c896fe29Sbellard     }
1852ac3b8891SRichard Henderson     for (n = s->nb_temps; i < n; i++) {
1853e8996ee0Sbellard         ts = &s->temps[i];
1854ac3b8891SRichard Henderson         ts->val_type = (ts->temp_local ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
1855e8996ee0Sbellard         ts->mem_allocated = 0;
1856e8996ee0Sbellard         ts->fixed_reg = 0;
1857e8996ee0Sbellard     }
1858f8b2f202SRichard Henderson 
1859f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
1860c896fe29Sbellard }
1861c896fe29Sbellard 
1862f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
1863f8b2f202SRichard Henderson                                  TCGTemp *ts)
1864c896fe29Sbellard {
18651807f4c4SRichard Henderson     int idx = temp_idx(ts);
1866ac56dd48Spbrook 
1867fa477d25SRichard Henderson     if (ts->temp_global) {
1868ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
1869f8b2f202SRichard Henderson     } else if (ts->temp_local) {
1870641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
1871f8b2f202SRichard Henderson     } else {
1872ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
1873c896fe29Sbellard     }
1874c896fe29Sbellard     return buf;
1875c896fe29Sbellard }
1876c896fe29Sbellard 
187743439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
187843439139SRichard Henderson                              int buf_size, TCGArg arg)
1879f8b2f202SRichard Henderson {
188043439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
1881f8b2f202SRichard Henderson }
1882f8b2f202SRichard Henderson 
18836e085f72SRichard Henderson /* Find helper name.  */
18846e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val)
1885e8996ee0Sbellard {
18866e085f72SRichard Henderson     const char *ret = NULL;
1887619205fdSEmilio G. Cota     if (helper_table) {
1888619205fdSEmilio G. Cota         TCGHelperInfo *info = g_hash_table_lookup(helper_table, (gpointer)val);
188972866e82SRichard Henderson         if (info) {
189072866e82SRichard Henderson             ret = info->name;
189172866e82SRichard Henderson         }
1892e8996ee0Sbellard     }
18936e085f72SRichard Henderson     return ret;
18944dc81f28Sbellard }
18954dc81f28Sbellard 
1896f48f3edeSblueswir1 static const char * const cond_name[] =
1897f48f3edeSblueswir1 {
18980aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
18990aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
1900f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
1901f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
1902f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
1903f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
1904f48f3edeSblueswir1     [TCG_COND_LE] = "le",
1905f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
1906f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
1907f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
1908f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
1909f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
1910f48f3edeSblueswir1 };
1911f48f3edeSblueswir1 
1912f713d6adSRichard Henderson static const char * const ldst_name[] =
1913f713d6adSRichard Henderson {
1914f713d6adSRichard Henderson     [MO_UB]   = "ub",
1915f713d6adSRichard Henderson     [MO_SB]   = "sb",
1916f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
1917f713d6adSRichard Henderson     [MO_LESW] = "lesw",
1918f713d6adSRichard Henderson     [MO_LEUL] = "leul",
1919f713d6adSRichard Henderson     [MO_LESL] = "lesl",
1920f713d6adSRichard Henderson     [MO_LEQ]  = "leq",
1921f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
1922f713d6adSRichard Henderson     [MO_BESW] = "besw",
1923f713d6adSRichard Henderson     [MO_BEUL] = "beul",
1924f713d6adSRichard Henderson     [MO_BESL] = "besl",
1925f713d6adSRichard Henderson     [MO_BEQ]  = "beq",
1926f713d6adSRichard Henderson };
1927f713d6adSRichard Henderson 
19281f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
19291f00b27fSSergey Sorokin #ifdef ALIGNED_ONLY
19301f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
19311f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
19321f00b27fSSergey Sorokin #else
19331f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
19341f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
19351f00b27fSSergey Sorokin #endif
19361f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
19371f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
19381f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
19391f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
19401f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
19411f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
19421f00b27fSSergey Sorokin };
19431f00b27fSSergey Sorokin 
1944b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
1945b016486eSRichard Henderson {
1946b016486eSRichard Henderson     return (d & (d - 1)) == 0;
1947b016486eSRichard Henderson }
1948b016486eSRichard Henderson 
1949b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
1950b016486eSRichard Henderson {
1951b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
1952b016486eSRichard Henderson         return ctz32(d);
1953b016486eSRichard Henderson     } else {
1954b016486eSRichard Henderson         return ctz64(d);
1955b016486eSRichard Henderson     }
1956b016486eSRichard Henderson }
1957b016486eSRichard Henderson 
19581894f69aSRichard Henderson static void tcg_dump_ops(TCGContext *s, bool have_prefs)
1959c896fe29Sbellard {
1960c896fe29Sbellard     char buf[128];
1961c45cb8bbSRichard Henderson     TCGOp *op;
1962c896fe29Sbellard 
196315fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
1964c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
1965c45cb8bbSRichard Henderson         const TCGOpDef *def;
1966c45cb8bbSRichard Henderson         TCGOpcode c;
1967bdfb460eSRichard Henderson         int col = 0;
1968c45cb8bbSRichard Henderson 
1969c45cb8bbSRichard Henderson         c = op->opc;
1970c896fe29Sbellard         def = &tcg_op_defs[c];
1971c45cb8bbSRichard Henderson 
1972765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
1973b016486eSRichard Henderson             nb_oargs = 0;
197415fa08f8SRichard Henderson             col += qemu_log("\n ----");
19759aef40edSRichard Henderson 
19769aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
19779aef40edSRichard Henderson                 target_ulong a;
19787e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
1979efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
19807e4597d7Sbellard #else
1981efee3746SRichard Henderson                 a = op->args[i];
19827e4597d7Sbellard #endif
1983bdfb460eSRichard Henderson                 col += qemu_log(" " TARGET_FMT_lx, a);
1984eeacee4dSBlue Swirl             }
19857e4597d7Sbellard         } else if (c == INDEX_op_call) {
1986c896fe29Sbellard             /* variable number of arguments */
1987cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
1988cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
1989c896fe29Sbellard             nb_cargs = def->nb_cargs;
1990b03cce8eSbellard 
1991cf066674SRichard Henderson             /* function name, flags, out args */
1992bdfb460eSRichard Henderson             col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name,
1993efee3746SRichard Henderson                             tcg_find_helper(s, op->args[nb_oargs + nb_iargs]),
1994efee3746SRichard Henderson                             op->args[nb_oargs + nb_iargs + 1], nb_oargs);
1995b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
199643439139SRichard Henderson                 col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf),
1997efee3746SRichard Henderson                                                        op->args[i]));
1998b03cce8eSbellard             }
1999cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
2000efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
2001cf066674SRichard Henderson                 const char *t = "<dummy>";
2002cf066674SRichard Henderson                 if (arg != TCG_CALL_DUMMY_ARG) {
200343439139SRichard Henderson                     t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
2004b03cce8eSbellard                 }
2005bdfb460eSRichard Henderson                 col += qemu_log(",%s", t);
2006e8996ee0Sbellard             }
2007b03cce8eSbellard         } else {
2008bdfb460eSRichard Henderson             col += qemu_log(" %s ", def->name);
2009c45cb8bbSRichard Henderson 
2010c896fe29Sbellard             nb_oargs = def->nb_oargs;
2011c896fe29Sbellard             nb_iargs = def->nb_iargs;
2012c896fe29Sbellard             nb_cargs = def->nb_cargs;
2013c896fe29Sbellard 
2014d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
2015d2fd745fSRichard Henderson                 col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op),
2016d2fd745fSRichard Henderson                                 8 << TCGOP_VECE(op));
2017d2fd745fSRichard Henderson             }
2018d2fd745fSRichard Henderson 
2019c896fe29Sbellard             k = 0;
2020c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
2021eeacee4dSBlue Swirl                 if (k != 0) {
2022bdfb460eSRichard Henderson                     col += qemu_log(",");
2023eeacee4dSBlue Swirl                 }
202443439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2025efee3746SRichard Henderson                                                       op->args[k++]));
2026c896fe29Sbellard             }
2027c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
2028eeacee4dSBlue Swirl                 if (k != 0) {
2029bdfb460eSRichard Henderson                     col += qemu_log(",");
2030eeacee4dSBlue Swirl                 }
203143439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2032efee3746SRichard Henderson                                                       op->args[k++]));
2033c896fe29Sbellard             }
2034be210acbSRichard Henderson             switch (c) {
2035be210acbSRichard Henderson             case INDEX_op_brcond_i32:
2036ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
2037ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
2038be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
2039be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
2040ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
2041be210acbSRichard Henderson             case INDEX_op_setcond_i64:
2042ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
2043212be173SRichard Henderson             case INDEX_op_cmp_vec:
2044f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
2045efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
2046efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
2047efee3746SRichard Henderson                     col += qemu_log(",%s", cond_name[op->args[k++]]);
2048eeacee4dSBlue Swirl                 } else {
2049efee3746SRichard Henderson                     col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]);
2050eeacee4dSBlue Swirl                 }
2051f48f3edeSblueswir1                 i = 1;
2052be210acbSRichard Henderson                 break;
2053f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
2054f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
2055f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
2056f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
205759227d5dSRichard Henderson                 {
2058efee3746SRichard Henderson                     TCGMemOpIdx oi = op->args[k++];
205959227d5dSRichard Henderson                     TCGMemOp op = get_memop(oi);
206059227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
206159227d5dSRichard Henderson 
206259c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
2063bdfb460eSRichard Henderson                         col += qemu_log(",$0x%x,%u", op, ix);
206459c4b7e8SRichard Henderson                     } else {
20651f00b27fSSergey Sorokin                         const char *s_al, *s_op;
20661f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
206759c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
2068bdfb460eSRichard Henderson                         col += qemu_log(",%s%s,%u", s_al, s_op, ix);
2069f713d6adSRichard Henderson                     }
2070f713d6adSRichard Henderson                     i = 1;
207159227d5dSRichard Henderson                 }
2072f713d6adSRichard Henderson                 break;
2073be210acbSRichard Henderson             default:
2074f48f3edeSblueswir1                 i = 0;
2075be210acbSRichard Henderson                 break;
2076be210acbSRichard Henderson             }
207751e3972cSRichard Henderson             switch (c) {
207851e3972cSRichard Henderson             case INDEX_op_set_label:
207951e3972cSRichard Henderson             case INDEX_op_br:
208051e3972cSRichard Henderson             case INDEX_op_brcond_i32:
208151e3972cSRichard Henderson             case INDEX_op_brcond_i64:
208251e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2083efee3746SRichard Henderson                 col += qemu_log("%s$L%d", k ? "," : "",
2084efee3746SRichard Henderson                                 arg_label(op->args[k])->id);
208551e3972cSRichard Henderson                 i++, k++;
208651e3972cSRichard Henderson                 break;
208751e3972cSRichard Henderson             default:
208851e3972cSRichard Henderson                 break;
2089eeacee4dSBlue Swirl             }
209051e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
2091efee3746SRichard Henderson                 col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]);
2092bdfb460eSRichard Henderson             }
2093bdfb460eSRichard Henderson         }
2094bdfb460eSRichard Henderson 
20951894f69aSRichard Henderson         if (have_prefs || op->life) {
20961894f69aSRichard Henderson             for (; col < 40; ++col) {
2097bdfb460eSRichard Henderson                 putc(' ', qemu_logfile);
2098bdfb460eSRichard Henderson             }
20991894f69aSRichard Henderson         }
21001894f69aSRichard Henderson 
21011894f69aSRichard Henderson         if (op->life) {
21021894f69aSRichard Henderson             unsigned life = op->life;
2103bdfb460eSRichard Henderson 
2104bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
2105bdfb460eSRichard Henderson                 qemu_log("  sync:");
2106bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
2107bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
2108bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2109bdfb460eSRichard Henderson                     }
2110bdfb460eSRichard Henderson                 }
2111bdfb460eSRichard Henderson             }
2112bdfb460eSRichard Henderson             life /= DEAD_ARG;
2113bdfb460eSRichard Henderson             if (life) {
2114bdfb460eSRichard Henderson                 qemu_log("  dead:");
2115bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
2116bdfb460eSRichard Henderson                     if (life & 1) {
2117bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2118bdfb460eSRichard Henderson                     }
2119bdfb460eSRichard Henderson                 }
2120c896fe29Sbellard             }
2121b03cce8eSbellard         }
21221894f69aSRichard Henderson 
21231894f69aSRichard Henderson         if (have_prefs) {
21241894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
21251894f69aSRichard Henderson                 TCGRegSet set = op->output_pref[i];
21261894f69aSRichard Henderson 
21271894f69aSRichard Henderson                 if (i == 0) {
21281894f69aSRichard Henderson                     qemu_log("  pref=");
21291894f69aSRichard Henderson                 } else {
21301894f69aSRichard Henderson                     qemu_log(",");
21311894f69aSRichard Henderson                 }
21321894f69aSRichard Henderson                 if (set == 0) {
21331894f69aSRichard Henderson                     qemu_log("none");
21341894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
21351894f69aSRichard Henderson                     qemu_log("all");
21361894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
21371894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
21381894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
21391894f69aSRichard Henderson                     qemu_log("%s", tcg_target_reg_names[reg]);
21401894f69aSRichard Henderson #endif
21411894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
21421894f69aSRichard Henderson                     qemu_log("%#x", (uint32_t)set);
21431894f69aSRichard Henderson                 } else {
21441894f69aSRichard Henderson                     qemu_log("%#" PRIx64, (uint64_t)set);
21451894f69aSRichard Henderson                 }
21461894f69aSRichard Henderson             }
21471894f69aSRichard Henderson         }
21481894f69aSRichard Henderson 
2149eeacee4dSBlue Swirl         qemu_log("\n");
2150c896fe29Sbellard     }
2151c896fe29Sbellard }
2152c896fe29Sbellard 
2153c896fe29Sbellard /* we give more priority to constraints with less registers */
2154c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2155c896fe29Sbellard {
2156c896fe29Sbellard     const TCGArgConstraint *arg_ct;
2157c896fe29Sbellard 
2158c896fe29Sbellard     int i, n;
2159c896fe29Sbellard     arg_ct = &def->args_ct[k];
2160c896fe29Sbellard     if (arg_ct->ct & TCG_CT_ALIAS) {
2161c896fe29Sbellard         /* an alias is equivalent to a single register */
2162c896fe29Sbellard         n = 1;
2163c896fe29Sbellard     } else {
2164c896fe29Sbellard         if (!(arg_ct->ct & TCG_CT_REG))
2165c896fe29Sbellard             return 0;
2166c896fe29Sbellard         n = 0;
2167c896fe29Sbellard         for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
2168c896fe29Sbellard             if (tcg_regset_test_reg(arg_ct->u.regs, i))
2169c896fe29Sbellard                 n++;
2170c896fe29Sbellard         }
2171c896fe29Sbellard     }
2172c896fe29Sbellard     return TCG_TARGET_NB_REGS - n + 1;
2173c896fe29Sbellard }
2174c896fe29Sbellard 
2175c896fe29Sbellard /* sort from highest priority to lowest */
2176c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2177c896fe29Sbellard {
2178c896fe29Sbellard     int i, j, p1, p2, tmp;
2179c896fe29Sbellard 
2180c896fe29Sbellard     for(i = 0; i < n; i++)
2181c896fe29Sbellard         def->sorted_args[start + i] = start + i;
2182c896fe29Sbellard     if (n <= 1)
2183c896fe29Sbellard         return;
2184c896fe29Sbellard     for(i = 0; i < n - 1; i++) {
2185c896fe29Sbellard         for(j = i + 1; j < n; j++) {
2186c896fe29Sbellard             p1 = get_constraint_priority(def, def->sorted_args[start + i]);
2187c896fe29Sbellard             p2 = get_constraint_priority(def, def->sorted_args[start + j]);
2188c896fe29Sbellard             if (p1 < p2) {
2189c896fe29Sbellard                 tmp = def->sorted_args[start + i];
2190c896fe29Sbellard                 def->sorted_args[start + i] = def->sorted_args[start + j];
2191c896fe29Sbellard                 def->sorted_args[start + j] = tmp;
2192c896fe29Sbellard             }
2193c896fe29Sbellard         }
2194c896fe29Sbellard     }
2195c896fe29Sbellard }
2196c896fe29Sbellard 
2197f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2198c896fe29Sbellard {
2199a9751609SRichard Henderson     TCGOpcode op;
2200c896fe29Sbellard 
2201f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
2202f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
2203f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
2204069ea736SRichard Henderson         TCGType type;
2205069ea736SRichard Henderson         int i, nb_args;
2206f69d277eSRichard Henderson 
2207f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
2208f69d277eSRichard Henderson             continue;
2209f69d277eSRichard Henderson         }
2210f69d277eSRichard Henderson 
2211c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
2212f69d277eSRichard Henderson         if (nb_args == 0) {
2213f69d277eSRichard Henderson             continue;
2214f69d277eSRichard Henderson         }
2215f69d277eSRichard Henderson 
2216f69d277eSRichard Henderson         tdefs = tcg_target_op_def(op);
2217f69d277eSRichard Henderson         /* Missing TCGTargetOpDef entry. */
2218f69d277eSRichard Henderson         tcg_debug_assert(tdefs != NULL);
2219f69d277eSRichard Henderson 
2220069ea736SRichard Henderson         type = (def->flags & TCG_OPF_64BIT ? TCG_TYPE_I64 : TCG_TYPE_I32);
2221c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2222f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
2223f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2224eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2225f69d277eSRichard Henderson 
2226ccb1bb66SRichard Henderson             def->args_ct[i].u.regs = 0;
2227c896fe29Sbellard             def->args_ct[i].ct = 0;
222817280ff4SRichard Henderson             while (*ct_str != '\0') {
222917280ff4SRichard Henderson                 switch(*ct_str) {
223017280ff4SRichard Henderson                 case '0' ... '9':
223117280ff4SRichard Henderson                     {
223217280ff4SRichard Henderson                         int oarg = *ct_str - '0';
223317280ff4SRichard Henderson                         tcg_debug_assert(ct_str == tdefs->args_ct_str[i]);
2234eabb7b91SAurelien Jarno                         tcg_debug_assert(oarg < def->nb_oargs);
2235eabb7b91SAurelien Jarno                         tcg_debug_assert(def->args_ct[oarg].ct & TCG_CT_REG);
223617280ff4SRichard Henderson                         /* TCG_CT_ALIAS is for the output arguments.
223717280ff4SRichard Henderson                            The input is tagged with TCG_CT_IALIAS. */
2238c896fe29Sbellard                         def->args_ct[i] = def->args_ct[oarg];
223917280ff4SRichard Henderson                         def->args_ct[oarg].ct |= TCG_CT_ALIAS;
22405ff9d6a4Sbellard                         def->args_ct[oarg].alias_index = i;
2241c896fe29Sbellard                         def->args_ct[i].ct |= TCG_CT_IALIAS;
22425ff9d6a4Sbellard                         def->args_ct[i].alias_index = oarg;
224317280ff4SRichard Henderson                     }
224417280ff4SRichard Henderson                     ct_str++;
2245c896fe29Sbellard                     break;
224682790a87SRichard Henderson                 case '&':
224782790a87SRichard Henderson                     def->args_ct[i].ct |= TCG_CT_NEWREG;
224882790a87SRichard Henderson                     ct_str++;
224982790a87SRichard Henderson                     break;
2250c896fe29Sbellard                 case 'i':
2251c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2252c896fe29Sbellard                     ct_str++;
2253c896fe29Sbellard                     break;
2254c896fe29Sbellard                 default:
2255069ea736SRichard Henderson                     ct_str = target_parse_constraint(&def->args_ct[i],
2256069ea736SRichard Henderson                                                      ct_str, type);
2257f69d277eSRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2258069ea736SRichard Henderson                     tcg_debug_assert(ct_str != NULL);
2259c896fe29Sbellard                 }
2260c896fe29Sbellard             }
2261c896fe29Sbellard         }
2262c896fe29Sbellard 
2263c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2264eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2265c68aaa18SStefan Weil 
2266c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
2267c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
2268c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
2269c896fe29Sbellard     }
2270c896fe29Sbellard }
2271c896fe29Sbellard 
22720c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
22730c627cdcSRichard Henderson {
2274d88a117eSRichard Henderson     TCGLabel *label;
2275d88a117eSRichard Henderson 
2276d88a117eSRichard Henderson     switch (op->opc) {
2277d88a117eSRichard Henderson     case INDEX_op_br:
2278d88a117eSRichard Henderson         label = arg_label(op->args[0]);
2279d88a117eSRichard Henderson         label->refs--;
2280d88a117eSRichard Henderson         break;
2281d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
2282d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
2283d88a117eSRichard Henderson         label = arg_label(op->args[3]);
2284d88a117eSRichard Henderson         label->refs--;
2285d88a117eSRichard Henderson         break;
2286d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
2287d88a117eSRichard Henderson         label = arg_label(op->args[5]);
2288d88a117eSRichard Henderson         label->refs--;
2289d88a117eSRichard Henderson         break;
2290d88a117eSRichard Henderson     default:
2291d88a117eSRichard Henderson         break;
2292d88a117eSRichard Henderson     }
2293d88a117eSRichard Henderson 
229415fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
229515fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
2296abebf925SRichard Henderson     s->nb_ops--;
22970c627cdcSRichard Henderson 
22980c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
2299c3fac113SEmilio G. Cota     atomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
23000c627cdcSRichard Henderson #endif
23010c627cdcSRichard Henderson }
23020c627cdcSRichard Henderson 
230315fa08f8SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc)
230415fa08f8SRichard Henderson {
230515fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
230615fa08f8SRichard Henderson     TCGOp *op;
230715fa08f8SRichard Henderson 
230815fa08f8SRichard Henderson     if (likely(QTAILQ_EMPTY(&s->free_ops))) {
230915fa08f8SRichard Henderson         op = tcg_malloc(sizeof(TCGOp));
231015fa08f8SRichard Henderson     } else {
231115fa08f8SRichard Henderson         op = QTAILQ_FIRST(&s->free_ops);
231215fa08f8SRichard Henderson         QTAILQ_REMOVE(&s->free_ops, op, link);
231315fa08f8SRichard Henderson     }
231415fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
231515fa08f8SRichard Henderson     op->opc = opc;
2316abebf925SRichard Henderson     s->nb_ops++;
231715fa08f8SRichard Henderson 
231815fa08f8SRichard Henderson     return op;
231915fa08f8SRichard Henderson }
232015fa08f8SRichard Henderson 
232115fa08f8SRichard Henderson TCGOp *tcg_emit_op(TCGOpcode opc)
232215fa08f8SRichard Henderson {
232315fa08f8SRichard Henderson     TCGOp *op = tcg_op_alloc(opc);
232415fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
232515fa08f8SRichard Henderson     return op;
232615fa08f8SRichard Henderson }
232715fa08f8SRichard Henderson 
2328ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
23295a18407fSRichard Henderson {
233015fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
233115fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
23325a18407fSRichard Henderson     return new_op;
23335a18407fSRichard Henderson }
23345a18407fSRichard Henderson 
2335ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
23365a18407fSRichard Henderson {
233715fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
233815fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
23395a18407fSRichard Henderson     return new_op;
23405a18407fSRichard Henderson }
23415a18407fSRichard Henderson 
2342b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
2343b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s)
2344b4fc67c7SRichard Henderson {
2345b4fc67c7SRichard Henderson     TCGOp *op, *op_next;
2346b4fc67c7SRichard Henderson     bool dead = false;
2347b4fc67c7SRichard Henderson 
2348b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
2349b4fc67c7SRichard Henderson         bool remove = dead;
2350b4fc67c7SRichard Henderson         TCGLabel *label;
2351b4fc67c7SRichard Henderson         int call_flags;
2352b4fc67c7SRichard Henderson 
2353b4fc67c7SRichard Henderson         switch (op->opc) {
2354b4fc67c7SRichard Henderson         case INDEX_op_set_label:
2355b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
2356b4fc67c7SRichard Henderson             if (label->refs == 0) {
2357b4fc67c7SRichard Henderson                 /*
2358b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
2359b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
2360b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
2361b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
2362b4fc67c7SRichard Henderson                  * little to be gained by iterating.
2363b4fc67c7SRichard Henderson                  */
2364b4fc67c7SRichard Henderson                 remove = true;
2365b4fc67c7SRichard Henderson             } else {
2366b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
2367b4fc67c7SRichard Henderson                 dead = false;
2368b4fc67c7SRichard Henderson                 remove = false;
2369b4fc67c7SRichard Henderson 
2370b4fc67c7SRichard Henderson                 /*
2371b4fc67c7SRichard Henderson                  * Optimization can fold conditional branches to unconditional.
2372b4fc67c7SRichard Henderson                  * If we find a label with one reference which is preceded by
2373b4fc67c7SRichard Henderson                  * an unconditional branch to it, remove both.  This needed to
2374b4fc67c7SRichard Henderson                  * wait until the dead code in between them was removed.
2375b4fc67c7SRichard Henderson                  */
2376b4fc67c7SRichard Henderson                 if (label->refs == 1) {
2377eae3eb3eSPaolo Bonzini                     TCGOp *op_prev = QTAILQ_PREV(op, link);
2378b4fc67c7SRichard Henderson                     if (op_prev->opc == INDEX_op_br &&
2379b4fc67c7SRichard Henderson                         label == arg_label(op_prev->args[0])) {
2380b4fc67c7SRichard Henderson                         tcg_op_remove(s, op_prev);
2381b4fc67c7SRichard Henderson                         remove = true;
2382b4fc67c7SRichard Henderson                     }
2383b4fc67c7SRichard Henderson                 }
2384b4fc67c7SRichard Henderson             }
2385b4fc67c7SRichard Henderson             break;
2386b4fc67c7SRichard Henderson 
2387b4fc67c7SRichard Henderson         case INDEX_op_br:
2388b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
2389b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
2390b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
2391b4fc67c7SRichard Henderson             dead = true;
2392b4fc67c7SRichard Henderson             break;
2393b4fc67c7SRichard Henderson 
2394b4fc67c7SRichard Henderson         case INDEX_op_call:
2395b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
2396b4fc67c7SRichard Henderson             call_flags = op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1];
2397b4fc67c7SRichard Henderson             if (call_flags & TCG_CALL_NO_RETURN) {
2398b4fc67c7SRichard Henderson                 dead = true;
2399b4fc67c7SRichard Henderson             }
2400b4fc67c7SRichard Henderson             break;
2401b4fc67c7SRichard Henderson 
2402b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
2403b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
2404b4fc67c7SRichard Henderson             remove = false;
2405b4fc67c7SRichard Henderson             break;
2406b4fc67c7SRichard Henderson 
2407b4fc67c7SRichard Henderson         default:
2408b4fc67c7SRichard Henderson             break;
2409b4fc67c7SRichard Henderson         }
2410b4fc67c7SRichard Henderson 
2411b4fc67c7SRichard Henderson         if (remove) {
2412b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
2413b4fc67c7SRichard Henderson         }
2414b4fc67c7SRichard Henderson     }
2415b4fc67c7SRichard Henderson }
2416b4fc67c7SRichard Henderson 
2417c70fbf0aSRichard Henderson #define TS_DEAD  1
2418c70fbf0aSRichard Henderson #define TS_MEM   2
2419c70fbf0aSRichard Henderson 
24205a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
24215a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
24225a18407fSRichard Henderson 
242325f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
242425f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
242525f49c5fSRichard Henderson {
242625f49c5fSRichard Henderson     return ts->state_ptr;
242725f49c5fSRichard Henderson }
242825f49c5fSRichard Henderson 
242925f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
243025f49c5fSRichard Henderson  * maximal regset for its type.
243125f49c5fSRichard Henderson  */
243225f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
243325f49c5fSRichard Henderson {
243425f49c5fSRichard Henderson     *la_temp_pref(ts)
243525f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
243625f49c5fSRichard Henderson }
243725f49c5fSRichard Henderson 
24389c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
24399c43b68dSAurelien Jarno    should be in memory. */
24402616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
2441c896fe29Sbellard {
2442b83eabeaSRichard Henderson     int i;
2443b83eabeaSRichard Henderson 
2444b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2445b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
244625f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2447b83eabeaSRichard Henderson     }
2448b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2449b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
245025f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2451b83eabeaSRichard Henderson     }
2452c896fe29Sbellard }
2453c896fe29Sbellard 
24549c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
24559c43b68dSAurelien Jarno    and local temps should be in memory. */
24562616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
2457641d5fbeSbellard {
2458b83eabeaSRichard Henderson     int i;
2459641d5fbeSbellard 
2460b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2461b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
246225f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2463c70fbf0aSRichard Henderson     }
2464b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2465b83eabeaSRichard Henderson         s->temps[i].state = (s->temps[i].temp_local
2466b83eabeaSRichard Henderson                              ? TS_DEAD | TS_MEM
2467b83eabeaSRichard Henderson                              : TS_DEAD);
246825f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2469641d5fbeSbellard     }
2470641d5fbeSbellard }
2471641d5fbeSbellard 
2472f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
2473f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
2474f65a061cSRichard Henderson {
2475f65a061cSRichard Henderson     int i;
2476f65a061cSRichard Henderson 
2477f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
247825f49c5fSRichard Henderson         int state = s->temps[i].state;
247925f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
248025f49c5fSRichard Henderson         if (state == TS_DEAD) {
248125f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
248225f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
248325f49c5fSRichard Henderson         }
2484f65a061cSRichard Henderson     }
2485f65a061cSRichard Henderson }
2486f65a061cSRichard Henderson 
2487f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
2488f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
2489f65a061cSRichard Henderson {
2490f65a061cSRichard Henderson     int i;
2491f65a061cSRichard Henderson 
2492f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
2493f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
249425f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
249525f49c5fSRichard Henderson     }
249625f49c5fSRichard Henderson }
249725f49c5fSRichard Henderson 
249825f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
249925f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
250025f49c5fSRichard Henderson {
250125f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
250225f49c5fSRichard Henderson     int i;
250325f49c5fSRichard Henderson 
250425f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
250525f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
250625f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
250725f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
250825f49c5fSRichard Henderson             TCGRegSet set = *pset;
250925f49c5fSRichard Henderson 
251025f49c5fSRichard Henderson             set &= mask;
251125f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
251225f49c5fSRichard Henderson             if (set == 0) {
251325f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
251425f49c5fSRichard Henderson             }
251525f49c5fSRichard Henderson             *pset = set;
251625f49c5fSRichard Henderson         }
2517f65a061cSRichard Henderson     }
2518f65a061cSRichard Henderson }
2519f65a061cSRichard Henderson 
2520a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
2521c896fe29Sbellard    given input arguments is dead. Instructions updating dead
2522c896fe29Sbellard    temporaries are removed. */
2523b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s)
2524c896fe29Sbellard {
2525c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
25262616c808SRichard Henderson     int nb_temps = s->nb_temps;
252715fa08f8SRichard Henderson     TCGOp *op, *op_prev;
252825f49c5fSRichard Henderson     TCGRegSet *prefs;
252925f49c5fSRichard Henderson     int i;
253025f49c5fSRichard Henderson 
253125f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
253225f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
253325f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
253425f49c5fSRichard Henderson     }
2535c896fe29Sbellard 
2536ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
25372616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
2538c896fe29Sbellard 
2539eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
254025f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
2541c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
2542c45cb8bbSRichard Henderson         bool have_opc_new2;
2543a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
254425f49c5fSRichard Henderson         TCGTemp *ts;
2545c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2546c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2547c45cb8bbSRichard Henderson 
2548c45cb8bbSRichard Henderson         switch (opc) {
2549c896fe29Sbellard         case INDEX_op_call:
2550c6e113f5Sbellard             {
2551c6e113f5Sbellard                 int call_flags;
255225f49c5fSRichard Henderson                 int nb_call_regs;
2553c6e113f5Sbellard 
2554cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
2555cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
2556efee3746SRichard Henderson                 call_flags = op->args[nb_oargs + nb_iargs + 1];
2557c6e113f5Sbellard 
2558c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
255978505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
2560c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
256125f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
256225f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
2563c6e113f5Sbellard                             goto do_not_remove_call;
2564c6e113f5Sbellard                         }
25659c43b68dSAurelien Jarno                     }
2566c45cb8bbSRichard Henderson                     goto do_remove;
2567152c35aaSRichard Henderson                 }
2568c6e113f5Sbellard             do_not_remove_call:
2569c896fe29Sbellard 
257025f49c5fSRichard Henderson                 /* Output args are dead.  */
2571c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
257225f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
257325f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
2574a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
25756b64b624SAurelien Jarno                     }
257625f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
2577a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
25789c43b68dSAurelien Jarno                     }
257925f49c5fSRichard Henderson                     ts->state = TS_DEAD;
258025f49c5fSRichard Henderson                     la_reset_pref(ts);
258125f49c5fSRichard Henderson 
258225f49c5fSRichard Henderson                     /* Not used -- it will be tcg_target_call_oarg_regs[i].  */
258325f49c5fSRichard Henderson                     op->output_pref[i] = 0;
2584c896fe29Sbellard                 }
2585c896fe29Sbellard 
258678505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
258778505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
2588f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
2589c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
2590f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
2591b9c18f56Saurel32                 }
2592c896fe29Sbellard 
259325f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
2594866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
259525f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
259625f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
2597a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
2598c896fe29Sbellard                     }
2599c896fe29Sbellard                 }
260025f49c5fSRichard Henderson 
260125f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
260225f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
260325f49c5fSRichard Henderson 
260425f49c5fSRichard Henderson                 nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
260525f49c5fSRichard Henderson 
260625f49c5fSRichard Henderson                 /* Input arguments are live for preceding opcodes.  */
260725f49c5fSRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
260825f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
260925f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
261025f49c5fSRichard Henderson                         /* For those arguments that die, and will be allocated
261125f49c5fSRichard Henderson                          * in registers, clear the register set for that arg,
261225f49c5fSRichard Henderson                          * to be filled in below.  For args that will be on
261325f49c5fSRichard Henderson                          * the stack, reset to any available reg.
261425f49c5fSRichard Henderson                          */
261525f49c5fSRichard Henderson                         *la_temp_pref(ts)
261625f49c5fSRichard Henderson                             = (i < nb_call_regs ? 0 :
261725f49c5fSRichard Henderson                                tcg_target_available_regs[ts->type]);
261825f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
261925f49c5fSRichard Henderson                     }
262025f49c5fSRichard Henderson                 }
262125f49c5fSRichard Henderson 
262225f49c5fSRichard Henderson                 /* For each input argument, add its input register to prefs.
262325f49c5fSRichard Henderson                    If a temp is used once, this produces a single set bit.  */
262425f49c5fSRichard Henderson                 for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) {
262525f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
262625f49c5fSRichard Henderson                     if (ts) {
262725f49c5fSRichard Henderson                         tcg_regset_set_reg(*la_temp_pref(ts),
262825f49c5fSRichard Henderson                                            tcg_target_call_iarg_regs[i]);
2629c70fbf0aSRichard Henderson                     }
2630c19f47bfSAurelien Jarno                 }
2631c6e113f5Sbellard             }
2632c896fe29Sbellard             break;
2633765b842aSRichard Henderson         case INDEX_op_insn_start:
2634c896fe29Sbellard             break;
26355ff9d6a4Sbellard         case INDEX_op_discard:
26365ff9d6a4Sbellard             /* mark the temporary as dead */
263725f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
263825f49c5fSRichard Henderson             ts->state = TS_DEAD;
263925f49c5fSRichard Henderson             la_reset_pref(ts);
26405ff9d6a4Sbellard             break;
26411305c451SRichard Henderson 
26421305c451SRichard Henderson         case INDEX_op_add2_i32:
2643c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
2644f1fae40cSRichard Henderson             goto do_addsub2;
26451305c451SRichard Henderson         case INDEX_op_sub2_i32:
2646c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
2647f1fae40cSRichard Henderson             goto do_addsub2;
2648f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
2649c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
2650f1fae40cSRichard Henderson             goto do_addsub2;
2651f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
2652c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
2653f1fae40cSRichard Henderson         do_addsub2:
26541305c451SRichard Henderson             nb_iargs = 4;
26551305c451SRichard Henderson             nb_oargs = 2;
26561305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
26571305c451SRichard Henderson                the low part.  The result can be optimized to a simple
26581305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
26591305c451SRichard Henderson                cpu mode is set to 32 bit.  */
2660b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2661b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
26621305c451SRichard Henderson                     goto do_remove;
26631305c451SRichard Henderson                 }
2664c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
2665c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
2666c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2667efee3746SRichard Henderson                 op->args[1] = op->args[2];
2668efee3746SRichard Henderson                 op->args[2] = op->args[4];
26691305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
26701305c451SRichard Henderson                 nb_iargs = 2;
26711305c451SRichard Henderson                 nb_oargs = 1;
26721305c451SRichard Henderson             }
26731305c451SRichard Henderson             goto do_not_remove;
26741305c451SRichard Henderson 
26751414968aSRichard Henderson         case INDEX_op_mulu2_i32:
2676c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2677c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
2678c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
267903271524SRichard Henderson             goto do_mul2;
2680f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
2681c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2682c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
2683c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
2684f1fae40cSRichard Henderson             goto do_mul2;
2685f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
2686c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2687c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
2688c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
268903271524SRichard Henderson             goto do_mul2;
2690f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
2691c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2692c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
2693c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
269403271524SRichard Henderson             goto do_mul2;
2695f1fae40cSRichard Henderson         do_mul2:
26961414968aSRichard Henderson             nb_iargs = 2;
26971414968aSRichard Henderson             nb_oargs = 2;
2698b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2699b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
270003271524SRichard Henderson                     /* Both parts of the operation are dead.  */
27011414968aSRichard Henderson                     goto do_remove;
27021414968aSRichard Henderson                 }
270303271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
2704c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2705efee3746SRichard Henderson                 op->args[1] = op->args[2];
2706efee3746SRichard Henderson                 op->args[2] = op->args[3];
2707b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
270803271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
2709c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
2710efee3746SRichard Henderson                 op->args[0] = op->args[1];
2711efee3746SRichard Henderson                 op->args[1] = op->args[2];
2712efee3746SRichard Henderson                 op->args[2] = op->args[3];
271303271524SRichard Henderson             } else {
271403271524SRichard Henderson                 goto do_not_remove;
271503271524SRichard Henderson             }
271603271524SRichard Henderson             /* Mark the single-word operation live.  */
27171414968aSRichard Henderson             nb_oargs = 1;
27181414968aSRichard Henderson             goto do_not_remove;
27191414968aSRichard Henderson 
2720c896fe29Sbellard         default:
27211305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
2722c896fe29Sbellard             nb_iargs = def->nb_iargs;
2723c896fe29Sbellard             nb_oargs = def->nb_oargs;
2724c896fe29Sbellard 
2725c896fe29Sbellard             /* Test if the operation can be removed because all
27265ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
27275ff9d6a4Sbellard                implies side effects */
27285ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
2729c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
2730b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
2731c896fe29Sbellard                         goto do_not_remove;
2732c896fe29Sbellard                     }
27339c43b68dSAurelien Jarno                 }
2734152c35aaSRichard Henderson                 goto do_remove;
2735152c35aaSRichard Henderson             }
2736152c35aaSRichard Henderson             goto do_not_remove;
2737152c35aaSRichard Henderson 
27381305c451SRichard Henderson         do_remove:
27390c627cdcSRichard Henderson             tcg_op_remove(s, op);
2740152c35aaSRichard Henderson             break;
2741152c35aaSRichard Henderson 
2742c896fe29Sbellard         do_not_remove:
2743c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
274425f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
274525f49c5fSRichard Henderson 
274625f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
274725f49c5fSRichard Henderson                 op->output_pref[i] = *la_temp_pref(ts);
274825f49c5fSRichard Henderson 
274925f49c5fSRichard Henderson                 /* Output args are dead.  */
275025f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2751a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
27526b64b624SAurelien Jarno                 }
275325f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
2754a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
27559c43b68dSAurelien Jarno                 }
275625f49c5fSRichard Henderson                 ts->state = TS_DEAD;
275725f49c5fSRichard Henderson                 la_reset_pref(ts);
2758c896fe29Sbellard             }
2759c896fe29Sbellard 
276025f49c5fSRichard Henderson             /* If end of basic block, update.  */
2761ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
2762ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
2763ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
27642616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
27653d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
2766f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
276725f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
276825f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
276925f49c5fSRichard Henderson                 }
2770c896fe29Sbellard             }
2771c896fe29Sbellard 
277225f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
2773866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
277425f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
277525f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2776a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
2777c896fe29Sbellard                 }
2778c19f47bfSAurelien Jarno             }
277925f49c5fSRichard Henderson 
278025f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
2781c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
278225f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
278325f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
278425f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
278525f49c5fSRichard Henderson                        all regs for the type.  */
278625f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
278725f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
278825f49c5fSRichard Henderson                 }
278925f49c5fSRichard Henderson             }
279025f49c5fSRichard Henderson 
279125f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
279225f49c5fSRichard Henderson             switch (opc) {
279325f49c5fSRichard Henderson             case INDEX_op_mov_i32:
279425f49c5fSRichard Henderson             case INDEX_op_mov_i64:
279525f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
279625f49c5fSRichard Henderson                    have proper constraints.  That said, special case
279725f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
279825f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
279925f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
280025f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
280125f49c5fSRichard Henderson                 }
280225f49c5fSRichard Henderson                 break;
280325f49c5fSRichard Henderson 
280425f49c5fSRichard Henderson             default:
280525f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
280625f49c5fSRichard Henderson                     const TCGArgConstraint *ct = &def->args_ct[i];
280725f49c5fSRichard Henderson                     TCGRegSet set, *pset;
280825f49c5fSRichard Henderson 
280925f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
281025f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
281125f49c5fSRichard Henderson                     set = *pset;
281225f49c5fSRichard Henderson 
281325f49c5fSRichard Henderson                     set &= ct->u.regs;
281425f49c5fSRichard Henderson                     if (ct->ct & TCG_CT_IALIAS) {
281525f49c5fSRichard Henderson                         set &= op->output_pref[ct->alias_index];
281625f49c5fSRichard Henderson                     }
281725f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
281825f49c5fSRichard Henderson                     if (set == 0) {
281925f49c5fSRichard Henderson                         set = ct->u.regs;
282025f49c5fSRichard Henderson                     }
282125f49c5fSRichard Henderson                     *pset = set;
282225f49c5fSRichard Henderson                 }
282325f49c5fSRichard Henderson                 break;
2824c896fe29Sbellard             }
2825c896fe29Sbellard             break;
2826c896fe29Sbellard         }
2827bee158cbSRichard Henderson         op->life = arg_life;
2828c896fe29Sbellard     }
28291ff0a2c5SEvgeny Voevodin }
2830c896fe29Sbellard 
28315a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
2832b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s)
28335a18407fSRichard Henderson {
28345a18407fSRichard Henderson     int nb_globals = s->nb_globals;
283515fa08f8SRichard Henderson     int nb_temps, i;
28365a18407fSRichard Henderson     bool changes = false;
283715fa08f8SRichard Henderson     TCGOp *op, *op_next;
28385a18407fSRichard Henderson 
28395a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
28405a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
28415a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
28425a18407fSRichard Henderson         if (its->indirect_reg) {
28435a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
28445a18407fSRichard Henderson             dts->type = its->type;
28455a18407fSRichard Henderson             dts->base_type = its->base_type;
2846b83eabeaSRichard Henderson             its->state_ptr = dts;
2847b83eabeaSRichard Henderson         } else {
2848b83eabeaSRichard Henderson             its->state_ptr = NULL;
28495a18407fSRichard Henderson         }
2850b83eabeaSRichard Henderson         /* All globals begin dead.  */
2851b83eabeaSRichard Henderson         its->state = TS_DEAD;
28525a18407fSRichard Henderson     }
2853b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
2854b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
2855b83eabeaSRichard Henderson         its->state_ptr = NULL;
2856b83eabeaSRichard Henderson         its->state = TS_DEAD;
2857b83eabeaSRichard Henderson     }
28585a18407fSRichard Henderson 
285915fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
28605a18407fSRichard Henderson         TCGOpcode opc = op->opc;
28615a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
28625a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
28635a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
2864b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
28655a18407fSRichard Henderson 
28665a18407fSRichard Henderson         if (opc == INDEX_op_call) {
2867cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2868cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2869efee3746SRichard Henderson             call_flags = op->args[nb_oargs + nb_iargs + 1];
28705a18407fSRichard Henderson         } else {
28715a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
28725a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
28735a18407fSRichard Henderson 
28745a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
28755a18407fSRichard Henderson             if (def->flags & TCG_OPF_BB_END) {
28765a18407fSRichard Henderson                 /* Like writing globals: save_globals */
28775a18407fSRichard Henderson                 call_flags = 0;
28785a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
28795a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
28805a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
28815a18407fSRichard Henderson             } else {
28825a18407fSRichard Henderson                 /* No effect on globals.  */
28835a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
28845a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
28855a18407fSRichard Henderson             }
28865a18407fSRichard Henderson         }
28875a18407fSRichard Henderson 
28885a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
28895a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2890b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2891b83eabeaSRichard Henderson             if (arg_ts) {
2892b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
2893b83eabeaSRichard Henderson                 if (dir_ts && arg_ts->state == TS_DEAD) {
2894b83eabeaSRichard Henderson                     TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
28955a18407fSRichard Henderson                                       ? INDEX_op_ld_i32
28965a18407fSRichard Henderson                                       : INDEX_op_ld_i64);
2897ac1043f6SEmilio G. Cota                     TCGOp *lop = tcg_op_insert_before(s, op, lopc);
28985a18407fSRichard Henderson 
2899b83eabeaSRichard Henderson                     lop->args[0] = temp_arg(dir_ts);
2900b83eabeaSRichard Henderson                     lop->args[1] = temp_arg(arg_ts->mem_base);
2901b83eabeaSRichard Henderson                     lop->args[2] = arg_ts->mem_offset;
29025a18407fSRichard Henderson 
29035a18407fSRichard Henderson                     /* Loaded, but synced with memory.  */
2904b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
29055a18407fSRichard Henderson                 }
29065a18407fSRichard Henderson             }
29075a18407fSRichard Henderson         }
29085a18407fSRichard Henderson 
29095a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
29105a18407fSRichard Henderson            No action is required except keeping temp_state up to date
29115a18407fSRichard Henderson            so that we reload when needed.  */
29125a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2913b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2914b83eabeaSRichard Henderson             if (arg_ts) {
2915b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
2916b83eabeaSRichard Henderson                 if (dir_ts) {
2917b83eabeaSRichard Henderson                     op->args[i] = temp_arg(dir_ts);
29185a18407fSRichard Henderson                     changes = true;
29195a18407fSRichard Henderson                     if (IS_DEAD_ARG(i)) {
2920b83eabeaSRichard Henderson                         arg_ts->state = TS_DEAD;
29215a18407fSRichard Henderson                     }
29225a18407fSRichard Henderson                 }
29235a18407fSRichard Henderson             }
29245a18407fSRichard Henderson         }
29255a18407fSRichard Henderson 
29265a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
29275a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
29285a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
29295a18407fSRichard Henderson             /* Nothing to do */
29305a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
29315a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
29325a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
29335a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
2934b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
2935b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
2936b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
29375a18407fSRichard Henderson             }
29385a18407fSRichard Henderson         } else {
29395a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
29405a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
29415a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
2942b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
2943b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
2944b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
29455a18407fSRichard Henderson             }
29465a18407fSRichard Henderson         }
29475a18407fSRichard Henderson 
29485a18407fSRichard Henderson         /* Outputs become available.  */
29495a18407fSRichard Henderson         for (i = 0; i < nb_oargs; i++) {
2950b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2951b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
2952b83eabeaSRichard Henderson             if (!dir_ts) {
29535a18407fSRichard Henderson                 continue;
29545a18407fSRichard Henderson             }
2955b83eabeaSRichard Henderson             op->args[i] = temp_arg(dir_ts);
29565a18407fSRichard Henderson             changes = true;
29575a18407fSRichard Henderson 
29585a18407fSRichard Henderson             /* The output is now live and modified.  */
2959b83eabeaSRichard Henderson             arg_ts->state = 0;
29605a18407fSRichard Henderson 
29615a18407fSRichard Henderson             /* Sync outputs upon their last write.  */
29625a18407fSRichard Henderson             if (NEED_SYNC_ARG(i)) {
2963b83eabeaSRichard Henderson                 TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
29645a18407fSRichard Henderson                                   ? INDEX_op_st_i32
29655a18407fSRichard Henderson                                   : INDEX_op_st_i64);
2966ac1043f6SEmilio G. Cota                 TCGOp *sop = tcg_op_insert_after(s, op, sopc);
29675a18407fSRichard Henderson 
2968b83eabeaSRichard Henderson                 sop->args[0] = temp_arg(dir_ts);
2969b83eabeaSRichard Henderson                 sop->args[1] = temp_arg(arg_ts->mem_base);
2970b83eabeaSRichard Henderson                 sop->args[2] = arg_ts->mem_offset;
29715a18407fSRichard Henderson 
2972b83eabeaSRichard Henderson                 arg_ts->state = TS_MEM;
29735a18407fSRichard Henderson             }
29745a18407fSRichard Henderson             /* Drop outputs that are dead.  */
29755a18407fSRichard Henderson             if (IS_DEAD_ARG(i)) {
2976b83eabeaSRichard Henderson                 arg_ts->state = TS_DEAD;
29775a18407fSRichard Henderson             }
29785a18407fSRichard Henderson         }
29795a18407fSRichard Henderson     }
29805a18407fSRichard Henderson 
29815a18407fSRichard Henderson     return changes;
29825a18407fSRichard Henderson }
29835a18407fSRichard Henderson 
29848d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
2985c896fe29Sbellard static void dump_regs(TCGContext *s)
2986c896fe29Sbellard {
2987c896fe29Sbellard     TCGTemp *ts;
2988c896fe29Sbellard     int i;
2989c896fe29Sbellard     char buf[64];
2990c896fe29Sbellard 
2991c896fe29Sbellard     for(i = 0; i < s->nb_temps; i++) {
2992c896fe29Sbellard         ts = &s->temps[i];
299343439139SRichard Henderson         printf("  %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
2994c896fe29Sbellard         switch(ts->val_type) {
2995c896fe29Sbellard         case TEMP_VAL_REG:
2996c896fe29Sbellard             printf("%s", tcg_target_reg_names[ts->reg]);
2997c896fe29Sbellard             break;
2998c896fe29Sbellard         case TEMP_VAL_MEM:
2999b3a62939SRichard Henderson             printf("%d(%s)", (int)ts->mem_offset,
3000b3a62939SRichard Henderson                    tcg_target_reg_names[ts->mem_base->reg]);
3001c896fe29Sbellard             break;
3002c896fe29Sbellard         case TEMP_VAL_CONST:
3003c896fe29Sbellard             printf("$0x%" TCG_PRIlx, ts->val);
3004c896fe29Sbellard             break;
3005c896fe29Sbellard         case TEMP_VAL_DEAD:
3006c896fe29Sbellard             printf("D");
3007c896fe29Sbellard             break;
3008c896fe29Sbellard         default:
3009c896fe29Sbellard             printf("???");
3010c896fe29Sbellard             break;
3011c896fe29Sbellard         }
3012c896fe29Sbellard         printf("\n");
3013c896fe29Sbellard     }
3014c896fe29Sbellard 
3015c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
3016f8b2f202SRichard Henderson         if (s->reg_to_temp[i] != NULL) {
3017c896fe29Sbellard             printf("%s: %s\n",
3018c896fe29Sbellard                    tcg_target_reg_names[i],
3019f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i]));
3020c896fe29Sbellard         }
3021c896fe29Sbellard     }
3022c896fe29Sbellard }
3023c896fe29Sbellard 
3024c896fe29Sbellard static void check_regs(TCGContext *s)
3025c896fe29Sbellard {
3026869938aeSRichard Henderson     int reg;
3027b6638662SRichard Henderson     int k;
3028c896fe29Sbellard     TCGTemp *ts;
3029c896fe29Sbellard     char buf[64];
3030c896fe29Sbellard 
3031c896fe29Sbellard     for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
3032f8b2f202SRichard Henderson         ts = s->reg_to_temp[reg];
3033f8b2f202SRichard Henderson         if (ts != NULL) {
3034f8b2f202SRichard Henderson             if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) {
3035c896fe29Sbellard                 printf("Inconsistency for register %s:\n",
3036c896fe29Sbellard                        tcg_target_reg_names[reg]);
3037b03cce8eSbellard                 goto fail;
3038c896fe29Sbellard             }
3039c896fe29Sbellard         }
3040c896fe29Sbellard     }
3041c896fe29Sbellard     for (k = 0; k < s->nb_temps; k++) {
3042c896fe29Sbellard         ts = &s->temps[k];
3043f8b2f202SRichard Henderson         if (ts->val_type == TEMP_VAL_REG && !ts->fixed_reg
3044f8b2f202SRichard Henderson             && s->reg_to_temp[ts->reg] != ts) {
3045c896fe29Sbellard             printf("Inconsistency for temp %s:\n",
3046f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3047b03cce8eSbellard         fail:
3048c896fe29Sbellard             printf("reg state:\n");
3049c896fe29Sbellard             dump_regs(s);
3050c896fe29Sbellard             tcg_abort();
3051c896fe29Sbellard         }
3052c896fe29Sbellard     }
3053c896fe29Sbellard }
3054c896fe29Sbellard #endif
3055c896fe29Sbellard 
30562272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
3057c896fe29Sbellard {
30589b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64)
30599b9c37c3SRichard Henderson     /* Sparc64 stack is accessed with offset of 2047 */
3060b591dc59SBlue Swirl     s->current_frame_offset = (s->current_frame_offset +
3061b591dc59SBlue Swirl                                (tcg_target_long)sizeof(tcg_target_long) - 1) &
3062b591dc59SBlue Swirl         ~(sizeof(tcg_target_long) - 1);
3063f44c9960SBlue Swirl #endif
3064b591dc59SBlue Swirl     if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
3065b591dc59SBlue Swirl         s->frame_end) {
30665ff9d6a4Sbellard         tcg_abort();
3067b591dc59SBlue Swirl     }
3068c896fe29Sbellard     ts->mem_offset = s->current_frame_offset;
3069b3a62939SRichard Henderson     ts->mem_base = s->frame_temp;
3070c896fe29Sbellard     ts->mem_allocated = 1;
3071e2c6d1b4SRichard Henderson     s->current_frame_offset += sizeof(tcg_target_long);
3072c896fe29Sbellard }
3073c896fe29Sbellard 
3074b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
3075b3915dbbSRichard Henderson 
307659d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
307759d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
307859d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
3079c896fe29Sbellard {
308059d7c14eSRichard Henderson     if (ts->fixed_reg) {
308159d7c14eSRichard Henderson         return;
308259d7c14eSRichard Henderson     }
308359d7c14eSRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
308459d7c14eSRichard Henderson         s->reg_to_temp[ts->reg] = NULL;
308559d7c14eSRichard Henderson     }
308659d7c14eSRichard Henderson     ts->val_type = (free_or_dead < 0
308759d7c14eSRichard Henderson                     || ts->temp_local
3088fa477d25SRichard Henderson                     || ts->temp_global
308959d7c14eSRichard Henderson                     ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
309059d7c14eSRichard Henderson }
3091c896fe29Sbellard 
309259d7c14eSRichard Henderson /* Mark a temporary as dead.  */
309359d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
309459d7c14eSRichard Henderson {
309559d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
309659d7c14eSRichard Henderson }
309759d7c14eSRichard Henderson 
309859d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
309959d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
310059d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
310159d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
310298b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
310398b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
310459d7c14eSRichard Henderson {
310559d7c14eSRichard Henderson     if (ts->fixed_reg) {
310659d7c14eSRichard Henderson         return;
310759d7c14eSRichard Henderson     }
310859d7c14eSRichard Henderson     if (!ts->mem_coherent) {
31097f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
31102272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
311159d7c14eSRichard Henderson         }
311259d7c14eSRichard Henderson         switch (ts->val_type) {
311359d7c14eSRichard Henderson         case TEMP_VAL_CONST:
311459d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
311559d7c14eSRichard Henderson                require it later in a register, so attempt to store the
311659d7c14eSRichard Henderson                constant to memory directly.  */
311759d7c14eSRichard Henderson             if (free_or_dead
311859d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
311959d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
312059d7c14eSRichard Henderson                 break;
312159d7c14eSRichard Henderson             }
312259d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
312398b4e186SRichard Henderson                       allocated_regs, preferred_regs);
312459d7c14eSRichard Henderson             /* fallthrough */
312559d7c14eSRichard Henderson 
312659d7c14eSRichard Henderson         case TEMP_VAL_REG:
312759d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
312859d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
312959d7c14eSRichard Henderson             break;
313059d7c14eSRichard Henderson 
313159d7c14eSRichard Henderson         case TEMP_VAL_MEM:
313259d7c14eSRichard Henderson             break;
313359d7c14eSRichard Henderson 
313459d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
313559d7c14eSRichard Henderson         default:
313659d7c14eSRichard Henderson             tcg_abort();
3137c896fe29Sbellard         }
31387f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
31397f6ceedfSAurelien Jarno     }
314059d7c14eSRichard Henderson     if (free_or_dead) {
314159d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
314259d7c14eSRichard Henderson     }
314359d7c14eSRichard Henderson }
31447f6ceedfSAurelien Jarno 
31457f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
3146b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
31477f6ceedfSAurelien Jarno {
3148f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
3149f8b2f202SRichard Henderson     if (ts != NULL) {
315098b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
3151c896fe29Sbellard     }
3152c896fe29Sbellard }
3153c896fe29Sbellard 
3154b016486eSRichard Henderson /**
3155b016486eSRichard Henderson  * tcg_reg_alloc:
3156b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
3157b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
3158b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
3159b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
3160b016486eSRichard Henderson  *
3161b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
3162b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
3163b016486eSRichard Henderson  */
3164b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
3165b016486eSRichard Henderson                             TCGRegSet allocated_regs,
3166b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
3167c896fe29Sbellard {
3168b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
3169b016486eSRichard Henderson     TCGRegSet reg_ct[2];
317091478cefSRichard Henderson     const int *order;
3171c896fe29Sbellard 
3172b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
3173b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
3174b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
3175b016486eSRichard Henderson 
3176b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
3177b016486eSRichard Henderson        or if the preference made no difference.  */
3178b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
3179b016486eSRichard Henderson 
318091478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
3181c896fe29Sbellard 
3182b016486eSRichard Henderson     /* Try free registers, preferences first.  */
3183b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3184b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3185b016486eSRichard Henderson 
3186b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3187b016486eSRichard Henderson             /* One register in the set.  */
3188b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3189b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
3190c896fe29Sbellard                 return reg;
3191c896fe29Sbellard             }
3192b016486eSRichard Henderson         } else {
319391478cefSRichard Henderson             for (i = 0; i < n; i++) {
3194b016486eSRichard Henderson                 TCGReg reg = order[i];
3195b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
3196b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
3197b016486eSRichard Henderson                     return reg;
3198b016486eSRichard Henderson                 }
3199b016486eSRichard Henderson             }
3200b016486eSRichard Henderson         }
3201b016486eSRichard Henderson     }
3202b016486eSRichard Henderson 
3203b016486eSRichard Henderson     /* We must spill something.  */
3204b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3205b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3206b016486eSRichard Henderson 
3207b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3208b016486eSRichard Henderson             /* One register in the set.  */
3209b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3210b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
3211c896fe29Sbellard             return reg;
3212b016486eSRichard Henderson         } else {
3213b016486eSRichard Henderson             for (i = 0; i < n; i++) {
3214b016486eSRichard Henderson                 TCGReg reg = order[i];
3215b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
3216b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
3217b016486eSRichard Henderson                     return reg;
3218b016486eSRichard Henderson                 }
3219b016486eSRichard Henderson             }
3220c896fe29Sbellard         }
3221c896fe29Sbellard     }
3222c896fe29Sbellard 
3223c896fe29Sbellard     tcg_abort();
3224c896fe29Sbellard }
3225c896fe29Sbellard 
322640ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
322740ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
322840ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
3229b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
323040ae5c62SRichard Henderson {
323140ae5c62SRichard Henderson     TCGReg reg;
323240ae5c62SRichard Henderson 
323340ae5c62SRichard Henderson     switch (ts->val_type) {
323440ae5c62SRichard Henderson     case TEMP_VAL_REG:
323540ae5c62SRichard Henderson         return;
323640ae5c62SRichard Henderson     case TEMP_VAL_CONST:
3237b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3238b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
323940ae5c62SRichard Henderson         tcg_out_movi(s, ts->type, reg, ts->val);
324040ae5c62SRichard Henderson         ts->mem_coherent = 0;
324140ae5c62SRichard Henderson         break;
324240ae5c62SRichard Henderson     case TEMP_VAL_MEM:
3243b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3244b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
324540ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
324640ae5c62SRichard Henderson         ts->mem_coherent = 1;
324740ae5c62SRichard Henderson         break;
324840ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
324940ae5c62SRichard Henderson     default:
325040ae5c62SRichard Henderson         tcg_abort();
325140ae5c62SRichard Henderson     }
325240ae5c62SRichard Henderson     ts->reg = reg;
325340ae5c62SRichard Henderson     ts->val_type = TEMP_VAL_REG;
325440ae5c62SRichard Henderson     s->reg_to_temp[reg] = ts;
325540ae5c62SRichard Henderson }
325640ae5c62SRichard Henderson 
325759d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
3258e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
325959d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
32601ad80729SAurelien Jarno {
32612c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
3262eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
3263f8bf00f1SRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg);
32641ad80729SAurelien Jarno }
32651ad80729SAurelien Jarno 
32669814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
3267641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
3268641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
3269641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
3270641d5fbeSbellard {
3271ac3b8891SRichard Henderson     int i, n;
3272641d5fbeSbellard 
3273ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
3274b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
3275641d5fbeSbellard     }
3276e5097dc8Sbellard }
3277e5097dc8Sbellard 
32783d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
32793d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
32803d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
32813d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
32823d5c5f87SAurelien Jarno {
3283ac3b8891SRichard Henderson     int i, n;
32843d5c5f87SAurelien Jarno 
3285ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
328612b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
328712b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
328812b9b11aSRichard Henderson                          || ts->fixed_reg
328912b9b11aSRichard Henderson                          || ts->mem_coherent);
32903d5c5f87SAurelien Jarno     }
32913d5c5f87SAurelien Jarno }
32923d5c5f87SAurelien Jarno 
3293e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
3294e8996ee0Sbellard    all globals are stored at their canonical location. */
3295e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
3296e5097dc8Sbellard {
3297e5097dc8Sbellard     int i;
3298e5097dc8Sbellard 
3299c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
3300b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
3301641d5fbeSbellard         if (ts->temp_local) {
3302b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
3303641d5fbeSbellard         } else {
33042c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
3305eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
3306eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3307c896fe29Sbellard         }
3308641d5fbeSbellard     }
3309e8996ee0Sbellard 
3310e8996ee0Sbellard     save_globals(s, allocated_regs);
3311c896fe29Sbellard }
3312c896fe29Sbellard 
3313bab1671fSRichard Henderson /*
3314bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_movi_*.
3315bab1671fSRichard Henderson  */
33160fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
3317ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
3318ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
3319e8996ee0Sbellard {
3320d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3321d63e3b6eSRichard Henderson     tcg_debug_assert(!ots->fixed_reg);
332259d7c14eSRichard Henderson 
332359d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
3324f8b2f202SRichard Henderson     if (ots->val_type == TEMP_VAL_REG) {
3325f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = NULL;
3326f8b2f202SRichard Henderson     }
3327e8996ee0Sbellard     ots->val_type = TEMP_VAL_CONST;
3328e8996ee0Sbellard     ots->val = val;
332959d7c14eSRichard Henderson     ots->mem_coherent = 0;
3330ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
3331ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
333259d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
3333f8bf00f1SRichard Henderson         temp_dead(s, ots);
33344c4e1ab2SAurelien Jarno     }
3335e8996ee0Sbellard }
3336e8996ee0Sbellard 
3337dd186292SRichard Henderson static void tcg_reg_alloc_movi(TCGContext *s, const TCGOp *op)
33380fe4fca4SPaolo Bonzini {
333943439139SRichard Henderson     TCGTemp *ots = arg_temp(op->args[0]);
3340dd186292SRichard Henderson     tcg_target_ulong val = op->args[1];
33410fe4fca4SPaolo Bonzini 
334269e3706dSRichard Henderson     tcg_reg_alloc_do_movi(s, ots, val, op->life, op->output_pref[0]);
33430fe4fca4SPaolo Bonzini }
33440fe4fca4SPaolo Bonzini 
3345bab1671fSRichard Henderson /*
3346bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
3347bab1671fSRichard Henderson  */
3348dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
3349c896fe29Sbellard {
3350dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
335169e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
3352c896fe29Sbellard     TCGTemp *ts, *ots;
3353450445d5SRichard Henderson     TCGType otype, itype;
3354c896fe29Sbellard 
3355d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
335669e3706dSRichard Henderson     preferred_regs = op->output_pref[0];
335743439139SRichard Henderson     ots = arg_temp(op->args[0]);
335843439139SRichard Henderson     ts = arg_temp(op->args[1]);
3359450445d5SRichard Henderson 
3360d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3361d63e3b6eSRichard Henderson     tcg_debug_assert(!ots->fixed_reg);
3362d63e3b6eSRichard Henderson 
3363450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
3364450445d5SRichard Henderson     otype = ots->type;
3365450445d5SRichard Henderson     itype = ts->type;
3366c896fe29Sbellard 
33670fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
33680fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
33690fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
33700fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
33710fe4fca4SPaolo Bonzini             temp_dead(s, ts);
33720fe4fca4SPaolo Bonzini         }
337369e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
33740fe4fca4SPaolo Bonzini         return;
33750fe4fca4SPaolo Bonzini     }
33760fe4fca4SPaolo Bonzini 
33770fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
33780fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
33790fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
33800fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
33810fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
338269e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
338369e3706dSRichard Henderson                   allocated_regs, preferred_regs);
3384c29c1d7eSAurelien Jarno     }
3385c29c1d7eSAurelien Jarno 
33860fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
3387d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
3388c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
3389c29c1d7eSAurelien Jarno            liveness analysis disabled). */
3390eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
3391c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
33922272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
3393c29c1d7eSAurelien Jarno         }
3394b3a62939SRichard Henderson         tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset);
3395c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
3396f8bf00f1SRichard Henderson             temp_dead(s, ts);
3397c29c1d7eSAurelien Jarno         }
3398f8bf00f1SRichard Henderson         temp_dead(s, ots);
3399e8996ee0Sbellard     } else {
3400d63e3b6eSRichard Henderson         if (IS_DEAD_ARG(1) && !ts->fixed_reg) {
3401c29c1d7eSAurelien Jarno             /* the mov can be suppressed */
3402c29c1d7eSAurelien Jarno             if (ots->val_type == TEMP_VAL_REG) {
3403f8b2f202SRichard Henderson                 s->reg_to_temp[ots->reg] = NULL;
3404c896fe29Sbellard             }
3405c29c1d7eSAurelien Jarno             ots->reg = ts->reg;
3406f8bf00f1SRichard Henderson             temp_dead(s, ts);
3407c29c1d7eSAurelien Jarno         } else {
3408c29c1d7eSAurelien Jarno             if (ots->val_type != TEMP_VAL_REG) {
3409c29c1d7eSAurelien Jarno                 /* When allocating a new register, make sure to not spill the
3410c29c1d7eSAurelien Jarno                    input one. */
3411c29c1d7eSAurelien Jarno                 tcg_regset_set_reg(allocated_regs, ts->reg);
3412450445d5SRichard Henderson                 ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
341369e3706dSRichard Henderson                                          allocated_regs, preferred_regs,
3414b016486eSRichard Henderson                                          ots->indirect_base);
3415c29c1d7eSAurelien Jarno             }
341678113e83SRichard Henderson             if (!tcg_out_mov(s, otype, ots->reg, ts->reg)) {
3417240c08d0SRichard Henderson                 /*
3418240c08d0SRichard Henderson                  * Cross register class move not supported.
3419240c08d0SRichard Henderson                  * Store the source register into the destination slot
3420240c08d0SRichard Henderson                  * and leave the destination temp as TEMP_VAL_MEM.
3421240c08d0SRichard Henderson                  */
3422240c08d0SRichard Henderson                 assert(!ots->fixed_reg);
3423240c08d0SRichard Henderson                 if (!ts->mem_allocated) {
3424240c08d0SRichard Henderson                     temp_allocate_frame(s, ots);
3425240c08d0SRichard Henderson                 }
3426240c08d0SRichard Henderson                 tcg_out_st(s, ts->type, ts->reg,
3427240c08d0SRichard Henderson                            ots->mem_base->reg, ots->mem_offset);
3428240c08d0SRichard Henderson                 ots->mem_coherent = 1;
3429240c08d0SRichard Henderson                 temp_free_or_dead(s, ots, -1);
3430240c08d0SRichard Henderson                 return;
343178113e83SRichard Henderson             }
3432c29c1d7eSAurelien Jarno         }
3433c896fe29Sbellard         ots->val_type = TEMP_VAL_REG;
3434c896fe29Sbellard         ots->mem_coherent = 0;
3435f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3436ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(0)) {
343798b4e186SRichard Henderson             temp_sync(s, ots, allocated_regs, 0, 0);
3438c29c1d7eSAurelien Jarno         }
3439ec7a869dSAurelien Jarno     }
3440c896fe29Sbellard }
3441c896fe29Sbellard 
3442bab1671fSRichard Henderson /*
3443bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
3444bab1671fSRichard Henderson  */
3445bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
3446bab1671fSRichard Henderson {
3447bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
3448bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
3449bab1671fSRichard Henderson     TCGTemp *its, *ots;
3450bab1671fSRichard Henderson     TCGType itype, vtype;
3451d6ecb4a9SRichard Henderson     intptr_t endian_fixup;
3452bab1671fSRichard Henderson     unsigned vece;
3453bab1671fSRichard Henderson     bool ok;
3454bab1671fSRichard Henderson 
3455bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
3456bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
3457bab1671fSRichard Henderson 
3458bab1671fSRichard Henderson     /* ENV should not be modified.  */
3459bab1671fSRichard Henderson     tcg_debug_assert(!ots->fixed_reg);
3460bab1671fSRichard Henderson 
3461bab1671fSRichard Henderson     itype = its->type;
3462bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
3463bab1671fSRichard Henderson     vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
3464bab1671fSRichard Henderson 
3465bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
3466bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
3467bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
3468bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
3469bab1671fSRichard Henderson             temp_dead(s, its);
3470bab1671fSRichard Henderson         }
3471bab1671fSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, op->output_pref[0]);
3472bab1671fSRichard Henderson         return;
3473bab1671fSRichard Henderson     }
3474bab1671fSRichard Henderson 
3475bab1671fSRichard Henderson     dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].u.regs;
3476bab1671fSRichard Henderson     dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].u.regs;
3477bab1671fSRichard Henderson 
3478bab1671fSRichard Henderson     /* Allocate the output register now.  */
3479bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
3480bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
3481bab1671fSRichard Henderson 
3482bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
3483bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
3484bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
3485bab1671fSRichard Henderson         }
3486bab1671fSRichard Henderson         ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
3487bab1671fSRichard Henderson                                  op->output_pref[0], ots->indirect_base);
3488bab1671fSRichard Henderson         ots->val_type = TEMP_VAL_REG;
3489bab1671fSRichard Henderson         ots->mem_coherent = 0;
3490bab1671fSRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3491bab1671fSRichard Henderson     }
3492bab1671fSRichard Henderson 
3493bab1671fSRichard Henderson     switch (its->val_type) {
3494bab1671fSRichard Henderson     case TEMP_VAL_REG:
3495bab1671fSRichard Henderson         /*
3496bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
3497bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
3498bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
3499bab1671fSRichard Henderson          */
3500bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
3501bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
3502bab1671fSRichard Henderson                 goto done;
3503bab1671fSRichard Henderson             }
3504bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
3505bab1671fSRichard Henderson         }
3506bab1671fSRichard Henderson         if (!its->mem_coherent) {
3507bab1671fSRichard Henderson             /*
3508bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
3509bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
3510bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
3511bab1671fSRichard Henderson              */
3512bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
3513bab1671fSRichard Henderson                 break;
3514bab1671fSRichard Henderson             }
3515bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
3516bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
3517bab1671fSRichard Henderson         }
3518bab1671fSRichard Henderson         /* fall through */
3519bab1671fSRichard Henderson 
3520bab1671fSRichard Henderson     case TEMP_VAL_MEM:
3521d6ecb4a9SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
3522d6ecb4a9SRichard Henderson         endian_fixup = itype == TCG_TYPE_I32 ? 4 : 8;
3523d6ecb4a9SRichard Henderson         endian_fixup -= 1 << vece;
3524d6ecb4a9SRichard Henderson #else
3525d6ecb4a9SRichard Henderson         endian_fixup = 0;
3526d6ecb4a9SRichard Henderson #endif
3527d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
3528d6ecb4a9SRichard Henderson                              its->mem_offset + endian_fixup)) {
3529d6ecb4a9SRichard Henderson             goto done;
3530d6ecb4a9SRichard Henderson         }
3531bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
3532bab1671fSRichard Henderson         break;
3533bab1671fSRichard Henderson 
3534bab1671fSRichard Henderson     default:
3535bab1671fSRichard Henderson         g_assert_not_reached();
3536bab1671fSRichard Henderson     }
3537bab1671fSRichard Henderson 
3538bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
3539bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
3540bab1671fSRichard Henderson     tcg_debug_assert(ok);
3541bab1671fSRichard Henderson 
3542bab1671fSRichard Henderson  done:
3543bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
3544bab1671fSRichard Henderson         temp_dead(s, its);
3545bab1671fSRichard Henderson     }
3546bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
3547bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
3548bab1671fSRichard Henderson     }
3549bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
3550bab1671fSRichard Henderson         temp_dead(s, ots);
3551bab1671fSRichard Henderson     }
3552bab1671fSRichard Henderson }
3553bab1671fSRichard Henderson 
3554dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
3555c896fe29Sbellard {
3556dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3557dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
355882790a87SRichard Henderson     TCGRegSet i_allocated_regs;
355982790a87SRichard Henderson     TCGRegSet o_allocated_regs;
3560b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
3561b6638662SRichard Henderson     TCGReg reg;
3562c896fe29Sbellard     TCGArg arg;
3563c896fe29Sbellard     const TCGArgConstraint *arg_ct;
3564c896fe29Sbellard     TCGTemp *ts;
3565c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
3566c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
3567c896fe29Sbellard 
3568c896fe29Sbellard     nb_oargs = def->nb_oargs;
3569c896fe29Sbellard     nb_iargs = def->nb_iargs;
3570c896fe29Sbellard 
3571c896fe29Sbellard     /* copy constants */
3572c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
3573dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
3574c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
3575c896fe29Sbellard 
3576d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
3577d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
357882790a87SRichard Henderson 
3579c896fe29Sbellard     /* satisfy input constraints */
3580c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
3581d62816f2SRichard Henderson         TCGRegSet i_preferred_regs, o_preferred_regs;
3582d62816f2SRichard Henderson 
3583c896fe29Sbellard         i = def->sorted_args[nb_oargs + k];
3584dd186292SRichard Henderson         arg = op->args[i];
3585c896fe29Sbellard         arg_ct = &def->args_ct[i];
358643439139SRichard Henderson         ts = arg_temp(arg);
358740ae5c62SRichard Henderson 
358840ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
358940ae5c62SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct)) {
3590c896fe29Sbellard             /* constant is OK for instruction */
3591c896fe29Sbellard             const_args[i] = 1;
3592c896fe29Sbellard             new_args[i] = ts->val;
3593d62816f2SRichard Henderson             continue;
3594c896fe29Sbellard         }
359540ae5c62SRichard Henderson 
3596d62816f2SRichard Henderson         i_preferred_regs = o_preferred_regs = 0;
35975ff9d6a4Sbellard         if (arg_ct->ct & TCG_CT_IALIAS) {
3598d62816f2SRichard Henderson             o_preferred_regs = op->output_pref[arg_ct->alias_index];
35995ff9d6a4Sbellard             if (ts->fixed_reg) {
36005ff9d6a4Sbellard                 /* if fixed register, we must allocate a new register
36015ff9d6a4Sbellard                    if the alias is not the same register */
3602d62816f2SRichard Henderson                 if (arg != op->args[arg_ct->alias_index]) {
36035ff9d6a4Sbellard                     goto allocate_in_reg;
3604d62816f2SRichard Henderson                 }
36055ff9d6a4Sbellard             } else {
3606c896fe29Sbellard                 /* if the input is aliased to an output and if it is
3607c896fe29Sbellard                    not dead after the instruction, we must allocate
3608c896fe29Sbellard                    a new register and move it */
3609866cb6cbSAurelien Jarno                 if (!IS_DEAD_ARG(i)) {
3610c896fe29Sbellard                     goto allocate_in_reg;
3611c896fe29Sbellard                 }
3612d62816f2SRichard Henderson 
36137e1df267SAurelien Jarno                 /* check if the current register has already been allocated
36147e1df267SAurelien Jarno                    for another input aliased to an output */
3615d62816f2SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG) {
36167e1df267SAurelien Jarno                     int k2, i2;
3617d62816f2SRichard Henderson                     reg = ts->reg;
36187e1df267SAurelien Jarno                     for (k2 = 0 ; k2 < k ; k2++) {
36197e1df267SAurelien Jarno                         i2 = def->sorted_args[nb_oargs + k2];
36207e1df267SAurelien Jarno                         if ((def->args_ct[i2].ct & TCG_CT_IALIAS) &&
3621d62816f2SRichard Henderson                             reg == new_args[i2]) {
36227e1df267SAurelien Jarno                             goto allocate_in_reg;
36237e1df267SAurelien Jarno                         }
36247e1df267SAurelien Jarno                     }
36255ff9d6a4Sbellard                 }
3626d62816f2SRichard Henderson                 i_preferred_regs = o_preferred_regs;
3627866cb6cbSAurelien Jarno             }
3628d62816f2SRichard Henderson         }
3629d62816f2SRichard Henderson 
3630d62816f2SRichard Henderson         temp_load(s, ts, arg_ct->u.regs, i_allocated_regs, i_preferred_regs);
3631c896fe29Sbellard         reg = ts->reg;
3632d62816f2SRichard Henderson 
3633c896fe29Sbellard         if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
3634c896fe29Sbellard             /* nothing to do : the constraint is satisfied */
3635c896fe29Sbellard         } else {
3636c896fe29Sbellard         allocate_in_reg:
3637c896fe29Sbellard             /* allocate a new register matching the constraint
3638c896fe29Sbellard                and move the temporary register into it */
3639d62816f2SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
3640d62816f2SRichard Henderson                       i_allocated_regs, 0);
364182790a87SRichard Henderson             reg = tcg_reg_alloc(s, arg_ct->u.regs, i_allocated_regs,
3642d62816f2SRichard Henderson                                 o_preferred_regs, ts->indirect_base);
364378113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
3644240c08d0SRichard Henderson                 /*
3645240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
3646240c08d0SRichard Henderson                  * temp back to its slot and load from there.
3647240c08d0SRichard Henderson                  */
3648240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
3649240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
3650240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
365178113e83SRichard Henderson             }
3652c896fe29Sbellard         }
3653c896fe29Sbellard         new_args[i] = reg;
3654c896fe29Sbellard         const_args[i] = 0;
365582790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
3656c896fe29Sbellard     }
3657c896fe29Sbellard 
3658c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
3659866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
3660866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
366143439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
3662c896fe29Sbellard         }
3663c896fe29Sbellard     }
3664c896fe29Sbellard 
3665a52ad07eSAurelien Jarno     if (def->flags & TCG_OPF_BB_END) {
366682790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
3667a52ad07eSAurelien Jarno     } else {
3668c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
3669b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
3670c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
3671c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
367282790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
3673c896fe29Sbellard                 }
3674c896fe29Sbellard             }
36753d5c5f87SAurelien Jarno         }
36763d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
36773d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
36783d5c5f87SAurelien Jarno                an exception. */
367982790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
3680c896fe29Sbellard         }
3681c896fe29Sbellard 
3682c896fe29Sbellard         /* satisfy the output constraints */
3683c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
3684c896fe29Sbellard             i = def->sorted_args[k];
3685dd186292SRichard Henderson             arg = op->args[i];
3686c896fe29Sbellard             arg_ct = &def->args_ct[i];
368743439139SRichard Henderson             ts = arg_temp(arg);
3688d63e3b6eSRichard Henderson 
3689d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
3690d63e3b6eSRichard Henderson             tcg_debug_assert(!ts->fixed_reg);
3691d63e3b6eSRichard Henderson 
369217280ff4SRichard Henderson             if ((arg_ct->ct & TCG_CT_ALIAS)
369317280ff4SRichard Henderson                 && !const_args[arg_ct->alias_index]) {
36945ff9d6a4Sbellard                 reg = new_args[arg_ct->alias_index];
369582790a87SRichard Henderson             } else if (arg_ct->ct & TCG_CT_NEWREG) {
369682790a87SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->u.regs,
369782790a87SRichard Henderson                                     i_allocated_regs | o_allocated_regs,
369869e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
3699c896fe29Sbellard             } else {
370082790a87SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->u.regs, o_allocated_regs,
370169e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
3702c896fe29Sbellard             }
370382790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
3704639368ddSAurelien Jarno             if (ts->val_type == TEMP_VAL_REG) {
3705f8b2f202SRichard Henderson                 s->reg_to_temp[ts->reg] = NULL;
3706639368ddSAurelien Jarno             }
3707c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
3708c896fe29Sbellard             ts->reg = reg;
3709d63e3b6eSRichard Henderson             /*
3710d63e3b6eSRichard Henderson              * Temp value is modified, so the value kept in memory is
3711d63e3b6eSRichard Henderson              * potentially not the same.
3712d63e3b6eSRichard Henderson              */
3713c896fe29Sbellard             ts->mem_coherent = 0;
3714f8b2f202SRichard Henderson             s->reg_to_temp[reg] = ts;
3715c896fe29Sbellard             new_args[i] = reg;
3716c896fe29Sbellard         }
3717e8996ee0Sbellard     }
3718c896fe29Sbellard 
3719c896fe29Sbellard     /* emit instruction */
3720d2fd745fSRichard Henderson     if (def->flags & TCG_OPF_VECTOR) {
3721d2fd745fSRichard Henderson         tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
3722d2fd745fSRichard Henderson                        new_args, const_args);
3723d2fd745fSRichard Henderson     } else {
3724dd186292SRichard Henderson         tcg_out_op(s, op->opc, new_args, const_args);
3725d2fd745fSRichard Henderson     }
3726c896fe29Sbellard 
3727c896fe29Sbellard     /* move the outputs in the correct register if needed */
3728c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
372943439139SRichard Henderson         ts = arg_temp(op->args[i]);
3730d63e3b6eSRichard Henderson 
3731d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
3732d63e3b6eSRichard Henderson         tcg_debug_assert(!ts->fixed_reg);
3733d63e3b6eSRichard Henderson 
3734ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
373598b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
373659d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
3737f8bf00f1SRichard Henderson             temp_dead(s, ts);
3738ec7a869dSAurelien Jarno         }
3739c896fe29Sbellard     }
3740c896fe29Sbellard }
3741c896fe29Sbellard 
3742b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP
3743b03cce8eSbellard #define STACK_DIR(x) (-(x))
3744b03cce8eSbellard #else
3745b03cce8eSbellard #define STACK_DIR(x) (x)
3746b03cce8eSbellard #endif
3747b03cce8eSbellard 
3748dd186292SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
3749c896fe29Sbellard {
3750cd9090aaSRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
3751cd9090aaSRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
3752dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3753b6638662SRichard Henderson     int flags, nb_regs, i;
3754b6638662SRichard Henderson     TCGReg reg;
3755cf066674SRichard Henderson     TCGArg arg;
3756c896fe29Sbellard     TCGTemp *ts;
3757d3452f1fSRichard Henderson     intptr_t stack_offset;
3758d3452f1fSRichard Henderson     size_t call_stack_size;
3759cf066674SRichard Henderson     tcg_insn_unit *func_addr;
3760cf066674SRichard Henderson     int allocate_args;
3761c896fe29Sbellard     TCGRegSet allocated_regs;
3762c896fe29Sbellard 
3763dd186292SRichard Henderson     func_addr = (tcg_insn_unit *)(intptr_t)op->args[nb_oargs + nb_iargs];
3764dd186292SRichard Henderson     flags = op->args[nb_oargs + nb_iargs + 1];
3765c896fe29Sbellard 
37666e17d0c5SStefan Weil     nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
3767c45cb8bbSRichard Henderson     if (nb_regs > nb_iargs) {
3768c45cb8bbSRichard Henderson         nb_regs = nb_iargs;
3769cf066674SRichard Henderson     }
3770c896fe29Sbellard 
3771c896fe29Sbellard     /* assign stack slots first */
3772c45cb8bbSRichard Henderson     call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long);
3773c896fe29Sbellard     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
3774c896fe29Sbellard         ~(TCG_TARGET_STACK_ALIGN - 1);
3775b03cce8eSbellard     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
3776b03cce8eSbellard     if (allocate_args) {
3777345649c0SBlue Swirl         /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
3778345649c0SBlue Swirl            preallocate call stack */
3779345649c0SBlue Swirl         tcg_abort();
3780b03cce8eSbellard     }
378139cf05d3Sbellard 
378239cf05d3Sbellard     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
3783c45cb8bbSRichard Henderson     for (i = nb_regs; i < nb_iargs; i++) {
3784dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
378539cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP
378639cf05d3Sbellard         stack_offset -= sizeof(tcg_target_long);
378739cf05d3Sbellard #endif
378839cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
378943439139SRichard Henderson             ts = arg_temp(arg);
379040ae5c62SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
3791b722452aSRichard Henderson                       s->reserved_regs, 0);
3792e4d5434cSblueswir1             tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
379339cf05d3Sbellard         }
379439cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP
379539cf05d3Sbellard         stack_offset += sizeof(tcg_target_long);
379639cf05d3Sbellard #endif
3797c896fe29Sbellard     }
3798c896fe29Sbellard 
3799c896fe29Sbellard     /* assign input registers */
3800d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
3801c896fe29Sbellard     for (i = 0; i < nb_regs; i++) {
3802dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
380339cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
380443439139SRichard Henderson             ts = arg_temp(arg);
3805c896fe29Sbellard             reg = tcg_target_call_iarg_regs[i];
380640ae5c62SRichard Henderson 
3807c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
3808c896fe29Sbellard                 if (ts->reg != reg) {
38094250da10SRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
381078113e83SRichard Henderson                     if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
3811240c08d0SRichard Henderson                         /*
3812240c08d0SRichard Henderson                          * Cross register class move not supported.  Sync the
3813240c08d0SRichard Henderson                          * temp back to its slot and load from there.
3814240c08d0SRichard Henderson                          */
3815240c08d0SRichard Henderson                         temp_sync(s, ts, allocated_regs, 0, 0);
3816240c08d0SRichard Henderson                         tcg_out_ld(s, ts->type, reg,
3817240c08d0SRichard Henderson                                    ts->mem_base->reg, ts->mem_offset);
381878113e83SRichard Henderson                     }
3819c896fe29Sbellard                 }
3820c896fe29Sbellard             } else {
3821ccb1bb66SRichard Henderson                 TCGRegSet arg_set = 0;
382240ae5c62SRichard Henderson 
38234250da10SRichard Henderson                 tcg_reg_free(s, reg, allocated_regs);
382440ae5c62SRichard Henderson                 tcg_regset_set_reg(arg_set, reg);
3825b722452aSRichard Henderson                 temp_load(s, ts, arg_set, allocated_regs, 0);
3826c896fe29Sbellard             }
382740ae5c62SRichard Henderson 
3828c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
3829c896fe29Sbellard         }
383039cf05d3Sbellard     }
3831c896fe29Sbellard 
3832c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
3833866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3834866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
383543439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
3836c896fe29Sbellard         }
3837c896fe29Sbellard     }
3838c896fe29Sbellard 
3839c896fe29Sbellard     /* clobber call registers */
3840c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
3841c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
3842b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
3843c896fe29Sbellard         }
3844c896fe29Sbellard     }
3845c896fe29Sbellard 
384678505279SAurelien Jarno     /* Save globals if they might be written by the helper, sync them if
384778505279SAurelien Jarno        they might be read. */
384878505279SAurelien Jarno     if (flags & TCG_CALL_NO_READ_GLOBALS) {
384978505279SAurelien Jarno         /* Nothing to do */
385078505279SAurelien Jarno     } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) {
385178505279SAurelien Jarno         sync_globals(s, allocated_regs);
385278505279SAurelien Jarno     } else {
3853e8996ee0Sbellard         save_globals(s, allocated_regs);
3854b9c18f56Saurel32     }
3855c896fe29Sbellard 
3856cf066674SRichard Henderson     tcg_out_call(s, func_addr);
3857c896fe29Sbellard 
3858c896fe29Sbellard     /* assign output registers and emit moves if needed */
3859c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
3860dd186292SRichard Henderson         arg = op->args[i];
386143439139SRichard Henderson         ts = arg_temp(arg);
3862d63e3b6eSRichard Henderson 
3863d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
3864d63e3b6eSRichard Henderson         tcg_debug_assert(!ts->fixed_reg);
3865d63e3b6eSRichard Henderson 
3866c896fe29Sbellard         reg = tcg_target_call_oarg_regs[i];
3867eabb7b91SAurelien Jarno         tcg_debug_assert(s->reg_to_temp[reg] == NULL);
3868639368ddSAurelien Jarno         if (ts->val_type == TEMP_VAL_REG) {
3869f8b2f202SRichard Henderson             s->reg_to_temp[ts->reg] = NULL;
3870639368ddSAurelien Jarno         }
3871c896fe29Sbellard         ts->val_type = TEMP_VAL_REG;
3872c896fe29Sbellard         ts->reg = reg;
3873c896fe29Sbellard         ts->mem_coherent = 0;
3874f8b2f202SRichard Henderson         s->reg_to_temp[reg] = ts;
3875ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
387698b4e186SRichard Henderson             temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i));
387759d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
3878f8bf00f1SRichard Henderson             temp_dead(s, ts);
3879c896fe29Sbellard         }
3880c896fe29Sbellard     }
38818c11ad25SAurelien Jarno }
3882c896fe29Sbellard 
3883c896fe29Sbellard #ifdef CONFIG_PROFILER
3884c896fe29Sbellard 
3885c3fac113SEmilio G. Cota /* avoid copy/paste errors */
3886c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field)                       \
3887c3fac113SEmilio G. Cota     do {                                                \
3888c3fac113SEmilio G. Cota         (to)->field += atomic_read(&((from)->field));   \
3889c3fac113SEmilio G. Cota     } while (0)
3890c896fe29Sbellard 
3891c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field)                                       \
3892c3fac113SEmilio G. Cota     do {                                                                \
3893c3fac113SEmilio G. Cota         typeof((from)->field) val__ = atomic_read(&((from)->field));    \
3894c3fac113SEmilio G. Cota         if (val__ > (to)->field) {                                      \
3895c3fac113SEmilio G. Cota             (to)->field = val__;                                        \
3896c3fac113SEmilio G. Cota         }                                                               \
3897c3fac113SEmilio G. Cota     } while (0)
3898c3fac113SEmilio G. Cota 
3899c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */
3900c3fac113SEmilio G. Cota static inline
3901c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
3902c896fe29Sbellard {
39033468b59eSEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
3904c3fac113SEmilio G. Cota     unsigned int i;
3905c3fac113SEmilio G. Cota 
39063468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
39073468b59eSEmilio G. Cota         TCGContext *s = atomic_read(&tcg_ctxs[i]);
39083468b59eSEmilio G. Cota         const TCGProfile *orig = &s->prof;
3909c3fac113SEmilio G. Cota 
3910c3fac113SEmilio G. Cota         if (counters) {
391172fd2efbSEmilio G. Cota             PROF_ADD(prof, orig, cpu_exec_time);
3912c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count1);
3913c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count);
3914c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, op_count);
3915c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, op_count_max);
3916c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, temp_count);
3917c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, temp_count_max);
3918c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, del_op_count);
3919c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_in_len);
3920c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_out_len);
3921c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, search_out_len);
3922c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, interm_time);
3923c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_time);
3924c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, la_time);
3925c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, opt_time);
3926c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_count);
3927c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_time);
3928c3fac113SEmilio G. Cota         }
3929c3fac113SEmilio G. Cota         if (table) {
3930c896fe29Sbellard             int i;
3931d70724ceSzhanghailiang 
393215fc7daaSRichard Henderson             for (i = 0; i < NB_OPS; i++) {
3933c3fac113SEmilio G. Cota                 PROF_ADD(prof, orig, table_op_count[i]);
3934c3fac113SEmilio G. Cota             }
3935c3fac113SEmilio G. Cota         }
3936c3fac113SEmilio G. Cota     }
3937c3fac113SEmilio G. Cota }
3938c3fac113SEmilio G. Cota 
3939c3fac113SEmilio G. Cota #undef PROF_ADD
3940c3fac113SEmilio G. Cota #undef PROF_MAX
3941c3fac113SEmilio G. Cota 
3942c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof)
3943c3fac113SEmilio G. Cota {
3944c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, true, false);
3945c3fac113SEmilio G. Cota }
3946c3fac113SEmilio G. Cota 
3947c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof)
3948c3fac113SEmilio G. Cota {
3949c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, false, true);
3950c3fac113SEmilio G. Cota }
3951c3fac113SEmilio G. Cota 
3952d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
3953c3fac113SEmilio G. Cota {
3954c3fac113SEmilio G. Cota     TCGProfile prof = {};
3955c3fac113SEmilio G. Cota     int i;
3956c3fac113SEmilio G. Cota 
3957c3fac113SEmilio G. Cota     tcg_profile_snapshot_table(&prof);
3958c3fac113SEmilio G. Cota     for (i = 0; i < NB_OPS; i++) {
3959d4c51a0aSMarkus Armbruster         qemu_printf("%s %" PRId64 "\n", tcg_op_defs[i].name,
3960c3fac113SEmilio G. Cota                     prof.table_op_count[i]);
3961c896fe29Sbellard     }
3962c896fe29Sbellard }
396372fd2efbSEmilio G. Cota 
396472fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
396572fd2efbSEmilio G. Cota {
396672fd2efbSEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
396772fd2efbSEmilio G. Cota     unsigned int i;
396872fd2efbSEmilio G. Cota     int64_t ret = 0;
396972fd2efbSEmilio G. Cota 
397072fd2efbSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
397172fd2efbSEmilio G. Cota         const TCGContext *s = atomic_read(&tcg_ctxs[i]);
397272fd2efbSEmilio G. Cota         const TCGProfile *prof = &s->prof;
397372fd2efbSEmilio G. Cota 
397472fd2efbSEmilio G. Cota         ret += atomic_read(&prof->cpu_exec_time);
397572fd2efbSEmilio G. Cota     }
397672fd2efbSEmilio G. Cota     return ret;
397772fd2efbSEmilio G. Cota }
3978246ae24dSMax Filippov #else
3979d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
3980246ae24dSMax Filippov {
3981d4c51a0aSMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
3982246ae24dSMax Filippov }
398372fd2efbSEmilio G. Cota 
398472fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
398572fd2efbSEmilio G. Cota {
398672fd2efbSEmilio G. Cota     error_report("%s: TCG profiler not compiled", __func__);
398772fd2efbSEmilio G. Cota     exit(EXIT_FAILURE);
398872fd2efbSEmilio G. Cota }
3989c896fe29Sbellard #endif
3990c896fe29Sbellard 
3991c896fe29Sbellard 
39925bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
3993c896fe29Sbellard {
3994c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER
3995c3fac113SEmilio G. Cota     TCGProfile *prof = &s->prof;
3996c3fac113SEmilio G. Cota #endif
399715fa08f8SRichard Henderson     int i, num_insns;
399815fa08f8SRichard Henderson     TCGOp *op;
3999c896fe29Sbellard 
400004fe6400SRichard Henderson #ifdef CONFIG_PROFILER
400104fe6400SRichard Henderson     {
4002c1f543b7SEmilio G. Cota         int n = 0;
400304fe6400SRichard Henderson 
400415fa08f8SRichard Henderson         QTAILQ_FOREACH(op, &s->ops, link) {
400515fa08f8SRichard Henderson             n++;
400615fa08f8SRichard Henderson         }
4007c3fac113SEmilio G. Cota         atomic_set(&prof->op_count, prof->op_count + n);
4008c3fac113SEmilio G. Cota         if (n > prof->op_count_max) {
4009c3fac113SEmilio G. Cota             atomic_set(&prof->op_count_max, n);
401004fe6400SRichard Henderson         }
401104fe6400SRichard Henderson 
401204fe6400SRichard Henderson         n = s->nb_temps;
4013c3fac113SEmilio G. Cota         atomic_set(&prof->temp_count, prof->temp_count + n);
4014c3fac113SEmilio G. Cota         if (n > prof->temp_count_max) {
4015c3fac113SEmilio G. Cota             atomic_set(&prof->temp_count_max, n);
401604fe6400SRichard Henderson         }
401704fe6400SRichard Henderson     }
401804fe6400SRichard Henderson #endif
401904fe6400SRichard Henderson 
4020c896fe29Sbellard #ifdef DEBUG_DISAS
4021d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
4022d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
40231ee73216SRichard Henderson         qemu_log_lock();
402493fcfe39Saliguori         qemu_log("OP:\n");
40251894f69aSRichard Henderson         tcg_dump_ops(s, false);
402693fcfe39Saliguori         qemu_log("\n");
40271ee73216SRichard Henderson         qemu_log_unlock();
4028c896fe29Sbellard     }
4029c896fe29Sbellard #endif
4030c896fe29Sbellard 
4031bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
4032bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
4033bef16ab4SRichard Henderson     {
4034bef16ab4SRichard Henderson         TCGLabel *l;
4035bef16ab4SRichard Henderson         bool error = false;
4036bef16ab4SRichard Henderson 
4037bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
4038bef16ab4SRichard Henderson             if (unlikely(!l->present) && l->refs) {
4039bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
4040bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
4041bef16ab4SRichard Henderson                 error = true;
4042bef16ab4SRichard Henderson             }
4043bef16ab4SRichard Henderson         }
4044bef16ab4SRichard Henderson         assert(!error);
4045bef16ab4SRichard Henderson     }
4046bef16ab4SRichard Henderson #endif
4047bef16ab4SRichard Henderson 
4048c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
4049c3fac113SEmilio G. Cota     atomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
4050c5cc28ffSAurelien Jarno #endif
4051c5cc28ffSAurelien Jarno 
40528f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
4053c45cb8bbSRichard Henderson     tcg_optimize(s);
40548f2e8c07SKirill Batuzov #endif
40558f2e8c07SKirill Batuzov 
4056a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4057c3fac113SEmilio G. Cota     atomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
4058c3fac113SEmilio G. Cota     atomic_set(&prof->la_time, prof->la_time - profile_getclock());
4059a23a9ec6Sbellard #endif
4060c5cc28ffSAurelien Jarno 
4061b4fc67c7SRichard Henderson     reachable_code_pass(s);
4062b83eabeaSRichard Henderson     liveness_pass_1(s);
40635a18407fSRichard Henderson 
40645a18407fSRichard Henderson     if (s->nb_indirects > 0) {
40655a18407fSRichard Henderson #ifdef DEBUG_DISAS
40665a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
40675a18407fSRichard Henderson                      && qemu_log_in_addr_range(tb->pc))) {
40681ee73216SRichard Henderson             qemu_log_lock();
40695a18407fSRichard Henderson             qemu_log("OP before indirect lowering:\n");
40701894f69aSRichard Henderson             tcg_dump_ops(s, false);
40715a18407fSRichard Henderson             qemu_log("\n");
40721ee73216SRichard Henderson             qemu_log_unlock();
40735a18407fSRichard Henderson         }
40745a18407fSRichard Henderson #endif
40755a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
4076b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
40775a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
4078b83eabeaSRichard Henderson             liveness_pass_1(s);
40795a18407fSRichard Henderson         }
40805a18407fSRichard Henderson     }
4081c5cc28ffSAurelien Jarno 
4082a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4083c3fac113SEmilio G. Cota     atomic_set(&prof->la_time, prof->la_time + profile_getclock());
4084a23a9ec6Sbellard #endif
4085c896fe29Sbellard 
4086c896fe29Sbellard #ifdef DEBUG_DISAS
4087d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
4088d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
40891ee73216SRichard Henderson         qemu_log_lock();
4090c5cc28ffSAurelien Jarno         qemu_log("OP after optimization and liveness analysis:\n");
40911894f69aSRichard Henderson         tcg_dump_ops(s, true);
409293fcfe39Saliguori         qemu_log("\n");
40931ee73216SRichard Henderson         qemu_log_unlock();
4094c896fe29Sbellard     }
4095c896fe29Sbellard #endif
4096c896fe29Sbellard 
4097c896fe29Sbellard     tcg_reg_alloc_start(s);
4098c896fe29Sbellard 
4099e7e168f4SEmilio G. Cota     s->code_buf = tb->tc.ptr;
4100e7e168f4SEmilio G. Cota     s->code_ptr = tb->tc.ptr;
4101c896fe29Sbellard 
4102659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
41036001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
4104659ef5cbSRichard Henderson #endif
410557a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
410657a26946SRichard Henderson     s->pool_labels = NULL;
410757a26946SRichard Henderson #endif
41089ecefc84SRichard Henderson 
4109fca8a500SRichard Henderson     num_insns = -1;
411015fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
4111c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
4112b3db8758Sblueswir1 
4113c896fe29Sbellard #ifdef CONFIG_PROFILER
4114c3fac113SEmilio G. Cota         atomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
4115c896fe29Sbellard #endif
4116c45cb8bbSRichard Henderson 
4117c896fe29Sbellard         switch (opc) {
4118c896fe29Sbellard         case INDEX_op_mov_i32:
4119c896fe29Sbellard         case INDEX_op_mov_i64:
4120d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
4121dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
4122c896fe29Sbellard             break;
4123e8996ee0Sbellard         case INDEX_op_movi_i32:
4124e8996ee0Sbellard         case INDEX_op_movi_i64:
4125d2fd745fSRichard Henderson         case INDEX_op_dupi_vec:
4126dd186292SRichard Henderson             tcg_reg_alloc_movi(s, op);
4127e8996ee0Sbellard             break;
4128bab1671fSRichard Henderson         case INDEX_op_dup_vec:
4129bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
4130bab1671fSRichard Henderson             break;
4131765b842aSRichard Henderson         case INDEX_op_insn_start:
4132fca8a500SRichard Henderson             if (num_insns >= 0) {
41339f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
41349f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
41359f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
41369f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
4137fca8a500SRichard Henderson             }
4138fca8a500SRichard Henderson             num_insns++;
4139bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
4140bad729e2SRichard Henderson                 target_ulong a;
4141bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
4142efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
4143bad729e2SRichard Henderson #else
4144efee3746SRichard Henderson                 a = op->args[i];
4145bad729e2SRichard Henderson #endif
4146fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
4147bad729e2SRichard Henderson             }
4148c896fe29Sbellard             break;
41495ff9d6a4Sbellard         case INDEX_op_discard:
415043439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
41515ff9d6a4Sbellard             break;
4152c896fe29Sbellard         case INDEX_op_set_label:
4153e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
4154efee3746SRichard Henderson             tcg_out_label(s, arg_label(op->args[0]), s->code_ptr);
4155c896fe29Sbellard             break;
4156c896fe29Sbellard         case INDEX_op_call:
4157dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
4158c45cb8bbSRichard Henderson             break;
4159c896fe29Sbellard         default:
416025c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
4161be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
4162c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
4163c896fe29Sbellard                faster to have specialized register allocator functions for
4164c896fe29Sbellard                some common argument patterns */
4165dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
4166c896fe29Sbellard             break;
4167c896fe29Sbellard         }
41688d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
4169c896fe29Sbellard         check_regs(s);
4170c896fe29Sbellard #endif
4171b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
4172b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
4173b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
4174b125f9dcSRichard Henderson            generating code without having to check during generation.  */
4175644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
4176b125f9dcSRichard Henderson             return -1;
4177b125f9dcSRichard Henderson         }
41786e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
41796e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
41806e6c4efeSRichard Henderson             return -2;
41816e6c4efeSRichard Henderson         }
4182c896fe29Sbellard     }
4183fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
4184fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
4185c45cb8bbSRichard Henderson 
4186b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
4187659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
4188aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
4189aeee05f5SRichard Henderson     if (i < 0) {
4190aeee05f5SRichard Henderson         return i;
419123dceda6SRichard Henderson     }
4192659ef5cbSRichard Henderson #endif
419357a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
41941768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
41951768987bSRichard Henderson     if (i < 0) {
41961768987bSRichard Henderson         return i;
419757a26946SRichard Henderson     }
419857a26946SRichard Henderson #endif
41997ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
42007ecd02a0SRichard Henderson         return -2;
42017ecd02a0SRichard Henderson     }
4202c896fe29Sbellard 
4203c896fe29Sbellard     /* flush instruction cache */
42041813e175SRichard Henderson     flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr);
42052aeabc08SStefan Weil 
42061813e175SRichard Henderson     return tcg_current_code_size(s);
4207c896fe29Sbellard }
4208c896fe29Sbellard 
4209a23a9ec6Sbellard #ifdef CONFIG_PROFILER
42103de2faa9SMarkus Armbruster void tcg_dump_info(void)
4211a23a9ec6Sbellard {
4212c3fac113SEmilio G. Cota     TCGProfile prof = {};
4213c3fac113SEmilio G. Cota     const TCGProfile *s;
4214c3fac113SEmilio G. Cota     int64_t tb_count;
4215c3fac113SEmilio G. Cota     int64_t tb_div_count;
4216c3fac113SEmilio G. Cota     int64_t tot;
4217c3fac113SEmilio G. Cota 
4218c3fac113SEmilio G. Cota     tcg_profile_snapshot_counters(&prof);
4219c3fac113SEmilio G. Cota     s = &prof;
4220c3fac113SEmilio G. Cota     tb_count = s->tb_count;
4221c3fac113SEmilio G. Cota     tb_div_count = tb_count ? tb_count : 1;
4222c3fac113SEmilio G. Cota     tot = s->interm_time + s->code_time;
4223a23a9ec6Sbellard 
42243de2faa9SMarkus Armbruster     qemu_printf("JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
4225a23a9ec6Sbellard                 tot, tot / 2.4e9);
42263de2faa9SMarkus Armbruster     qemu_printf("translated TBs      %" PRId64 " (aborted=%" PRId64
42273de2faa9SMarkus Armbruster                 " %0.1f%%)\n",
4228fca8a500SRichard Henderson                 tb_count, s->tb_count1 - tb_count,
4229fca8a500SRichard Henderson                 (double)(s->tb_count1 - s->tb_count)
4230fca8a500SRichard Henderson                 / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
42313de2faa9SMarkus Armbruster     qemu_printf("avg ops/TB          %0.1f max=%d\n",
4232fca8a500SRichard Henderson                 (double)s->op_count / tb_div_count, s->op_count_max);
42333de2faa9SMarkus Armbruster     qemu_printf("deleted ops/TB      %0.2f\n",
4234fca8a500SRichard Henderson                 (double)s->del_op_count / tb_div_count);
42353de2faa9SMarkus Armbruster     qemu_printf("avg temps/TB        %0.2f max=%d\n",
4236fca8a500SRichard Henderson                 (double)s->temp_count / tb_div_count, s->temp_count_max);
42373de2faa9SMarkus Armbruster     qemu_printf("avg host code/TB    %0.1f\n",
4238fca8a500SRichard Henderson                 (double)s->code_out_len / tb_div_count);
42393de2faa9SMarkus Armbruster     qemu_printf("avg search data/TB  %0.1f\n",
4240fca8a500SRichard Henderson                 (double)s->search_out_len / tb_div_count);
4241a23a9ec6Sbellard 
42423de2faa9SMarkus Armbruster     qemu_printf("cycles/op           %0.1f\n",
4243a23a9ec6Sbellard                 s->op_count ? (double)tot / s->op_count : 0);
42443de2faa9SMarkus Armbruster     qemu_printf("cycles/in byte      %0.1f\n",
4245a23a9ec6Sbellard                 s->code_in_len ? (double)tot / s->code_in_len : 0);
42463de2faa9SMarkus Armbruster     qemu_printf("cycles/out byte     %0.1f\n",
4247a23a9ec6Sbellard                 s->code_out_len ? (double)tot / s->code_out_len : 0);
42483de2faa9SMarkus Armbruster     qemu_printf("cycles/search byte     %0.1f\n",
4249fca8a500SRichard Henderson                 s->search_out_len ? (double)tot / s->search_out_len : 0);
4250fca8a500SRichard Henderson     if (tot == 0) {
4251a23a9ec6Sbellard         tot = 1;
4252fca8a500SRichard Henderson     }
42533de2faa9SMarkus Armbruster     qemu_printf("  gen_interm time   %0.1f%%\n",
4254a23a9ec6Sbellard                 (double)s->interm_time / tot * 100.0);
42553de2faa9SMarkus Armbruster     qemu_printf("  gen_code time     %0.1f%%\n",
4256a23a9ec6Sbellard                 (double)s->code_time / tot * 100.0);
42573de2faa9SMarkus Armbruster     qemu_printf("optim./code time    %0.1f%%\n",
4258c5cc28ffSAurelien Jarno                 (double)s->opt_time / (s->code_time ? s->code_time : 1)
4259c5cc28ffSAurelien Jarno                 * 100.0);
42603de2faa9SMarkus Armbruster     qemu_printf("liveness/code time  %0.1f%%\n",
4261a23a9ec6Sbellard                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
42623de2faa9SMarkus Armbruster     qemu_printf("cpu_restore count   %" PRId64 "\n",
4263a23a9ec6Sbellard                 s->restore_count);
42643de2faa9SMarkus Armbruster     qemu_printf("  avg cycles        %0.1f\n",
4265a23a9ec6Sbellard                 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
4266a23a9ec6Sbellard }
4267a23a9ec6Sbellard #else
42683de2faa9SMarkus Armbruster void tcg_dump_info(void)
4269a23a9ec6Sbellard {
42703de2faa9SMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4271a23a9ec6Sbellard }
4272a23a9ec6Sbellard #endif
4273813da627SRichard Henderson 
4274813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
42755872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
42765872bbf2SRichard Henderson 
42775872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
42785872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
42795872bbf2SRichard Henderson 
42805872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
42815872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
42825872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
42835872bbf2SRichard Henderson 
42845872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
42855872bbf2SRichard Henderson */
4286813da627SRichard Henderson 
4287813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
4288813da627SRichard Henderson typedef enum {
4289813da627SRichard Henderson     JIT_NOACTION = 0,
4290813da627SRichard Henderson     JIT_REGISTER_FN,
4291813da627SRichard Henderson     JIT_UNREGISTER_FN
4292813da627SRichard Henderson } jit_actions_t;
4293813da627SRichard Henderson 
4294813da627SRichard Henderson struct jit_code_entry {
4295813da627SRichard Henderson     struct jit_code_entry *next_entry;
4296813da627SRichard Henderson     struct jit_code_entry *prev_entry;
4297813da627SRichard Henderson     const void *symfile_addr;
4298813da627SRichard Henderson     uint64_t symfile_size;
4299813da627SRichard Henderson };
4300813da627SRichard Henderson 
4301813da627SRichard Henderson struct jit_descriptor {
4302813da627SRichard Henderson     uint32_t version;
4303813da627SRichard Henderson     uint32_t action_flag;
4304813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
4305813da627SRichard Henderson     struct jit_code_entry *first_entry;
4306813da627SRichard Henderson };
4307813da627SRichard Henderson 
4308813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
4309813da627SRichard Henderson void __jit_debug_register_code(void)
4310813da627SRichard Henderson {
4311813da627SRichard Henderson     asm("");
4312813da627SRichard Henderson }
4313813da627SRichard Henderson 
4314813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
4315813da627SRichard Henderson    the version before we can set it.  */
4316813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
4317813da627SRichard Henderson 
4318813da627SRichard Henderson /* End GDB interface.  */
4319813da627SRichard Henderson 
4320813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
4321813da627SRichard Henderson {
4322813da627SRichard Henderson     const char *p = strtab + 1;
4323813da627SRichard Henderson 
4324813da627SRichard Henderson     while (1) {
4325813da627SRichard Henderson         if (strcmp(p, str) == 0) {
4326813da627SRichard Henderson             return p - strtab;
4327813da627SRichard Henderson         }
4328813da627SRichard Henderson         p += strlen(p) + 1;
4329813da627SRichard Henderson     }
4330813da627SRichard Henderson }
4331813da627SRichard Henderson 
43325872bbf2SRichard Henderson static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
43332c90784aSRichard Henderson                                  const void *debug_frame,
43342c90784aSRichard Henderson                                  size_t debug_frame_size)
4335813da627SRichard Henderson {
43365872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
43375872bbf2SRichard Henderson         uint32_t  len;
43385872bbf2SRichard Henderson         uint16_t  version;
43395872bbf2SRichard Henderson         uint32_t  abbrev;
43405872bbf2SRichard Henderson         uint8_t   ptr_size;
43415872bbf2SRichard Henderson         uint8_t   cu_die;
43425872bbf2SRichard Henderson         uint16_t  cu_lang;
43435872bbf2SRichard Henderson         uintptr_t cu_low_pc;
43445872bbf2SRichard Henderson         uintptr_t cu_high_pc;
43455872bbf2SRichard Henderson         uint8_t   fn_die;
43465872bbf2SRichard Henderson         char      fn_name[16];
43475872bbf2SRichard Henderson         uintptr_t fn_low_pc;
43485872bbf2SRichard Henderson         uintptr_t fn_high_pc;
43495872bbf2SRichard Henderson         uint8_t   cu_eoc;
43505872bbf2SRichard Henderson     };
4351813da627SRichard Henderson 
4352813da627SRichard Henderson     struct ElfImage {
4353813da627SRichard Henderson         ElfW(Ehdr) ehdr;
4354813da627SRichard Henderson         ElfW(Phdr) phdr;
43555872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
43565872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
43575872bbf2SRichard Henderson         struct DebugInfo di;
43585872bbf2SRichard Henderson         uint8_t    da[24];
43595872bbf2SRichard Henderson         char       str[80];
43605872bbf2SRichard Henderson     };
43615872bbf2SRichard Henderson 
43625872bbf2SRichard Henderson     struct ElfImage *img;
43635872bbf2SRichard Henderson 
43645872bbf2SRichard Henderson     static const struct ElfImage img_template = {
43655872bbf2SRichard Henderson         .ehdr = {
43665872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
43675872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
43685872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
43695872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
43705872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
43715872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
43725872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
43735872bbf2SRichard Henderson             .e_type = ET_EXEC,
43745872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
43755872bbf2SRichard Henderson             .e_version = EV_CURRENT,
43765872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
43775872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
43785872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
43795872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
43805872bbf2SRichard Henderson             .e_phnum = 1,
43815872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
43825872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
43835872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
4384abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
4385abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
4386abbb3eaeSRichard Henderson #endif
4387abbb3eaeSRichard Henderson #ifdef ELF_OSABI
4388abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
4389abbb3eaeSRichard Henderson #endif
43905872bbf2SRichard Henderson         },
43915872bbf2SRichard Henderson         .phdr = {
43925872bbf2SRichard Henderson             .p_type = PT_LOAD,
43935872bbf2SRichard Henderson             .p_flags = PF_X,
43945872bbf2SRichard Henderson         },
43955872bbf2SRichard Henderson         .shdr = {
43965872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
43975872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
43985872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
43995872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
44005872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
44015872bbf2SRichard Henderson             [1] = { /* .text */
44025872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
44035872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
44045872bbf2SRichard Henderson             },
44055872bbf2SRichard Henderson             [2] = { /* .debug_info */
44065872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
44075872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
44085872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
44095872bbf2SRichard Henderson             },
44105872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
44115872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
44125872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
44135872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
44145872bbf2SRichard Henderson             },
44155872bbf2SRichard Henderson             [4] = { /* .debug_frame */
44165872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
44175872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
44185872bbf2SRichard Henderson             },
44195872bbf2SRichard Henderson             [5] = { /* .symtab */
44205872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
44215872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
44225872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
44235872bbf2SRichard Henderson                 .sh_info = 1,
44245872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
44255872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
44265872bbf2SRichard Henderson             },
44275872bbf2SRichard Henderson             [6] = { /* .strtab */
44285872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
44295872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
44305872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
44315872bbf2SRichard Henderson             }
44325872bbf2SRichard Henderson         },
44335872bbf2SRichard Henderson         .sym = {
44345872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
44355872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
44365872bbf2SRichard Henderson                 .st_shndx = 1,
44375872bbf2SRichard Henderson             }
44385872bbf2SRichard Henderson         },
44395872bbf2SRichard Henderson         .di = {
44405872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
44415872bbf2SRichard Henderson             .version = 2,
44425872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
44435872bbf2SRichard Henderson             .cu_die = 1,
44445872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
44455872bbf2SRichard Henderson             .fn_die = 2,
44465872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
44475872bbf2SRichard Henderson         },
44485872bbf2SRichard Henderson         .da = {
44495872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
44505872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
44515872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
44525872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
44535872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
44545872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
44555872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
44565872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
44575872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
44585872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
44595872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
44605872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
44615872bbf2SRichard Henderson             0           /* no more abbrev */
44625872bbf2SRichard Henderson         },
44635872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
44645872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
4465813da627SRichard Henderson     };
4466813da627SRichard Henderson 
4467813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
4468813da627SRichard Henderson     static struct jit_code_entry one_entry;
4469813da627SRichard Henderson 
44705872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
4471813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
44722c90784aSRichard Henderson     DebugFrameHeader *dfh;
4473813da627SRichard Henderson 
44745872bbf2SRichard Henderson     img = g_malloc(img_size);
44755872bbf2SRichard Henderson     *img = img_template;
4476813da627SRichard Henderson 
44775872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
44785872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
44795872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
4480813da627SRichard Henderson 
44815872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
44825872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
44835872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
4484813da627SRichard Henderson 
44855872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
44865872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
44875872bbf2SRichard Henderson 
44885872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
44895872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
44905872bbf2SRichard Henderson 
44915872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
44925872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
44935872bbf2SRichard Henderson 
44945872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
44955872bbf2SRichard Henderson     img->sym[1].st_value = buf;
44965872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
44975872bbf2SRichard Henderson 
44985872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
449945aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
45005872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
450145aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
4502813da627SRichard Henderson 
45032c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
45042c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
45052c90784aSRichard Henderson     dfh->fde.func_start = buf;
45062c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
45072c90784aSRichard Henderson 
4508813da627SRichard Henderson #ifdef DEBUG_JIT
4509813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
4510813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
4511813da627SRichard Henderson     {
4512813da627SRichard Henderson         FILE *f = fopen("/tmp/qemu.jit", "w+b");
4513813da627SRichard Henderson         if (f) {
45145872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
4515813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
4516813da627SRichard Henderson             }
4517813da627SRichard Henderson             fclose(f);
4518813da627SRichard Henderson         }
4519813da627SRichard Henderson     }
4520813da627SRichard Henderson #endif
4521813da627SRichard Henderson 
4522813da627SRichard Henderson     one_entry.symfile_addr = img;
4523813da627SRichard Henderson     one_entry.symfile_size = img_size;
4524813da627SRichard Henderson 
4525813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
4526813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
4527813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
4528813da627SRichard Henderson     __jit_debug_register_code();
4529813da627SRichard Henderson }
4530813da627SRichard Henderson #else
45315872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
45325872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
4533813da627SRichard Henderson 
4534813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size,
45352c90784aSRichard Henderson                                  const void *debug_frame,
45362c90784aSRichard Henderson                                  size_t debug_frame_size)
4537813da627SRichard Henderson {
4538813da627SRichard Henderson }
4539813da627SRichard Henderson 
4540813da627SRichard Henderson void tcg_register_jit(void *buf, size_t buf_size)
4541813da627SRichard Henderson {
4542813da627SRichard Henderson }
4543813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
4544db432672SRichard Henderson 
4545db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
4546db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
4547db432672SRichard Henderson {
4548db432672SRichard Henderson     g_assert_not_reached();
4549db432672SRichard Henderson }
4550db432672SRichard Henderson #endif
4551