xref: /qemu/tcg/tcg.c (revision df5d2b1658b988cb2be557e9f3114115935506ef)
1c896fe29Sbellard /*
2c896fe29Sbellard  * Tiny Code Generator for QEMU
3c896fe29Sbellard  *
4c896fe29Sbellard  * Copyright (c) 2008 Fabrice Bellard
5c896fe29Sbellard  *
6c896fe29Sbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
7c896fe29Sbellard  * of this software and associated documentation files (the "Software"), to deal
8c896fe29Sbellard  * in the Software without restriction, including without limitation the rights
9c896fe29Sbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10c896fe29Sbellard  * copies of the Software, and to permit persons to whom the Software is
11c896fe29Sbellard  * furnished to do so, subject to the following conditions:
12c896fe29Sbellard  *
13c896fe29Sbellard  * The above copyright notice and this permission notice shall be included in
14c896fe29Sbellard  * all copies or substantial portions of the Software.
15c896fe29Sbellard  *
16c896fe29Sbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17c896fe29Sbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18c896fe29Sbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19c896fe29Sbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20c896fe29Sbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21c896fe29Sbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22c896fe29Sbellard  * THE SOFTWARE.
23c896fe29Sbellard  */
24c896fe29Sbellard 
25c896fe29Sbellard /* define it to use liveness analysis (better code) */
268f2e8c07SKirill Batuzov #define USE_TCG_OPTIMIZATIONS
27c896fe29Sbellard 
28757e725bSPeter Maydell #include "qemu/osdep.h"
29cca82982Saurel32 
30813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB.  */
31813da627SRichard Henderson #undef DEBUG_JIT
32813da627SRichard Henderson 
3372fd2efbSEmilio G. Cota #include "qemu/error-report.h"
34f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
351de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
36d4c51a0aSMarkus Armbruster #include "qemu/qemu-print.h"
371de7afc9SPaolo Bonzini #include "qemu/timer.h"
38084cfca1SRichard Henderson #include "qemu/cacheflush.h"
39c896fe29Sbellard 
40c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU
41c896fe29Sbellard    CPU definitions. Currently they are used for qemu_ld/st
42c896fe29Sbellard    instructions */
43c896fe29Sbellard #define NO_CPU_IO_DEFS
44c896fe29Sbellard #include "cpu.h"
45c896fe29Sbellard 
4663c91552SPaolo Bonzini #include "exec/exec-all.h"
4763c91552SPaolo Bonzini 
485cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY)
495cc8767dSLike Xu #include "hw/boards.h"
505cc8767dSLike Xu #endif
515cc8767dSLike Xu 
52dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
53813da627SRichard Henderson 
54edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX
55813da627SRichard Henderson # define ELF_CLASS  ELFCLASS32
56edee2579SRichard Henderson #else
57edee2579SRichard Henderson # define ELF_CLASS  ELFCLASS64
58813da627SRichard Henderson #endif
59813da627SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
60813da627SRichard Henderson # define ELF_DATA   ELFDATA2MSB
61813da627SRichard Henderson #else
62813da627SRichard Henderson # define ELF_DATA   ELFDATA2LSB
63813da627SRichard Henderson #endif
64813da627SRichard Henderson 
65c896fe29Sbellard #include "elf.h"
66508127e2SPaolo Bonzini #include "exec/log.h"
673468b59eSEmilio G. Cota #include "sysemu/sysemu.h"
68c896fe29Sbellard 
69139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and
70ce151109SPeter Maydell    used here. */
71e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s);
72f69d277eSRichard Henderson static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode);
73e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
746ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
752ba7fae2SRichard Henderson                         intptr_t value, intptr_t addend);
76c896fe29Sbellard 
77497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts.  */
78497a22ebSRichard Henderson typedef struct {
79497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
80497a22ebSRichard Henderson     uint32_t id;
81497a22ebSRichard Henderson     uint8_t version;
82497a22ebSRichard Henderson     char augmentation[1];
83497a22ebSRichard Henderson     uint8_t code_align;
84497a22ebSRichard Henderson     uint8_t data_align;
85497a22ebSRichard Henderson     uint8_t return_column;
86497a22ebSRichard Henderson } DebugFrameCIE;
87497a22ebSRichard Henderson 
88497a22ebSRichard Henderson typedef struct QEMU_PACKED {
89497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
90497a22ebSRichard Henderson     uint32_t cie_offset;
91edee2579SRichard Henderson     uintptr_t func_start;
92edee2579SRichard Henderson     uintptr_t func_len;
93497a22ebSRichard Henderson } DebugFrameFDEHeader;
94497a22ebSRichard Henderson 
952c90784aSRichard Henderson typedef struct QEMU_PACKED {
962c90784aSRichard Henderson     DebugFrameCIE cie;
972c90784aSRichard Henderson     DebugFrameFDEHeader fde;
982c90784aSRichard Henderson } DebugFrameHeader;
992c90784aSRichard Henderson 
100813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size,
1012c90784aSRichard Henderson                                  const void *debug_frame,
1022c90784aSRichard Henderson                                  size_t debug_frame_size)
103813da627SRichard Henderson     __attribute__((unused));
104813da627SRichard Henderson 
105139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */
106069ea736SRichard Henderson static const char *target_parse_constraint(TCGArgConstraint *ct,
107069ea736SRichard Henderson                                            const char *ct_str, TCGType type);
1082a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
109a05b5b9bSRichard Henderson                        intptr_t arg2);
11078113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
111c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1122a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
113c0ad3001SStefan Weil static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
114c0ad3001SStefan Weil                        const int *const_args);
115d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec
116e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
117e7632cfaSRichard Henderson                             TCGReg dst, TCGReg src);
118d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
119d6ecb4a9SRichard Henderson                              TCGReg dst, TCGReg base, intptr_t offset);
120e7632cfaSRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type,
121e7632cfaSRichard Henderson                              TCGReg dst, tcg_target_long arg);
122d2fd745fSRichard Henderson static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl,
123d2fd745fSRichard Henderson                            unsigned vece, const TCGArg *args,
124d2fd745fSRichard Henderson                            const int *const_args);
125d2fd745fSRichard Henderson #else
126e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
127e7632cfaSRichard Henderson                                    TCGReg dst, TCGReg src)
128e7632cfaSRichard Henderson {
129e7632cfaSRichard Henderson     g_assert_not_reached();
130e7632cfaSRichard Henderson }
131d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
132d6ecb4a9SRichard Henderson                                     TCGReg dst, TCGReg base, intptr_t offset)
133d6ecb4a9SRichard Henderson {
134d6ecb4a9SRichard Henderson     g_assert_not_reached();
135d6ecb4a9SRichard Henderson }
136e7632cfaSRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type,
137e7632cfaSRichard Henderson                                     TCGReg dst, tcg_target_long arg)
138e7632cfaSRichard Henderson {
139e7632cfaSRichard Henderson     g_assert_not_reached();
140e7632cfaSRichard Henderson }
141d2fd745fSRichard Henderson static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl,
142d2fd745fSRichard Henderson                                   unsigned vece, const TCGArg *args,
143d2fd745fSRichard Henderson                                   const int *const_args)
144d2fd745fSRichard Henderson {
145d2fd745fSRichard Henderson     g_assert_not_reached();
146d2fd745fSRichard Henderson }
147d2fd745fSRichard Henderson #endif
1482a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
149a05b5b9bSRichard Henderson                        intptr_t arg2);
15059d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
15159d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
152cf066674SRichard Henderson static void tcg_out_call(TCGContext *s, tcg_insn_unit *target);
153f6c6afc1SRichard Henderson static int tcg_target_const_match(tcg_target_long val, TCGType type,
154c0ad3001SStefan Weil                                   const TCGArgConstraint *arg_ct);
155659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
156aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s);
157659ef5cbSRichard Henderson #endif
158c896fe29Sbellard 
159a505785cSEmilio G. Cota #define TCG_HIGHWATER 1024
160a505785cSEmilio G. Cota 
161df2cce29SEmilio G. Cota static TCGContext **tcg_ctxs;
162df2cce29SEmilio G. Cota static unsigned int n_tcg_ctxs;
1631c2adb95SRichard Henderson TCGv_env cpu_env = 0;
164df2cce29SEmilio G. Cota 
165be2cdc5eSEmilio G. Cota struct tcg_region_tree {
166be2cdc5eSEmilio G. Cota     QemuMutex lock;
167be2cdc5eSEmilio G. Cota     GTree *tree;
168be2cdc5eSEmilio G. Cota     /* padding to avoid false sharing is computed at run-time */
169be2cdc5eSEmilio G. Cota };
170be2cdc5eSEmilio G. Cota 
171e8feb96fSEmilio G. Cota /*
172e8feb96fSEmilio G. Cota  * We divide code_gen_buffer into equally-sized "regions" that TCG threads
173e8feb96fSEmilio G. Cota  * dynamically allocate from as demand dictates. Given appropriate region
174e8feb96fSEmilio G. Cota  * sizing, this minimizes flushes even when some TCG threads generate a lot
175e8feb96fSEmilio G. Cota  * more code than others.
176e8feb96fSEmilio G. Cota  */
177e8feb96fSEmilio G. Cota struct tcg_region_state {
178e8feb96fSEmilio G. Cota     QemuMutex lock;
179e8feb96fSEmilio G. Cota 
180e8feb96fSEmilio G. Cota     /* fields set at init time */
181e8feb96fSEmilio G. Cota     void *start;
182e8feb96fSEmilio G. Cota     void *start_aligned;
183e8feb96fSEmilio G. Cota     void *end;
184e8feb96fSEmilio G. Cota     size_t n;
185e8feb96fSEmilio G. Cota     size_t size; /* size of one region */
186e8feb96fSEmilio G. Cota     size_t stride; /* .size + guard size */
187e8feb96fSEmilio G. Cota 
188e8feb96fSEmilio G. Cota     /* fields protected by the lock */
189e8feb96fSEmilio G. Cota     size_t current; /* current region index */
190e8feb96fSEmilio G. Cota     size_t agg_size_full; /* aggregate size of full regions */
191e8feb96fSEmilio G. Cota };
192e8feb96fSEmilio G. Cota 
193e8feb96fSEmilio G. Cota static struct tcg_region_state region;
194be2cdc5eSEmilio G. Cota /*
195be2cdc5eSEmilio G. Cota  * This is an array of struct tcg_region_tree's, with padding.
196be2cdc5eSEmilio G. Cota  * We use void * to simplify the computation of region_trees[i]; each
197be2cdc5eSEmilio G. Cota  * struct is found every tree_size bytes.
198be2cdc5eSEmilio G. Cota  */
199be2cdc5eSEmilio G. Cota static void *region_trees;
200be2cdc5eSEmilio G. Cota static size_t tree_size;
201d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
202b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
203c896fe29Sbellard 
2041813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
2054196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
206c896fe29Sbellard {
207c896fe29Sbellard     *s->code_ptr++ = v;
208c896fe29Sbellard }
209c896fe29Sbellard 
2104196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
2114196dca6SPeter Maydell                                                       uint8_t v)
2125c53bb81SPeter Maydell {
2131813e175SRichard Henderson     *p = v;
2145c53bb81SPeter Maydell }
2151813e175SRichard Henderson #endif
2165c53bb81SPeter Maydell 
2171813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
2184196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
219c896fe29Sbellard {
2201813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2211813e175SRichard Henderson         *s->code_ptr++ = v;
2221813e175SRichard Henderson     } else {
2231813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2244387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2251813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
2261813e175SRichard Henderson     }
227c896fe29Sbellard }
228c896fe29Sbellard 
2294196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2304196dca6SPeter Maydell                                                        uint16_t v)
2315c53bb81SPeter Maydell {
2321813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2331813e175SRichard Henderson         *p = v;
2341813e175SRichard Henderson     } else {
2355c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2365c53bb81SPeter Maydell     }
2371813e175SRichard Henderson }
2381813e175SRichard Henderson #endif
2395c53bb81SPeter Maydell 
2401813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
2414196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
242c896fe29Sbellard {
2431813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2441813e175SRichard Henderson         *s->code_ptr++ = v;
2451813e175SRichard Henderson     } else {
2461813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2474387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2481813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
2491813e175SRichard Henderson     }
250c896fe29Sbellard }
251c896fe29Sbellard 
2524196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
2534196dca6SPeter Maydell                                                        uint32_t v)
2545c53bb81SPeter Maydell {
2551813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2561813e175SRichard Henderson         *p = v;
2571813e175SRichard Henderson     } else {
2585c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2595c53bb81SPeter Maydell     }
2601813e175SRichard Henderson }
2611813e175SRichard Henderson #endif
2625c53bb81SPeter Maydell 
2631813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
2644196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
265ac26eb69SRichard Henderson {
2661813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2671813e175SRichard Henderson         *s->code_ptr++ = v;
2681813e175SRichard Henderson     } else {
2691813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2704387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2711813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
2721813e175SRichard Henderson     }
273ac26eb69SRichard Henderson }
274ac26eb69SRichard Henderson 
2754196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
2764196dca6SPeter Maydell                                                        uint64_t v)
2775c53bb81SPeter Maydell {
2781813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2791813e175SRichard Henderson         *p = v;
2801813e175SRichard Henderson     } else {
2815c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2825c53bb81SPeter Maydell     }
2831813e175SRichard Henderson }
2841813e175SRichard Henderson #endif
2855c53bb81SPeter Maydell 
286c896fe29Sbellard /* label relocation processing */
287c896fe29Sbellard 
2881813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
289bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
290c896fe29Sbellard {
2917ecd02a0SRichard Henderson     TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation));
292c896fe29Sbellard 
293c896fe29Sbellard     r->type = type;
294c896fe29Sbellard     r->ptr = code_ptr;
295c896fe29Sbellard     r->addend = addend;
2967ecd02a0SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
297c896fe29Sbellard }
298c896fe29Sbellard 
299bec16311SRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr)
300c896fe29Sbellard {
301eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
302c896fe29Sbellard     l->has_value = 1;
3031813e175SRichard Henderson     l->u.value_ptr = ptr;
304c896fe29Sbellard }
305c896fe29Sbellard 
30642a268c2SRichard Henderson TCGLabel *gen_new_label(void)
307c896fe29Sbellard {
308b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
30951e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
310c896fe29Sbellard 
3117ecd02a0SRichard Henderson     memset(l, 0, sizeof(TCGLabel));
3127ecd02a0SRichard Henderson     l->id = s->nb_labels++;
3137ecd02a0SRichard Henderson     QSIMPLEQ_INIT(&l->relocs);
3147ecd02a0SRichard Henderson 
315bef16ab4SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
31642a268c2SRichard Henderson 
31742a268c2SRichard Henderson     return l;
318c896fe29Sbellard }
319c896fe29Sbellard 
3207ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s)
3217ecd02a0SRichard Henderson {
3227ecd02a0SRichard Henderson     TCGLabel *l;
3237ecd02a0SRichard Henderson 
3247ecd02a0SRichard Henderson     QSIMPLEQ_FOREACH(l, &s->labels, next) {
3257ecd02a0SRichard Henderson         TCGRelocation *r;
3267ecd02a0SRichard Henderson         uintptr_t value = l->u.value;
3277ecd02a0SRichard Henderson 
3287ecd02a0SRichard Henderson         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
3297ecd02a0SRichard Henderson             if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
3307ecd02a0SRichard Henderson                 return false;
3317ecd02a0SRichard Henderson             }
3327ecd02a0SRichard Henderson         }
3337ecd02a0SRichard Henderson     }
3347ecd02a0SRichard Henderson     return true;
3357ecd02a0SRichard Henderson }
3367ecd02a0SRichard Henderson 
3379f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3389f754620SRichard Henderson {
339f14bed3fSRichard Henderson     /*
340f14bed3fSRichard Henderson      * We will check for overflow at the end of the opcode loop in
341f14bed3fSRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
342f14bed3fSRichard Henderson      */
343f14bed3fSRichard Henderson     s->tb_jmp_reset_offset[which] = tcg_current_code_size(s);
3449f754620SRichard Henderson }
3459f754620SRichard Henderson 
346139c1837SPaolo Bonzini #include "tcg-target.c.inc"
347c896fe29Sbellard 
348be2cdc5eSEmilio G. Cota /* compare a pointer @ptr and a tb_tc @s */
349be2cdc5eSEmilio G. Cota static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s)
350be2cdc5eSEmilio G. Cota {
351be2cdc5eSEmilio G. Cota     if (ptr >= s->ptr + s->size) {
352be2cdc5eSEmilio G. Cota         return 1;
353be2cdc5eSEmilio G. Cota     } else if (ptr < s->ptr) {
354be2cdc5eSEmilio G. Cota         return -1;
355be2cdc5eSEmilio G. Cota     }
356be2cdc5eSEmilio G. Cota     return 0;
357be2cdc5eSEmilio G. Cota }
358be2cdc5eSEmilio G. Cota 
359be2cdc5eSEmilio G. Cota static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp)
360be2cdc5eSEmilio G. Cota {
361be2cdc5eSEmilio G. Cota     const struct tb_tc *a = ap;
362be2cdc5eSEmilio G. Cota     const struct tb_tc *b = bp;
363be2cdc5eSEmilio G. Cota 
364be2cdc5eSEmilio G. Cota     /*
365be2cdc5eSEmilio G. Cota      * When both sizes are set, we know this isn't a lookup.
366be2cdc5eSEmilio G. Cota      * This is the most likely case: every TB must be inserted; lookups
367be2cdc5eSEmilio G. Cota      * are a lot less frequent.
368be2cdc5eSEmilio G. Cota      */
369be2cdc5eSEmilio G. Cota     if (likely(a->size && b->size)) {
370be2cdc5eSEmilio G. Cota         if (a->ptr > b->ptr) {
371be2cdc5eSEmilio G. Cota             return 1;
372be2cdc5eSEmilio G. Cota         } else if (a->ptr < b->ptr) {
373be2cdc5eSEmilio G. Cota             return -1;
374be2cdc5eSEmilio G. Cota         }
375be2cdc5eSEmilio G. Cota         /* a->ptr == b->ptr should happen only on deletions */
376be2cdc5eSEmilio G. Cota         g_assert(a->size == b->size);
377be2cdc5eSEmilio G. Cota         return 0;
378be2cdc5eSEmilio G. Cota     }
379be2cdc5eSEmilio G. Cota     /*
380be2cdc5eSEmilio G. Cota      * All lookups have either .size field set to 0.
381be2cdc5eSEmilio G. Cota      * From the glib sources we see that @ap is always the lookup key. However
382be2cdc5eSEmilio G. Cota      * the docs provide no guarantee, so we just mark this case as likely.
383be2cdc5eSEmilio G. Cota      */
384be2cdc5eSEmilio G. Cota     if (likely(a->size == 0)) {
385be2cdc5eSEmilio G. Cota         return ptr_cmp_tb_tc(a->ptr, b);
386be2cdc5eSEmilio G. Cota     }
387be2cdc5eSEmilio G. Cota     return ptr_cmp_tb_tc(b->ptr, a);
388be2cdc5eSEmilio G. Cota }
389be2cdc5eSEmilio G. Cota 
390be2cdc5eSEmilio G. Cota static void tcg_region_trees_init(void)
391be2cdc5eSEmilio G. Cota {
392be2cdc5eSEmilio G. Cota     size_t i;
393be2cdc5eSEmilio G. Cota 
394be2cdc5eSEmilio G. Cota     tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize);
395be2cdc5eSEmilio G. Cota     region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size);
396be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
397be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
398be2cdc5eSEmilio G. Cota 
399be2cdc5eSEmilio G. Cota         qemu_mutex_init(&rt->lock);
400be2cdc5eSEmilio G. Cota         rt->tree = g_tree_new(tb_tc_cmp);
401be2cdc5eSEmilio G. Cota     }
402be2cdc5eSEmilio G. Cota }
403be2cdc5eSEmilio G. Cota 
404be2cdc5eSEmilio G. Cota static struct tcg_region_tree *tc_ptr_to_region_tree(void *p)
405be2cdc5eSEmilio G. Cota {
406be2cdc5eSEmilio G. Cota     size_t region_idx;
407be2cdc5eSEmilio G. Cota 
408be2cdc5eSEmilio G. Cota     if (p < region.start_aligned) {
409be2cdc5eSEmilio G. Cota         region_idx = 0;
410be2cdc5eSEmilio G. Cota     } else {
411be2cdc5eSEmilio G. Cota         ptrdiff_t offset = p - region.start_aligned;
412be2cdc5eSEmilio G. Cota 
413be2cdc5eSEmilio G. Cota         if (offset > region.stride * (region.n - 1)) {
414be2cdc5eSEmilio G. Cota             region_idx = region.n - 1;
415be2cdc5eSEmilio G. Cota         } else {
416be2cdc5eSEmilio G. Cota             region_idx = offset / region.stride;
417be2cdc5eSEmilio G. Cota         }
418be2cdc5eSEmilio G. Cota     }
419be2cdc5eSEmilio G. Cota     return region_trees + region_idx * tree_size;
420be2cdc5eSEmilio G. Cota }
421be2cdc5eSEmilio G. Cota 
422be2cdc5eSEmilio G. Cota void tcg_tb_insert(TranslationBlock *tb)
423be2cdc5eSEmilio G. Cota {
424be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
425be2cdc5eSEmilio G. Cota 
426be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
427be2cdc5eSEmilio G. Cota     g_tree_insert(rt->tree, &tb->tc, tb);
428be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
429be2cdc5eSEmilio G. Cota }
430be2cdc5eSEmilio G. Cota 
431be2cdc5eSEmilio G. Cota void tcg_tb_remove(TranslationBlock *tb)
432be2cdc5eSEmilio G. Cota {
433be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
434be2cdc5eSEmilio G. Cota 
435be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
436be2cdc5eSEmilio G. Cota     g_tree_remove(rt->tree, &tb->tc);
437be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
438be2cdc5eSEmilio G. Cota }
439be2cdc5eSEmilio G. Cota 
440be2cdc5eSEmilio G. Cota /*
441be2cdc5eSEmilio G. Cota  * Find the TB 'tb' such that
442be2cdc5eSEmilio G. Cota  * tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size
443be2cdc5eSEmilio G. Cota  * Return NULL if not found.
444be2cdc5eSEmilio G. Cota  */
445be2cdc5eSEmilio G. Cota TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr)
446be2cdc5eSEmilio G. Cota {
447be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr);
448be2cdc5eSEmilio G. Cota     TranslationBlock *tb;
449be2cdc5eSEmilio G. Cota     struct tb_tc s = { .ptr = (void *)tc_ptr };
450be2cdc5eSEmilio G. Cota 
451be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
452be2cdc5eSEmilio G. Cota     tb = g_tree_lookup(rt->tree, &s);
453be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
454be2cdc5eSEmilio G. Cota     return tb;
455be2cdc5eSEmilio G. Cota }
456be2cdc5eSEmilio G. Cota 
457be2cdc5eSEmilio G. Cota static void tcg_region_tree_lock_all(void)
458be2cdc5eSEmilio G. Cota {
459be2cdc5eSEmilio G. Cota     size_t i;
460be2cdc5eSEmilio G. Cota 
461be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
462be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
463be2cdc5eSEmilio G. Cota 
464be2cdc5eSEmilio G. Cota         qemu_mutex_lock(&rt->lock);
465be2cdc5eSEmilio G. Cota     }
466be2cdc5eSEmilio G. Cota }
467be2cdc5eSEmilio G. Cota 
468be2cdc5eSEmilio G. Cota static void tcg_region_tree_unlock_all(void)
469be2cdc5eSEmilio G. Cota {
470be2cdc5eSEmilio G. Cota     size_t i;
471be2cdc5eSEmilio G. Cota 
472be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
473be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
474be2cdc5eSEmilio G. Cota 
475be2cdc5eSEmilio G. Cota         qemu_mutex_unlock(&rt->lock);
476be2cdc5eSEmilio G. Cota     }
477be2cdc5eSEmilio G. Cota }
478be2cdc5eSEmilio G. Cota 
479be2cdc5eSEmilio G. Cota void tcg_tb_foreach(GTraverseFunc func, gpointer user_data)
480be2cdc5eSEmilio G. Cota {
481be2cdc5eSEmilio G. Cota     size_t i;
482be2cdc5eSEmilio G. Cota 
483be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
484be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
485be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
486be2cdc5eSEmilio G. Cota 
487be2cdc5eSEmilio G. Cota         g_tree_foreach(rt->tree, func, user_data);
488be2cdc5eSEmilio G. Cota     }
489be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
490be2cdc5eSEmilio G. Cota }
491be2cdc5eSEmilio G. Cota 
492be2cdc5eSEmilio G. Cota size_t tcg_nb_tbs(void)
493be2cdc5eSEmilio G. Cota {
494be2cdc5eSEmilio G. Cota     size_t nb_tbs = 0;
495be2cdc5eSEmilio G. Cota     size_t i;
496be2cdc5eSEmilio G. Cota 
497be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
498be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
499be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
500be2cdc5eSEmilio G. Cota 
501be2cdc5eSEmilio G. Cota         nb_tbs += g_tree_nnodes(rt->tree);
502be2cdc5eSEmilio G. Cota     }
503be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
504be2cdc5eSEmilio G. Cota     return nb_tbs;
505be2cdc5eSEmilio G. Cota }
506be2cdc5eSEmilio G. Cota 
507938e897aSEmilio G. Cota static gboolean tcg_region_tree_traverse(gpointer k, gpointer v, gpointer data)
508938e897aSEmilio G. Cota {
509938e897aSEmilio G. Cota     TranslationBlock *tb = v;
510938e897aSEmilio G. Cota 
511938e897aSEmilio G. Cota     tb_destroy(tb);
512938e897aSEmilio G. Cota     return FALSE;
513938e897aSEmilio G. Cota }
514938e897aSEmilio G. Cota 
515be2cdc5eSEmilio G. Cota static void tcg_region_tree_reset_all(void)
516be2cdc5eSEmilio G. Cota {
517be2cdc5eSEmilio G. Cota     size_t i;
518be2cdc5eSEmilio G. Cota 
519be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
520be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
521be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
522be2cdc5eSEmilio G. Cota 
523938e897aSEmilio G. Cota         g_tree_foreach(rt->tree, tcg_region_tree_traverse, NULL);
524be2cdc5eSEmilio G. Cota         /* Increment the refcount first so that destroy acts as a reset */
525be2cdc5eSEmilio G. Cota         g_tree_ref(rt->tree);
526be2cdc5eSEmilio G. Cota         g_tree_destroy(rt->tree);
527be2cdc5eSEmilio G. Cota     }
528be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
529be2cdc5eSEmilio G. Cota }
530be2cdc5eSEmilio G. Cota 
531e8feb96fSEmilio G. Cota static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend)
532e8feb96fSEmilio G. Cota {
533e8feb96fSEmilio G. Cota     void *start, *end;
534e8feb96fSEmilio G. Cota 
535e8feb96fSEmilio G. Cota     start = region.start_aligned + curr_region * region.stride;
536e8feb96fSEmilio G. Cota     end = start + region.size;
537e8feb96fSEmilio G. Cota 
538e8feb96fSEmilio G. Cota     if (curr_region == 0) {
539e8feb96fSEmilio G. Cota         start = region.start;
540e8feb96fSEmilio G. Cota     }
541e8feb96fSEmilio G. Cota     if (curr_region == region.n - 1) {
542e8feb96fSEmilio G. Cota         end = region.end;
543e8feb96fSEmilio G. Cota     }
544e8feb96fSEmilio G. Cota 
545e8feb96fSEmilio G. Cota     *pstart = start;
546e8feb96fSEmilio G. Cota     *pend = end;
547e8feb96fSEmilio G. Cota }
548e8feb96fSEmilio G. Cota 
549e8feb96fSEmilio G. Cota static void tcg_region_assign(TCGContext *s, size_t curr_region)
550e8feb96fSEmilio G. Cota {
551e8feb96fSEmilio G. Cota     void *start, *end;
552e8feb96fSEmilio G. Cota 
553e8feb96fSEmilio G. Cota     tcg_region_bounds(curr_region, &start, &end);
554e8feb96fSEmilio G. Cota 
555e8feb96fSEmilio G. Cota     s->code_gen_buffer = start;
556e8feb96fSEmilio G. Cota     s->code_gen_ptr = start;
557e8feb96fSEmilio G. Cota     s->code_gen_buffer_size = end - start;
558e8feb96fSEmilio G. Cota     s->code_gen_highwater = end - TCG_HIGHWATER;
559e8feb96fSEmilio G. Cota }
560e8feb96fSEmilio G. Cota 
561e8feb96fSEmilio G. Cota static bool tcg_region_alloc__locked(TCGContext *s)
562e8feb96fSEmilio G. Cota {
563e8feb96fSEmilio G. Cota     if (region.current == region.n) {
564e8feb96fSEmilio G. Cota         return true;
565e8feb96fSEmilio G. Cota     }
566e8feb96fSEmilio G. Cota     tcg_region_assign(s, region.current);
567e8feb96fSEmilio G. Cota     region.current++;
568e8feb96fSEmilio G. Cota     return false;
569e8feb96fSEmilio G. Cota }
570e8feb96fSEmilio G. Cota 
571e8feb96fSEmilio G. Cota /*
572e8feb96fSEmilio G. Cota  * Request a new region once the one in use has filled up.
573e8feb96fSEmilio G. Cota  * Returns true on error.
574e8feb96fSEmilio G. Cota  */
575e8feb96fSEmilio G. Cota static bool tcg_region_alloc(TCGContext *s)
576e8feb96fSEmilio G. Cota {
577e8feb96fSEmilio G. Cota     bool err;
578e8feb96fSEmilio G. Cota     /* read the region size now; alloc__locked will overwrite it on success */
579e8feb96fSEmilio G. Cota     size_t size_full = s->code_gen_buffer_size;
580e8feb96fSEmilio G. Cota 
581e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
582e8feb96fSEmilio G. Cota     err = tcg_region_alloc__locked(s);
583e8feb96fSEmilio G. Cota     if (!err) {
584e8feb96fSEmilio G. Cota         region.agg_size_full += size_full - TCG_HIGHWATER;
585e8feb96fSEmilio G. Cota     }
586e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
587e8feb96fSEmilio G. Cota     return err;
588e8feb96fSEmilio G. Cota }
589e8feb96fSEmilio G. Cota 
590e8feb96fSEmilio G. Cota /*
591e8feb96fSEmilio G. Cota  * Perform a context's first region allocation.
592e8feb96fSEmilio G. Cota  * This function does _not_ increment region.agg_size_full.
593e8feb96fSEmilio G. Cota  */
594e8feb96fSEmilio G. Cota static inline bool tcg_region_initial_alloc__locked(TCGContext *s)
595e8feb96fSEmilio G. Cota {
596e8feb96fSEmilio G. Cota     return tcg_region_alloc__locked(s);
597e8feb96fSEmilio G. Cota }
598e8feb96fSEmilio G. Cota 
599e8feb96fSEmilio G. Cota /* Call from a safe-work context */
600e8feb96fSEmilio G. Cota void tcg_region_reset_all(void)
601e8feb96fSEmilio G. Cota {
602d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
603e8feb96fSEmilio G. Cota     unsigned int i;
604e8feb96fSEmilio G. Cota 
605e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
606e8feb96fSEmilio G. Cota     region.current = 0;
607e8feb96fSEmilio G. Cota     region.agg_size_full = 0;
608e8feb96fSEmilio G. Cota 
6093468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
610d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
6113468b59eSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(s);
612e8feb96fSEmilio G. Cota 
613e8feb96fSEmilio G. Cota         g_assert(!err);
614e8feb96fSEmilio G. Cota     }
615e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
616be2cdc5eSEmilio G. Cota 
617be2cdc5eSEmilio G. Cota     tcg_region_tree_reset_all();
618e8feb96fSEmilio G. Cota }
619e8feb96fSEmilio G. Cota 
6203468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
6213468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
6223468b59eSEmilio G. Cota {
6233468b59eSEmilio G. Cota     return 1;
6243468b59eSEmilio G. Cota }
6253468b59eSEmilio G. Cota #else
6263468b59eSEmilio G. Cota /*
6273468b59eSEmilio G. Cota  * It is likely that some vCPUs will translate more code than others, so we
6283468b59eSEmilio G. Cota  * first try to set more regions than max_cpus, with those regions being of
6293468b59eSEmilio G. Cota  * reasonable size. If that's not possible we make do by evenly dividing
6303468b59eSEmilio G. Cota  * the code_gen_buffer among the vCPUs.
6313468b59eSEmilio G. Cota  */
6323468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
6333468b59eSEmilio G. Cota {
6343468b59eSEmilio G. Cota     size_t i;
6353468b59eSEmilio G. Cota 
6363468b59eSEmilio G. Cota     /* Use a single region if all we have is one vCPU thread */
6375cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY)
6385cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
6395cc8767dSLike Xu     unsigned int max_cpus = ms->smp.max_cpus;
6405cc8767dSLike Xu #endif
6413468b59eSEmilio G. Cota     if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) {
6423468b59eSEmilio G. Cota         return 1;
6433468b59eSEmilio G. Cota     }
6443468b59eSEmilio G. Cota 
6453468b59eSEmilio G. Cota     /* Try to have more regions than max_cpus, with each region being >= 2 MB */
6463468b59eSEmilio G. Cota     for (i = 8; i > 0; i--) {
6473468b59eSEmilio G. Cota         size_t regions_per_thread = i;
6483468b59eSEmilio G. Cota         size_t region_size;
6493468b59eSEmilio G. Cota 
6503468b59eSEmilio G. Cota         region_size = tcg_init_ctx.code_gen_buffer_size;
6513468b59eSEmilio G. Cota         region_size /= max_cpus * regions_per_thread;
6523468b59eSEmilio G. Cota 
6533468b59eSEmilio G. Cota         if (region_size >= 2 * 1024u * 1024) {
6543468b59eSEmilio G. Cota             return max_cpus * regions_per_thread;
6553468b59eSEmilio G. Cota         }
6563468b59eSEmilio G. Cota     }
6573468b59eSEmilio G. Cota     /* If we can't, then just allocate one region per vCPU thread */
6583468b59eSEmilio G. Cota     return max_cpus;
6593468b59eSEmilio G. Cota }
6603468b59eSEmilio G. Cota #endif
6613468b59eSEmilio G. Cota 
662e8feb96fSEmilio G. Cota /*
663e8feb96fSEmilio G. Cota  * Initializes region partitioning.
664e8feb96fSEmilio G. Cota  *
665e8feb96fSEmilio G. Cota  * Called at init time from the parent thread (i.e. the one calling
666e8feb96fSEmilio G. Cota  * tcg_context_init), after the target's TCG globals have been set.
6673468b59eSEmilio G. Cota  *
6683468b59eSEmilio G. Cota  * Region partitioning works by splitting code_gen_buffer into separate regions,
6693468b59eSEmilio G. Cota  * and then assigning regions to TCG threads so that the threads can translate
6703468b59eSEmilio G. Cota  * code in parallel without synchronization.
6713468b59eSEmilio G. Cota  *
6723468b59eSEmilio G. Cota  * In softmmu the number of TCG threads is bounded by max_cpus, so we use at
6733468b59eSEmilio G. Cota  * least max_cpus regions in MTTCG. In !MTTCG we use a single region.
6743468b59eSEmilio G. Cota  * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...])
6753468b59eSEmilio G. Cota  * must have been parsed before calling this function, since it calls
6763468b59eSEmilio G. Cota  * qemu_tcg_mttcg_enabled().
6773468b59eSEmilio G. Cota  *
6783468b59eSEmilio G. Cota  * In user-mode we use a single region.  Having multiple regions in user-mode
6793468b59eSEmilio G. Cota  * is not supported, because the number of vCPU threads (recall that each thread
6803468b59eSEmilio G. Cota  * spawned by the guest corresponds to a vCPU thread) is only bounded by the
6813468b59eSEmilio G. Cota  * OS, and usually this number is huge (tens of thousands is not uncommon).
6823468b59eSEmilio G. Cota  * Thus, given this large bound on the number of vCPU threads and the fact
6833468b59eSEmilio G. Cota  * that code_gen_buffer is allocated at compile-time, we cannot guarantee
6843468b59eSEmilio G. Cota  * that the availability of at least one region per vCPU thread.
6853468b59eSEmilio G. Cota  *
6863468b59eSEmilio G. Cota  * However, this user-mode limitation is unlikely to be a significant problem
6873468b59eSEmilio G. Cota  * in practice. Multi-threaded guests share most if not all of their translated
6883468b59eSEmilio G. Cota  * code, which makes parallel code generation less appealing than in softmmu.
689e8feb96fSEmilio G. Cota  */
690e8feb96fSEmilio G. Cota void tcg_region_init(void)
691e8feb96fSEmilio G. Cota {
692e8feb96fSEmilio G. Cota     void *buf = tcg_init_ctx.code_gen_buffer;
693e8feb96fSEmilio G. Cota     void *aligned;
694e8feb96fSEmilio G. Cota     size_t size = tcg_init_ctx.code_gen_buffer_size;
695e8feb96fSEmilio G. Cota     size_t page_size = qemu_real_host_page_size;
696e8feb96fSEmilio G. Cota     size_t region_size;
697e8feb96fSEmilio G. Cota     size_t n_regions;
698e8feb96fSEmilio G. Cota     size_t i;
699e8feb96fSEmilio G. Cota 
7003468b59eSEmilio G. Cota     n_regions = tcg_n_regions();
701e8feb96fSEmilio G. Cota 
702e8feb96fSEmilio G. Cota     /* The first region will be 'aligned - buf' bytes larger than the others */
703e8feb96fSEmilio G. Cota     aligned = QEMU_ALIGN_PTR_UP(buf, page_size);
704e8feb96fSEmilio G. Cota     g_assert(aligned < tcg_init_ctx.code_gen_buffer + size);
705e8feb96fSEmilio G. Cota     /*
706e8feb96fSEmilio G. Cota      * Make region_size a multiple of page_size, using aligned as the start.
707e8feb96fSEmilio G. Cota      * As a result of this we might end up with a few extra pages at the end of
708e8feb96fSEmilio G. Cota      * the buffer; we will assign those to the last region.
709e8feb96fSEmilio G. Cota      */
710e8feb96fSEmilio G. Cota     region_size = (size - (aligned - buf)) / n_regions;
711e8feb96fSEmilio G. Cota     region_size = QEMU_ALIGN_DOWN(region_size, page_size);
712e8feb96fSEmilio G. Cota 
713e8feb96fSEmilio G. Cota     /* A region must have at least 2 pages; one code, one guard */
714e8feb96fSEmilio G. Cota     g_assert(region_size >= 2 * page_size);
715e8feb96fSEmilio G. Cota 
716e8feb96fSEmilio G. Cota     /* init the region struct */
717e8feb96fSEmilio G. Cota     qemu_mutex_init(&region.lock);
718e8feb96fSEmilio G. Cota     region.n = n_regions;
719e8feb96fSEmilio G. Cota     region.size = region_size - page_size;
720e8feb96fSEmilio G. Cota     region.stride = region_size;
721e8feb96fSEmilio G. Cota     region.start = buf;
722e8feb96fSEmilio G. Cota     region.start_aligned = aligned;
723e8feb96fSEmilio G. Cota     /* page-align the end, since its last page will be a guard page */
724e8feb96fSEmilio G. Cota     region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size);
725e8feb96fSEmilio G. Cota     /* account for that last guard page */
726e8feb96fSEmilio G. Cota     region.end -= page_size;
727e8feb96fSEmilio G. Cota 
728e8feb96fSEmilio G. Cota     /* set guard pages */
729e8feb96fSEmilio G. Cota     for (i = 0; i < region.n; i++) {
730e8feb96fSEmilio G. Cota         void *start, *end;
731e8feb96fSEmilio G. Cota         int rc;
732e8feb96fSEmilio G. Cota 
733e8feb96fSEmilio G. Cota         tcg_region_bounds(i, &start, &end);
734e8feb96fSEmilio G. Cota         rc = qemu_mprotect_none(end, page_size);
735e8feb96fSEmilio G. Cota         g_assert(!rc);
736e8feb96fSEmilio G. Cota     }
737e8feb96fSEmilio G. Cota 
738be2cdc5eSEmilio G. Cota     tcg_region_trees_init();
739be2cdc5eSEmilio G. Cota 
7403468b59eSEmilio G. Cota     /* In user-mode we support only one ctx, so do the initial allocation now */
7413468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
742e8feb96fSEmilio G. Cota     {
743e8feb96fSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(tcg_ctx);
744e8feb96fSEmilio G. Cota 
745e8feb96fSEmilio G. Cota         g_assert(!err);
746e8feb96fSEmilio G. Cota     }
7473468b59eSEmilio G. Cota #endif
748e8feb96fSEmilio G. Cota }
749e8feb96fSEmilio G. Cota 
75038b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s)
75138b47b19SEmilio G. Cota {
75238b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
75338b47b19SEmilio G. Cota     s->plugin_tb = g_new0(struct qemu_plugin_tb, 1);
75438b47b19SEmilio G. Cota     s->plugin_tb->insns =
75538b47b19SEmilio G. Cota         g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn);
75638b47b19SEmilio G. Cota #endif
75738b47b19SEmilio G. Cota }
75838b47b19SEmilio G. Cota 
759e8feb96fSEmilio G. Cota /*
7603468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
7613468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
7623468b59eSEmilio G. Cota  * before initiating translation.
7633468b59eSEmilio G. Cota  *
7643468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
7653468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
7663468b59eSEmilio G. Cota  *
7673468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
7683468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
7693468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
7703468b59eSEmilio G. Cota  *
7713468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
7723468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
7733468b59eSEmilio G. Cota  */
7743468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
7753468b59eSEmilio G. Cota void tcg_register_thread(void)
7763468b59eSEmilio G. Cota {
7773468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
7783468b59eSEmilio G. Cota }
7793468b59eSEmilio G. Cota #else
7803468b59eSEmilio G. Cota void tcg_register_thread(void)
7813468b59eSEmilio G. Cota {
7825cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
7833468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
7843468b59eSEmilio G. Cota     unsigned int i, n;
7853468b59eSEmilio G. Cota     bool err;
7863468b59eSEmilio G. Cota 
7873468b59eSEmilio G. Cota     *s = tcg_init_ctx;
7883468b59eSEmilio G. Cota 
7893468b59eSEmilio G. Cota     /* Relink mem_base.  */
7903468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
7913468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
7923468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
7933468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
7943468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
7953468b59eSEmilio G. Cota         }
7963468b59eSEmilio G. Cota     }
7973468b59eSEmilio G. Cota 
7983468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
799d73415a3SStefan Hajnoczi     n = qatomic_fetch_inc(&n_tcg_ctxs);
8005cc8767dSLike Xu     g_assert(n < ms->smp.max_cpus);
801d73415a3SStefan Hajnoczi     qatomic_set(&tcg_ctxs[n], s);
8023468b59eSEmilio G. Cota 
80338b47b19SEmilio G. Cota     if (n > 0) {
80438b47b19SEmilio G. Cota         alloc_tcg_plugin_context(s);
80538b47b19SEmilio G. Cota     }
80638b47b19SEmilio G. Cota 
8073468b59eSEmilio G. Cota     tcg_ctx = s;
8083468b59eSEmilio G. Cota     qemu_mutex_lock(&region.lock);
8093468b59eSEmilio G. Cota     err = tcg_region_initial_alloc__locked(tcg_ctx);
8103468b59eSEmilio G. Cota     g_assert(!err);
8113468b59eSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
8123468b59eSEmilio G. Cota }
8133468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
8143468b59eSEmilio G. Cota 
8153468b59eSEmilio G. Cota /*
816e8feb96fSEmilio G. Cota  * Returns the size (in bytes) of all translated code (i.e. from all regions)
817e8feb96fSEmilio G. Cota  * currently in the cache.
818e8feb96fSEmilio G. Cota  * See also: tcg_code_capacity()
819e8feb96fSEmilio G. Cota  * Do not confuse with tcg_current_code_size(); that one applies to a single
820e8feb96fSEmilio G. Cota  * TCG context.
821e8feb96fSEmilio G. Cota  */
822e8feb96fSEmilio G. Cota size_t tcg_code_size(void)
823e8feb96fSEmilio G. Cota {
824d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
825e8feb96fSEmilio G. Cota     unsigned int i;
826e8feb96fSEmilio G. Cota     size_t total;
827e8feb96fSEmilio G. Cota 
828e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
829e8feb96fSEmilio G. Cota     total = region.agg_size_full;
8303468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
831d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
832e8feb96fSEmilio G. Cota         size_t size;
833e8feb96fSEmilio G. Cota 
834d73415a3SStefan Hajnoczi         size = qatomic_read(&s->code_gen_ptr) - s->code_gen_buffer;
835e8feb96fSEmilio G. Cota         g_assert(size <= s->code_gen_buffer_size);
836e8feb96fSEmilio G. Cota         total += size;
837e8feb96fSEmilio G. Cota     }
838e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
839e8feb96fSEmilio G. Cota     return total;
840e8feb96fSEmilio G. Cota }
841e8feb96fSEmilio G. Cota 
842e8feb96fSEmilio G. Cota /*
843e8feb96fSEmilio G. Cota  * Returns the code capacity (in bytes) of the entire cache, i.e. including all
844e8feb96fSEmilio G. Cota  * regions.
845e8feb96fSEmilio G. Cota  * See also: tcg_code_size()
846e8feb96fSEmilio G. Cota  */
847e8feb96fSEmilio G. Cota size_t tcg_code_capacity(void)
848e8feb96fSEmilio G. Cota {
849e8feb96fSEmilio G. Cota     size_t guard_size, capacity;
850e8feb96fSEmilio G. Cota 
851e8feb96fSEmilio G. Cota     /* no need for synchronization; these variables are set at init time */
852e8feb96fSEmilio G. Cota     guard_size = region.stride - region.size;
853e8feb96fSEmilio G. Cota     capacity = region.end + guard_size - region.start;
854e8feb96fSEmilio G. Cota     capacity -= region.n * (guard_size + TCG_HIGHWATER);
855e8feb96fSEmilio G. Cota     return capacity;
856e8feb96fSEmilio G. Cota }
857e8feb96fSEmilio G. Cota 
858128ed227SEmilio G. Cota size_t tcg_tb_phys_invalidate_count(void)
859128ed227SEmilio G. Cota {
860d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
861128ed227SEmilio G. Cota     unsigned int i;
862128ed227SEmilio G. Cota     size_t total = 0;
863128ed227SEmilio G. Cota 
864128ed227SEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
865d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
866128ed227SEmilio G. Cota 
867d73415a3SStefan Hajnoczi         total += qatomic_read(&s->tb_phys_invalidate_count);
868128ed227SEmilio G. Cota     }
869128ed227SEmilio G. Cota     return total;
870128ed227SEmilio G. Cota }
871128ed227SEmilio G. Cota 
872c896fe29Sbellard /* pool based memory allocation */
873c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
874c896fe29Sbellard {
875c896fe29Sbellard     TCGPool *p;
876c896fe29Sbellard     int pool_size;
877c896fe29Sbellard 
878c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
879c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
8807267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
881c896fe29Sbellard         p->size = size;
8824055299eSKirill Batuzov         p->next = s->pool_first_large;
8834055299eSKirill Batuzov         s->pool_first_large = p;
8844055299eSKirill Batuzov         return p->data;
885c896fe29Sbellard     } else {
886c896fe29Sbellard         p = s->pool_current;
887c896fe29Sbellard         if (!p) {
888c896fe29Sbellard             p = s->pool_first;
889c896fe29Sbellard             if (!p)
890c896fe29Sbellard                 goto new_pool;
891c896fe29Sbellard         } else {
892c896fe29Sbellard             if (!p->next) {
893c896fe29Sbellard             new_pool:
894c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
8957267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
896c896fe29Sbellard                 p->size = pool_size;
897c896fe29Sbellard                 p->next = NULL;
898c896fe29Sbellard                 if (s->pool_current)
899c896fe29Sbellard                     s->pool_current->next = p;
900c896fe29Sbellard                 else
901c896fe29Sbellard                     s->pool_first = p;
902c896fe29Sbellard             } else {
903c896fe29Sbellard                 p = p->next;
904c896fe29Sbellard             }
905c896fe29Sbellard         }
906c896fe29Sbellard     }
907c896fe29Sbellard     s->pool_current = p;
908c896fe29Sbellard     s->pool_cur = p->data + size;
909c896fe29Sbellard     s->pool_end = p->data + p->size;
910c896fe29Sbellard     return p->data;
911c896fe29Sbellard }
912c896fe29Sbellard 
913c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
914c896fe29Sbellard {
9154055299eSKirill Batuzov     TCGPool *p, *t;
9164055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
9174055299eSKirill Batuzov         t = p->next;
9184055299eSKirill Batuzov         g_free(p);
9194055299eSKirill Batuzov     }
9204055299eSKirill Batuzov     s->pool_first_large = NULL;
921c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
922c896fe29Sbellard     s->pool_current = NULL;
923c896fe29Sbellard }
924c896fe29Sbellard 
925100b5e01SRichard Henderson typedef struct TCGHelperInfo {
926100b5e01SRichard Henderson     void *func;
927100b5e01SRichard Henderson     const char *name;
928afb49896SRichard Henderson     unsigned flags;
929afb49896SRichard Henderson     unsigned sizemask;
930100b5e01SRichard Henderson } TCGHelperInfo;
931100b5e01SRichard Henderson 
9322ef6175aSRichard Henderson #include "exec/helper-proto.h"
9332ef6175aSRichard Henderson 
934100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = {
9352ef6175aSRichard Henderson #include "exec/helper-tcg.h"
936100b5e01SRichard Henderson };
937619205fdSEmilio G. Cota static GHashTable *helper_table;
938100b5e01SRichard Henderson 
93991478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
940f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
9411c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
9421c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
94391478cefSRichard Henderson 
944c896fe29Sbellard void tcg_context_init(TCGContext *s)
945c896fe29Sbellard {
946100b5e01SRichard Henderson     int op, total_args, n, i;
947c896fe29Sbellard     TCGOpDef *def;
948c896fe29Sbellard     TCGArgConstraint *args_ct;
9491c2adb95SRichard Henderson     TCGTemp *ts;
950c896fe29Sbellard 
951c896fe29Sbellard     memset(s, 0, sizeof(*s));
952c896fe29Sbellard     s->nb_globals = 0;
953c896fe29Sbellard 
954c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
955c896fe29Sbellard        space */
956c896fe29Sbellard     total_args = 0;
957c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
958c896fe29Sbellard         def = &tcg_op_defs[op];
959c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
960c896fe29Sbellard         total_args += n;
961c896fe29Sbellard     }
962c896fe29Sbellard 
963bc2b17e6SRichard Henderson     args_ct = g_new0(TCGArgConstraint, total_args);
964c896fe29Sbellard 
965c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
966c896fe29Sbellard         def = &tcg_op_defs[op];
967c896fe29Sbellard         def->args_ct = args_ct;
968c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
969c896fe29Sbellard         args_ct += n;
970c896fe29Sbellard     }
971c896fe29Sbellard 
9725cd8f621SRichard Henderson     /* Register helpers.  */
97384fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
974619205fdSEmilio G. Cota     helper_table = g_hash_table_new(NULL, NULL);
97584fd9dd3SRichard Henderson 
976100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
97784fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
97872866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
979100b5e01SRichard Henderson     }
9805cd8f621SRichard Henderson 
981c896fe29Sbellard     tcg_target_init(s);
982f69d277eSRichard Henderson     process_op_defs(s);
98391478cefSRichard Henderson 
98491478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
98591478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
98691478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
98791478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
98891478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
98991478cefSRichard Henderson             break;
99091478cefSRichard Henderson         }
99191478cefSRichard Henderson     }
99291478cefSRichard Henderson     for (i = 0; i < n; ++i) {
99391478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
99491478cefSRichard Henderson     }
99591478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
99691478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
99791478cefSRichard Henderson     }
998b1311c4aSEmilio G. Cota 
99938b47b19SEmilio G. Cota     alloc_tcg_plugin_context(s);
100038b47b19SEmilio G. Cota 
1001b1311c4aSEmilio G. Cota     tcg_ctx = s;
10023468b59eSEmilio G. Cota     /*
10033468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
10043468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
10053468b59eSEmilio G. Cota      * reasoning behind this.
10063468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
10073468b59eSEmilio G. Cota      */
10083468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
1009df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
1010df2cce29SEmilio G. Cota     n_tcg_ctxs = 1;
10113468b59eSEmilio G. Cota #else
10125cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
10135cc8767dSLike Xu     unsigned int max_cpus = ms->smp.max_cpus;
10143468b59eSEmilio G. Cota     tcg_ctxs = g_new(TCGContext *, max_cpus);
10153468b59eSEmilio G. Cota #endif
10161c2adb95SRichard Henderson 
10171c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
10181c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
10191c2adb95SRichard Henderson     cpu_env = temp_tcgv_ptr(ts);
10209002ec79SRichard Henderson }
1021b03cce8eSbellard 
10226e3b2bfdSEmilio G. Cota /*
10236e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
10246e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
10256e3b2bfdSEmilio G. Cota  */
10266e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
10276e3b2bfdSEmilio G. Cota {
10286e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
10296e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
10306e3b2bfdSEmilio G. Cota     void *next;
10316e3b2bfdSEmilio G. Cota 
1032e8feb96fSEmilio G. Cota  retry:
10336e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
10346e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
10356e3b2bfdSEmilio G. Cota 
10366e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
1037e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
10386e3b2bfdSEmilio G. Cota             return NULL;
10396e3b2bfdSEmilio G. Cota         }
1040e8feb96fSEmilio G. Cota         goto retry;
1041e8feb96fSEmilio G. Cota     }
1042d73415a3SStefan Hajnoczi     qatomic_set(&s->code_gen_ptr, next);
104357a26946SRichard Henderson     s->data_gen_ptr = NULL;
10446e3b2bfdSEmilio G. Cota     return tb;
10456e3b2bfdSEmilio G. Cota }
10466e3b2bfdSEmilio G. Cota 
10479002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
10489002ec79SRichard Henderson {
10498163b749SRichard Henderson     size_t prologue_size, total_size;
10508163b749SRichard Henderson     void *buf0, *buf1;
10518163b749SRichard Henderson 
10528163b749SRichard Henderson     /* Put the prologue at the beginning of code_gen_buffer.  */
10538163b749SRichard Henderson     buf0 = s->code_gen_buffer;
10545b38ee31SRichard Henderson     total_size = s->code_gen_buffer_size;
10558163b749SRichard Henderson     s->code_ptr = buf0;
10568163b749SRichard Henderson     s->code_buf = buf0;
10575b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
10588163b749SRichard Henderson     s->code_gen_prologue = buf0;
10598163b749SRichard Henderson 
10605b38ee31SRichard Henderson     /* Compute a high-water mark, at which we voluntarily flush the buffer
10615b38ee31SRichard Henderson        and start over.  The size here is arbitrary, significantly larger
10625b38ee31SRichard Henderson        than we expect the code generation for any one opcode to require.  */
10635b38ee31SRichard Henderson     s->code_gen_highwater = s->code_gen_buffer + (total_size - TCG_HIGHWATER);
10645b38ee31SRichard Henderson 
10655b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
10665b38ee31SRichard Henderson     s->pool_labels = NULL;
10675b38ee31SRichard Henderson #endif
10685b38ee31SRichard Henderson 
10698163b749SRichard Henderson     /* Generate the prologue.  */
1070b03cce8eSbellard     tcg_target_qemu_prologue(s);
10715b38ee31SRichard Henderson 
10725b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
10735b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
10745b38ee31SRichard Henderson     {
10751768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
10761768987bSRichard Henderson         tcg_debug_assert(result == 0);
10775b38ee31SRichard Henderson     }
10785b38ee31SRichard Henderson #endif
10795b38ee31SRichard Henderson 
10808163b749SRichard Henderson     buf1 = s->code_ptr;
1081*df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
10828163b749SRichard Henderson     flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1);
1083*df5d2b16SRichard Henderson #endif
10848163b749SRichard Henderson 
10858163b749SRichard Henderson     /* Deduct the prologue from the buffer.  */
10868163b749SRichard Henderson     prologue_size = tcg_current_code_size(s);
10878163b749SRichard Henderson     s->code_gen_ptr = buf1;
10888163b749SRichard Henderson     s->code_gen_buffer = buf1;
10898163b749SRichard Henderson     s->code_buf = buf1;
10905b38ee31SRichard Henderson     total_size -= prologue_size;
10918163b749SRichard Henderson     s->code_gen_buffer_size = total_size;
10928163b749SRichard Henderson 
10938163b749SRichard Henderson     tcg_register_jit(s->code_gen_buffer, total_size);
1094d6b64b2bSRichard Henderson 
1095d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
1096d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
1097fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
10988163b749SRichard Henderson         qemu_log("PROLOGUE: [size=%zu]\n", prologue_size);
10995b38ee31SRichard Henderson         if (s->data_gen_ptr) {
11005b38ee31SRichard Henderson             size_t code_size = s->data_gen_ptr - buf0;
11015b38ee31SRichard Henderson             size_t data_size = prologue_size - code_size;
11025b38ee31SRichard Henderson             size_t i;
11035b38ee31SRichard Henderson 
11044c389f6eSRichard Henderson             log_disas(buf0, code_size);
11055b38ee31SRichard Henderson 
11065b38ee31SRichard Henderson             for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
11075b38ee31SRichard Henderson                 if (sizeof(tcg_target_ulong) == 8) {
11085b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
11095b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
11105b38ee31SRichard Henderson                              *(uint64_t *)(s->data_gen_ptr + i));
11115b38ee31SRichard Henderson                 } else {
11125b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .long  0x%08x\n",
11135b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
11145b38ee31SRichard Henderson                              *(uint32_t *)(s->data_gen_ptr + i));
11155b38ee31SRichard Henderson                 }
11165b38ee31SRichard Henderson             }
11175b38ee31SRichard Henderson         } else {
11184c389f6eSRichard Henderson             log_disas(buf0, prologue_size);
11195b38ee31SRichard Henderson         }
1120d6b64b2bSRichard Henderson         qemu_log("\n");
1121d6b64b2bSRichard Henderson         qemu_log_flush();
1122fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
1123d6b64b2bSRichard Henderson     }
1124d6b64b2bSRichard Henderson #endif
1125cedbcb01SEmilio G. Cota 
1126cedbcb01SEmilio G. Cota     /* Assert that goto_ptr is implemented completely.  */
1127cedbcb01SEmilio G. Cota     if (TCG_TARGET_HAS_goto_ptr) {
1128cedbcb01SEmilio G. Cota         tcg_debug_assert(s->code_gen_epilogue != NULL);
1129cedbcb01SEmilio G. Cota     }
1130c896fe29Sbellard }
1131c896fe29Sbellard 
1132c896fe29Sbellard void tcg_func_start(TCGContext *s)
1133c896fe29Sbellard {
1134c896fe29Sbellard     tcg_pool_reset(s);
1135c896fe29Sbellard     s->nb_temps = s->nb_globals;
11360ec9eabcSRichard Henderson 
11370ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
11380ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
11390ec9eabcSRichard Henderson 
1140abebf925SRichard Henderson     s->nb_ops = 0;
1141c896fe29Sbellard     s->nb_labels = 0;
1142c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1143c896fe29Sbellard 
11440a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
11450a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
11460a209d4bSRichard Henderson #endif
11470a209d4bSRichard Henderson 
114815fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
114915fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
1150bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
1151c896fe29Sbellard }
1152c896fe29Sbellard 
11537ca4b752SRichard Henderson static inline TCGTemp *tcg_temp_alloc(TCGContext *s)
11547ca4b752SRichard Henderson {
11557ca4b752SRichard Henderson     int n = s->nb_temps++;
11567ca4b752SRichard Henderson     tcg_debug_assert(n < TCG_MAX_TEMPS);
11577ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
11587ca4b752SRichard Henderson }
11597ca4b752SRichard Henderson 
11607ca4b752SRichard Henderson static inline TCGTemp *tcg_global_alloc(TCGContext *s)
11617ca4b752SRichard Henderson {
1162fa477d25SRichard Henderson     TCGTemp *ts;
1163fa477d25SRichard Henderson 
11647ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
11657ca4b752SRichard Henderson     s->nb_globals++;
1166fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1167fa477d25SRichard Henderson     ts->temp_global = 1;
1168fa477d25SRichard Henderson 
1169fa477d25SRichard Henderson     return ts;
1170c896fe29Sbellard }
1171c896fe29Sbellard 
1172085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1173b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1174c896fe29Sbellard {
1175c896fe29Sbellard     TCGTemp *ts;
1176c896fe29Sbellard 
1177b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
1178c896fe29Sbellard         tcg_abort();
1179b3a62939SRichard Henderson     }
11807ca4b752SRichard Henderson 
11817ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1182c896fe29Sbellard     ts->base_type = type;
1183c896fe29Sbellard     ts->type = type;
1184c896fe29Sbellard     ts->fixed_reg = 1;
1185c896fe29Sbellard     ts->reg = reg;
1186c896fe29Sbellard     ts->name = name;
1187c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
11887ca4b752SRichard Henderson 
1189085272b3SRichard Henderson     return ts;
1190a7812ae4Spbrook }
1191a7812ae4Spbrook 
1192b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1193a7812ae4Spbrook {
1194b3a62939SRichard Henderson     s->frame_start = start;
1195b3a62939SRichard Henderson     s->frame_end = start + size;
1196085272b3SRichard Henderson     s->frame_temp
1197085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1198b3a62939SRichard Henderson }
1199a7812ae4Spbrook 
1200085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
1201e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
1202c896fe29Sbellard {
1203b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1204dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
12057ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1206b3915dbbSRichard Henderson     int indirect_reg = 0, bigendian = 0;
12077ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
12087ca4b752SRichard Henderson     bigendian = 1;
12097ca4b752SRichard Henderson #endif
1210c896fe29Sbellard 
1211b3915dbbSRichard Henderson     if (!base_ts->fixed_reg) {
12125a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
12135a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1214b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
12155a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
12165a18407fSRichard Henderson                             ? 2 : 1);
12175a18407fSRichard Henderson         indirect_reg = 1;
1218b3915dbbSRichard Henderson     }
1219b3915dbbSRichard Henderson 
12207ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
12217ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1222c896fe29Sbellard         char buf[64];
12237ca4b752SRichard Henderson 
12247ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1225c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1226b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1227c896fe29Sbellard         ts->mem_allocated = 1;
1228b3a62939SRichard Henderson         ts->mem_base = base_ts;
12297ca4b752SRichard Henderson         ts->mem_offset = offset + bigendian * 4;
1230c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1231c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1232c896fe29Sbellard         ts->name = strdup(buf);
1233c896fe29Sbellard 
12347ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
12357ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
12367ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1237b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
12387ca4b752SRichard Henderson         ts2->mem_allocated = 1;
12397ca4b752SRichard Henderson         ts2->mem_base = base_ts;
12407ca4b752SRichard Henderson         ts2->mem_offset = offset + (1 - bigendian) * 4;
1241c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1242c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1243120c1084SRichard Henderson         ts2->name = strdup(buf);
12447ca4b752SRichard Henderson     } else {
1245c896fe29Sbellard         ts->base_type = type;
1246c896fe29Sbellard         ts->type = type;
1247b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1248c896fe29Sbellard         ts->mem_allocated = 1;
1249b3a62939SRichard Henderson         ts->mem_base = base_ts;
1250c896fe29Sbellard         ts->mem_offset = offset;
1251c896fe29Sbellard         ts->name = name;
1252c896fe29Sbellard     }
1253085272b3SRichard Henderson     return ts;
1254c896fe29Sbellard }
1255c896fe29Sbellard 
12565bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local)
1257c896fe29Sbellard {
1258b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1259c896fe29Sbellard     TCGTemp *ts;
1260641d5fbeSbellard     int idx, k;
1261c896fe29Sbellard 
12620ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
12630ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
12640ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
12650ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
12660ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
12670ec9eabcSRichard Henderson 
1268e8996ee0Sbellard         ts = &s->temps[idx];
1269e8996ee0Sbellard         ts->temp_allocated = 1;
12707ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
12717ca4b752SRichard Henderson         tcg_debug_assert(ts->temp_local == temp_local);
1272e8996ee0Sbellard     } else {
12737ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
12747ca4b752SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
12757ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
12767ca4b752SRichard Henderson 
1277c896fe29Sbellard             ts->base_type = type;
1278c896fe29Sbellard             ts->type = TCG_TYPE_I32;
1279e8996ee0Sbellard             ts->temp_allocated = 1;
1280641d5fbeSbellard             ts->temp_local = temp_local;
12817ca4b752SRichard Henderson 
12827ca4b752SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
12837ca4b752SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
12847ca4b752SRichard Henderson             ts2->type = TCG_TYPE_I32;
12857ca4b752SRichard Henderson             ts2->temp_allocated = 1;
12867ca4b752SRichard Henderson             ts2->temp_local = temp_local;
12877ca4b752SRichard Henderson         } else {
1288c896fe29Sbellard             ts->base_type = type;
1289c896fe29Sbellard             ts->type = type;
1290e8996ee0Sbellard             ts->temp_allocated = 1;
1291641d5fbeSbellard             ts->temp_local = temp_local;
1292c896fe29Sbellard         }
1293e8996ee0Sbellard     }
129427bfd83cSPeter Maydell 
129527bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
129627bfd83cSPeter Maydell     s->temps_in_use++;
129727bfd83cSPeter Maydell #endif
1298085272b3SRichard Henderson     return ts;
1299c896fe29Sbellard }
1300c896fe29Sbellard 
1301d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1302d2fd745fSRichard Henderson {
1303d2fd745fSRichard Henderson     TCGTemp *t;
1304d2fd745fSRichard Henderson 
1305d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1306d2fd745fSRichard Henderson     switch (type) {
1307d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1308d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1309d2fd745fSRichard Henderson         break;
1310d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1311d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1312d2fd745fSRichard Henderson         break;
1313d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1314d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1315d2fd745fSRichard Henderson         break;
1316d2fd745fSRichard Henderson     default:
1317d2fd745fSRichard Henderson         g_assert_not_reached();
1318d2fd745fSRichard Henderson     }
1319d2fd745fSRichard Henderson #endif
1320d2fd745fSRichard Henderson 
1321d2fd745fSRichard Henderson     t = tcg_temp_new_internal(type, 0);
1322d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1323d2fd745fSRichard Henderson }
1324d2fd745fSRichard Henderson 
1325d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1326d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1327d2fd745fSRichard Henderson {
1328d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1329d2fd745fSRichard Henderson 
1330d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1331d2fd745fSRichard Henderson 
1332d2fd745fSRichard Henderson     t = tcg_temp_new_internal(t->base_type, 0);
1333d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1334d2fd745fSRichard Henderson }
1335d2fd745fSRichard Henderson 
13365bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1337c896fe29Sbellard {
1338b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1339085272b3SRichard Henderson     int k, idx;
1340c896fe29Sbellard 
134127bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
134227bfd83cSPeter Maydell     s->temps_in_use--;
134327bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
134427bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
134527bfd83cSPeter Maydell     }
134627bfd83cSPeter Maydell #endif
134727bfd83cSPeter Maydell 
1348085272b3SRichard Henderson     tcg_debug_assert(ts->temp_global == 0);
1349eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
1350e8996ee0Sbellard     ts->temp_allocated = 0;
13510ec9eabcSRichard Henderson 
1352085272b3SRichard Henderson     idx = temp_idx(ts);
135318d13fa2SAlexander Graf     k = ts->base_type + (ts->temp_local ? TCG_TYPE_COUNT : 0);
13540ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
1355e8996ee0Sbellard }
1356e8996ee0Sbellard 
1357a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
1358a7812ae4Spbrook {
1359a7812ae4Spbrook     TCGv_i32 t0;
1360a7812ae4Spbrook     t0 = tcg_temp_new_i32();
1361e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
1362e8996ee0Sbellard     return t0;
1363c896fe29Sbellard }
1364c896fe29Sbellard 
1365a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
1366c896fe29Sbellard {
1367a7812ae4Spbrook     TCGv_i64 t0;
1368a7812ae4Spbrook     t0 = tcg_temp_new_i64();
1369e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
1370e8996ee0Sbellard     return t0;
1371c896fe29Sbellard }
1372c896fe29Sbellard 
1373a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
1374bdffd4a9Saurel32 {
1375a7812ae4Spbrook     TCGv_i32 t0;
1376a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
1377bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
1378bdffd4a9Saurel32     return t0;
1379bdffd4a9Saurel32 }
1380bdffd4a9Saurel32 
1381a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
1382bdffd4a9Saurel32 {
1383a7812ae4Spbrook     TCGv_i64 t0;
1384a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
1385bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
1386bdffd4a9Saurel32     return t0;
1387bdffd4a9Saurel32 }
1388bdffd4a9Saurel32 
138927bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
139027bfd83cSPeter Maydell void tcg_clear_temp_count(void)
139127bfd83cSPeter Maydell {
1392b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
139327bfd83cSPeter Maydell     s->temps_in_use = 0;
139427bfd83cSPeter Maydell }
139527bfd83cSPeter Maydell 
139627bfd83cSPeter Maydell int tcg_check_temp_count(void)
139727bfd83cSPeter Maydell {
1398b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
139927bfd83cSPeter Maydell     if (s->temps_in_use) {
140027bfd83cSPeter Maydell         /* Clear the count so that we don't give another
140127bfd83cSPeter Maydell          * warning immediately next time around.
140227bfd83cSPeter Maydell          */
140327bfd83cSPeter Maydell         s->temps_in_use = 0;
140427bfd83cSPeter Maydell         return 1;
140527bfd83cSPeter Maydell     }
140627bfd83cSPeter Maydell     return 0;
140727bfd83cSPeter Maydell }
140827bfd83cSPeter Maydell #endif
140927bfd83cSPeter Maydell 
1410be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1411be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1412be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1413be0f34b5SRichard Henderson {
1414d2fd745fSRichard Henderson     const bool have_vec
1415d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1416d2fd745fSRichard Henderson 
1417be0f34b5SRichard Henderson     switch (op) {
1418be0f34b5SRichard Henderson     case INDEX_op_discard:
1419be0f34b5SRichard Henderson     case INDEX_op_set_label:
1420be0f34b5SRichard Henderson     case INDEX_op_call:
1421be0f34b5SRichard Henderson     case INDEX_op_br:
1422be0f34b5SRichard Henderson     case INDEX_op_mb:
1423be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1424be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1425be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1426be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i32:
1427be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i32:
1428be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i64:
1429be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i64:
1430be0f34b5SRichard Henderson         return true;
1431be0f34b5SRichard Henderson 
143207ce0b05SRichard Henderson     case INDEX_op_qemu_st8_i32:
143307ce0b05SRichard Henderson         return TCG_TARGET_HAS_qemu_st8_i32;
143407ce0b05SRichard Henderson 
1435be0f34b5SRichard Henderson     case INDEX_op_goto_ptr:
1436be0f34b5SRichard Henderson         return TCG_TARGET_HAS_goto_ptr;
1437be0f34b5SRichard Henderson 
1438be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1439be0f34b5SRichard Henderson     case INDEX_op_movi_i32:
1440be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1441be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1442be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1443be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1444be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1445be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1446be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1447be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1448be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1449be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1450be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1451be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1452be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1453be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1454be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1455be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1456be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1457be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1458be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1459be0f34b5SRichard Henderson         return true;
1460be0f34b5SRichard Henderson 
1461be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1462be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1463be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1464be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1465be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1466be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1467be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1468be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1469be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1470be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1471be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1472be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1473be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1474be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1475be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1476be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1477be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1478be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1479be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1480be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1481fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
1482fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
1483be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1484be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1485be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1486be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1487be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1488be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1489be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1490be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1491be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1492be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1493be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1494be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1495be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1496be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1497be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1498be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1499be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1500be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1501be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1502be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1503be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1504be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1505be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1506be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1507be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1508be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1509be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1510be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1511be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1512be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1513be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1514be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1515be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1516be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1517be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1518be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1519be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1520be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1521be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1522be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1523be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1524be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1525be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1526be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1527be0f34b5SRichard Henderson 
1528be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1529be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1530be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1531be0f34b5SRichard Henderson 
1532be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1533be0f34b5SRichard Henderson     case INDEX_op_movi_i64:
1534be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1535be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1536be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1537be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1538be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1539be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1540be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1541be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1542be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1543be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1544be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1545be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1546be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1547be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1548be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1549be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1550be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1551be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1552be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1553be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1554be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1555be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1556be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1557be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1558be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1559be0f34b5SRichard Henderson 
1560be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1561be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1562be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1563be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1564be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1565be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1566be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1567be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1568be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1569be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
1570be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
1571be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
1572be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
1573be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
1574be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
1575be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
1576be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
1577be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
1578be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
1579be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
1580fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
1581fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
1582be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
1583be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrl_i64_i32;
1584be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
1585be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrh_i64_i32;
1586be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
1587be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
1588be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
1589be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
1590be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
1591be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
1592be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
1593be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
1594be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
1595be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
1596be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
1597be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
1598be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
1599be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
1600be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
1601be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
1602be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
1603be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
1604be0f34b5SRichard Henderson     case INDEX_op_not_i64:
1605be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
1606be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
1607be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
1608be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
1609be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
1610be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
1611be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
1612be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
1613be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
1614be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
1615be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
1616be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
1617be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
1618be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
1619be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
1620be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
1621be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
1622be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
1623be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
1624be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
1625be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
1626be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
1627be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
1628be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
1629be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
1630be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
1631be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
1632be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
1633be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
1634be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
1635be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
1636be0f34b5SRichard Henderson 
1637d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
1638d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
1639d2fd745fSRichard Henderson     case INDEX_op_dupi_vec:
164037ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
1641d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
1642d2fd745fSRichard Henderson     case INDEX_op_st_vec:
1643d2fd745fSRichard Henderson     case INDEX_op_add_vec:
1644d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
1645d2fd745fSRichard Henderson     case INDEX_op_and_vec:
1646d2fd745fSRichard Henderson     case INDEX_op_or_vec:
1647d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
1648212be173SRichard Henderson     case INDEX_op_cmp_vec:
1649d2fd745fSRichard Henderson         return have_vec;
1650d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
1651d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
1652d2fd745fSRichard Henderson     case INDEX_op_not_vec:
1653d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
1654d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
1655d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
1656bcefc902SRichard Henderson     case INDEX_op_abs_vec:
1657bcefc902SRichard Henderson         return have_vec && TCG_TARGET_HAS_abs_vec;
1658d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
1659d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
1660d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
1661d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
16623774030aSRichard Henderson     case INDEX_op_mul_vec:
16633774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
1664d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
1665d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
1666d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
1667d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
1668d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
1669d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
1670d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
1671d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
1672d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
1673d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
1674d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
1675d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
1676b0f7e744SRichard Henderson     case INDEX_op_rotli_vec:
1677b0f7e744SRichard Henderson         return have_vec && TCG_TARGET_HAS_roti_vec;
167823850a74SRichard Henderson     case INDEX_op_rotls_vec:
167923850a74SRichard Henderson         return have_vec && TCG_TARGET_HAS_rots_vec;
16805d0ceda9SRichard Henderson     case INDEX_op_rotlv_vec:
16815d0ceda9SRichard Henderson     case INDEX_op_rotrv_vec:
16825d0ceda9SRichard Henderson         return have_vec && TCG_TARGET_HAS_rotv_vec;
16838afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
16848afaf050SRichard Henderson     case INDEX_op_usadd_vec:
16858afaf050SRichard Henderson     case INDEX_op_sssub_vec:
16868afaf050SRichard Henderson     case INDEX_op_ussub_vec:
16878afaf050SRichard Henderson         return have_vec && TCG_TARGET_HAS_sat_vec;
1688dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
1689dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
1690dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
1691dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
1692dd0a0fcdSRichard Henderson         return have_vec && TCG_TARGET_HAS_minmax_vec;
169338dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
169438dc1294SRichard Henderson         return have_vec && TCG_TARGET_HAS_bitsel_vec;
1695f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
1696f75da298SRichard Henderson         return have_vec && TCG_TARGET_HAS_cmpsel_vec;
1697d2fd745fSRichard Henderson 
1698db432672SRichard Henderson     default:
1699db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
1700db432672SRichard Henderson         return true;
1701be0f34b5SRichard Henderson     }
1702be0f34b5SRichard Henderson }
1703be0f34b5SRichard Henderson 
170439cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment
170539cf05d3Sbellard    and endian swap. Maybe it would be better to do the alignment
170639cf05d3Sbellard    and endian swap in tcg_reg_alloc_call(). */
1707ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
1708c896fe29Sbellard {
170975e8b9b7SRichard Henderson     int i, real_args, nb_rets, pi;
1710bbb8a1b4SRichard Henderson     unsigned sizemask, flags;
1711afb49896SRichard Henderson     TCGHelperInfo *info;
171275e8b9b7SRichard Henderson     TCGOp *op;
1713afb49896SRichard Henderson 
1714619205fdSEmilio G. Cota     info = g_hash_table_lookup(helper_table, (gpointer)func);
1715bbb8a1b4SRichard Henderson     flags = info->flags;
1716bbb8a1b4SRichard Henderson     sizemask = info->sizemask;
17172bece2c8SRichard Henderson 
171838b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
171938b47b19SEmilio G. Cota     /* detect non-plugin helpers */
172038b47b19SEmilio G. Cota     if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) {
172138b47b19SEmilio G. Cota         tcg_ctx->plugin_insn->calls_helpers = true;
172238b47b19SEmilio G. Cota     }
172338b47b19SEmilio G. Cota #endif
172438b47b19SEmilio G. Cota 
172534b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
172634b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
172734b1a49cSRichard Henderson     /* We have 64-bit values in one register, but need to pass as two
172834b1a49cSRichard Henderson        separate parameters.  Split them.  */
172934b1a49cSRichard Henderson     int orig_sizemask = sizemask;
173034b1a49cSRichard Henderson     int orig_nargs = nargs;
173134b1a49cSRichard Henderson     TCGv_i64 retl, reth;
1732ae8b75dcSRichard Henderson     TCGTemp *split_args[MAX_OPC_PARAM];
173334b1a49cSRichard Henderson 
1734f764718dSRichard Henderson     retl = NULL;
1735f764718dSRichard Henderson     reth = NULL;
173634b1a49cSRichard Henderson     if (sizemask != 0) {
173734b1a49cSRichard Henderson         for (i = real_args = 0; i < nargs; ++i) {
173834b1a49cSRichard Henderson             int is_64bit = sizemask & (1 << (i+1)*2);
173934b1a49cSRichard Henderson             if (is_64bit) {
1740085272b3SRichard Henderson                 TCGv_i64 orig = temp_tcgv_i64(args[i]);
174134b1a49cSRichard Henderson                 TCGv_i32 h = tcg_temp_new_i32();
174234b1a49cSRichard Henderson                 TCGv_i32 l = tcg_temp_new_i32();
174334b1a49cSRichard Henderson                 tcg_gen_extr_i64_i32(l, h, orig);
1744ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(h);
1745ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(l);
174634b1a49cSRichard Henderson             } else {
174734b1a49cSRichard Henderson                 split_args[real_args++] = args[i];
174834b1a49cSRichard Henderson             }
174934b1a49cSRichard Henderson         }
175034b1a49cSRichard Henderson         nargs = real_args;
175134b1a49cSRichard Henderson         args = split_args;
175234b1a49cSRichard Henderson         sizemask = 0;
175334b1a49cSRichard Henderson     }
175434b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
17552bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
17562bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
17572bece2c8SRichard Henderson         int is_signed = sizemask & (2 << (i+1)*2);
17582bece2c8SRichard Henderson         if (!is_64bit) {
17592bece2c8SRichard Henderson             TCGv_i64 temp = tcg_temp_new_i64();
1760085272b3SRichard Henderson             TCGv_i64 orig = temp_tcgv_i64(args[i]);
17612bece2c8SRichard Henderson             if (is_signed) {
17622bece2c8SRichard Henderson                 tcg_gen_ext32s_i64(temp, orig);
17632bece2c8SRichard Henderson             } else {
17642bece2c8SRichard Henderson                 tcg_gen_ext32u_i64(temp, orig);
17652bece2c8SRichard Henderson             }
1766ae8b75dcSRichard Henderson             args[i] = tcgv_i64_temp(temp);
17672bece2c8SRichard Henderson         }
17682bece2c8SRichard Henderson     }
17692bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
17702bece2c8SRichard Henderson 
177115fa08f8SRichard Henderson     op = tcg_emit_op(INDEX_op_call);
177275e8b9b7SRichard Henderson 
177375e8b9b7SRichard Henderson     pi = 0;
1774ae8b75dcSRichard Henderson     if (ret != NULL) {
177534b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
177634b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
177734b1a49cSRichard Henderson         if (orig_sizemask & 1) {
177834b1a49cSRichard Henderson             /* The 32-bit ABI is going to return the 64-bit value in
177934b1a49cSRichard Henderson                the %o0/%o1 register pair.  Prepare for this by using
178034b1a49cSRichard Henderson                two return temporaries, and reassemble below.  */
178134b1a49cSRichard Henderson             retl = tcg_temp_new_i64();
178234b1a49cSRichard Henderson             reth = tcg_temp_new_i64();
1783ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(reth);
1784ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(retl);
178534b1a49cSRichard Henderson             nb_rets = 2;
178634b1a49cSRichard Henderson         } else {
1787ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
178834b1a49cSRichard Henderson             nb_rets = 1;
178934b1a49cSRichard Henderson         }
179034b1a49cSRichard Henderson #else
179134b1a49cSRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) {
179202eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
1793ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1794ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1795a7812ae4Spbrook #else
1796ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1797ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1798a7812ae4Spbrook #endif
1799a7812ae4Spbrook             nb_rets = 2;
180034b1a49cSRichard Henderson         } else {
1801ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1802a7812ae4Spbrook             nb_rets = 1;
1803a7812ae4Spbrook         }
180434b1a49cSRichard Henderson #endif
1805a7812ae4Spbrook     } else {
1806a7812ae4Spbrook         nb_rets = 0;
1807a7812ae4Spbrook     }
1808cd9090aaSRichard Henderson     TCGOP_CALLO(op) = nb_rets;
180975e8b9b7SRichard Henderson 
1810a7812ae4Spbrook     real_args = 0;
1811a7812ae4Spbrook     for (i = 0; i < nargs; i++) {
18122bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
1813bbb8a1b4SRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
181439cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS
181539cf05d3Sbellard             /* some targets want aligned 64 bit args */
1816ebd486d5Smalc             if (real_args & 1) {
181775e8b9b7SRichard Henderson                 op->args[pi++] = TCG_CALL_DUMMY_ARG;
1818ebd486d5Smalc                 real_args++;
181939cf05d3Sbellard             }
182039cf05d3Sbellard #endif
18213f90f252SRichard Henderson            /* If stack grows up, then we will be placing successive
18223f90f252SRichard Henderson               arguments at lower addresses, which means we need to
18233f90f252SRichard Henderson               reverse the order compared to how we would normally
18243f90f252SRichard Henderson               treat either big or little-endian.  For those arguments
18253f90f252SRichard Henderson               that will wind up in registers, this still works for
18263f90f252SRichard Henderson               HPPA (the only current STACK_GROWSUP target) since the
18273f90f252SRichard Henderson               argument registers are *also* allocated in decreasing
18283f90f252SRichard Henderson               order.  If another such target is added, this logic may
18293f90f252SRichard Henderson               have to get more complicated to differentiate between
18303f90f252SRichard Henderson               stack arguments and register arguments.  */
183102eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
1832ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1833ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1834c896fe29Sbellard #else
1835ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1836ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1837c896fe29Sbellard #endif
1838a7812ae4Spbrook             real_args += 2;
18392bece2c8SRichard Henderson             continue;
18402bece2c8SRichard Henderson         }
18412bece2c8SRichard Henderson 
1842ae8b75dcSRichard Henderson         op->args[pi++] = temp_arg(args[i]);
1843a7812ae4Spbrook         real_args++;
1844c896fe29Sbellard     }
184575e8b9b7SRichard Henderson     op->args[pi++] = (uintptr_t)func;
184675e8b9b7SRichard Henderson     op->args[pi++] = flags;
1847cd9090aaSRichard Henderson     TCGOP_CALLI(op) = real_args;
1848a7812ae4Spbrook 
184975e8b9b7SRichard Henderson     /* Make sure the fields didn't overflow.  */
1850cd9090aaSRichard Henderson     tcg_debug_assert(TCGOP_CALLI(op) == real_args);
185175e8b9b7SRichard Henderson     tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
18522bece2c8SRichard Henderson 
185334b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
185434b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
185534b1a49cSRichard Henderson     /* Free all of the parts we allocated above.  */
185634b1a49cSRichard Henderson     for (i = real_args = 0; i < orig_nargs; ++i) {
185734b1a49cSRichard Henderson         int is_64bit = orig_sizemask & (1 << (i+1)*2);
185834b1a49cSRichard Henderson         if (is_64bit) {
1859085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
1860085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
186134b1a49cSRichard Henderson         } else {
186234b1a49cSRichard Henderson             real_args++;
186334b1a49cSRichard Henderson         }
186434b1a49cSRichard Henderson     }
186534b1a49cSRichard Henderson     if (orig_sizemask & 1) {
186634b1a49cSRichard Henderson         /* The 32-bit ABI returned two 32-bit pieces.  Re-assemble them.
186734b1a49cSRichard Henderson            Note that describing these as TCGv_i64 eliminates an unnecessary
186834b1a49cSRichard Henderson            zero-extension that tcg_gen_concat_i32_i64 would create.  */
1869085272b3SRichard Henderson         tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth);
187034b1a49cSRichard Henderson         tcg_temp_free_i64(retl);
187134b1a49cSRichard Henderson         tcg_temp_free_i64(reth);
187234b1a49cSRichard Henderson     }
187334b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
18742bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
18752bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
18762bece2c8SRichard Henderson         if (!is_64bit) {
1877085272b3SRichard Henderson             tcg_temp_free_internal(args[i]);
18782bece2c8SRichard Henderson         }
18792bece2c8SRichard Henderson     }
18802bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
1881a7812ae4Spbrook }
1882c896fe29Sbellard 
18838fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
1884c896fe29Sbellard {
1885ac3b8891SRichard Henderson     int i, n;
1886c896fe29Sbellard     TCGTemp *ts;
1887ac3b8891SRichard Henderson 
1888ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
1889c896fe29Sbellard         ts = &s->temps[i];
1890ac3b8891SRichard Henderson         ts->val_type = (ts->fixed_reg ? TEMP_VAL_REG : TEMP_VAL_MEM);
1891c896fe29Sbellard     }
1892ac3b8891SRichard Henderson     for (n = s->nb_temps; i < n; i++) {
1893e8996ee0Sbellard         ts = &s->temps[i];
1894ac3b8891SRichard Henderson         ts->val_type = (ts->temp_local ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
1895e8996ee0Sbellard         ts->mem_allocated = 0;
1896e8996ee0Sbellard         ts->fixed_reg = 0;
1897e8996ee0Sbellard     }
1898f8b2f202SRichard Henderson 
1899f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
1900c896fe29Sbellard }
1901c896fe29Sbellard 
1902f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
1903f8b2f202SRichard Henderson                                  TCGTemp *ts)
1904c896fe29Sbellard {
19051807f4c4SRichard Henderson     int idx = temp_idx(ts);
1906ac56dd48Spbrook 
1907fa477d25SRichard Henderson     if (ts->temp_global) {
1908ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
1909f8b2f202SRichard Henderson     } else if (ts->temp_local) {
1910641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
1911f8b2f202SRichard Henderson     } else {
1912ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
1913c896fe29Sbellard     }
1914c896fe29Sbellard     return buf;
1915c896fe29Sbellard }
1916c896fe29Sbellard 
191743439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
191843439139SRichard Henderson                              int buf_size, TCGArg arg)
1919f8b2f202SRichard Henderson {
192043439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
1921f8b2f202SRichard Henderson }
1922f8b2f202SRichard Henderson 
19236e085f72SRichard Henderson /* Find helper name.  */
19246e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val)
1925e8996ee0Sbellard {
19266e085f72SRichard Henderson     const char *ret = NULL;
1927619205fdSEmilio G. Cota     if (helper_table) {
1928619205fdSEmilio G. Cota         TCGHelperInfo *info = g_hash_table_lookup(helper_table, (gpointer)val);
192972866e82SRichard Henderson         if (info) {
193072866e82SRichard Henderson             ret = info->name;
193172866e82SRichard Henderson         }
1932e8996ee0Sbellard     }
19336e085f72SRichard Henderson     return ret;
19344dc81f28Sbellard }
19354dc81f28Sbellard 
1936f48f3edeSblueswir1 static const char * const cond_name[] =
1937f48f3edeSblueswir1 {
19380aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
19390aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
1940f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
1941f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
1942f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
1943f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
1944f48f3edeSblueswir1     [TCG_COND_LE] = "le",
1945f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
1946f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
1947f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
1948f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
1949f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
1950f48f3edeSblueswir1 };
1951f48f3edeSblueswir1 
1952f713d6adSRichard Henderson static const char * const ldst_name[] =
1953f713d6adSRichard Henderson {
1954f713d6adSRichard Henderson     [MO_UB]   = "ub",
1955f713d6adSRichard Henderson     [MO_SB]   = "sb",
1956f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
1957f713d6adSRichard Henderson     [MO_LESW] = "lesw",
1958f713d6adSRichard Henderson     [MO_LEUL] = "leul",
1959f713d6adSRichard Henderson     [MO_LESL] = "lesl",
1960f713d6adSRichard Henderson     [MO_LEQ]  = "leq",
1961f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
1962f713d6adSRichard Henderson     [MO_BESW] = "besw",
1963f713d6adSRichard Henderson     [MO_BEUL] = "beul",
1964f713d6adSRichard Henderson     [MO_BESL] = "besl",
1965f713d6adSRichard Henderson     [MO_BEQ]  = "beq",
1966f713d6adSRichard Henderson };
1967f713d6adSRichard Henderson 
19681f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
196952bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY
19701f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
19711f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
19721f00b27fSSergey Sorokin #else
19731f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
19741f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
19751f00b27fSSergey Sorokin #endif
19761f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
19771f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
19781f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
19791f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
19801f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
19811f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
19821f00b27fSSergey Sorokin };
19831f00b27fSSergey Sorokin 
1984b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
1985b016486eSRichard Henderson {
1986b016486eSRichard Henderson     return (d & (d - 1)) == 0;
1987b016486eSRichard Henderson }
1988b016486eSRichard Henderson 
1989b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
1990b016486eSRichard Henderson {
1991b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
1992b016486eSRichard Henderson         return ctz32(d);
1993b016486eSRichard Henderson     } else {
1994b016486eSRichard Henderson         return ctz64(d);
1995b016486eSRichard Henderson     }
1996b016486eSRichard Henderson }
1997b016486eSRichard Henderson 
19981894f69aSRichard Henderson static void tcg_dump_ops(TCGContext *s, bool have_prefs)
1999c896fe29Sbellard {
2000c896fe29Sbellard     char buf[128];
2001c45cb8bbSRichard Henderson     TCGOp *op;
2002c896fe29Sbellard 
200315fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
2004c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
2005c45cb8bbSRichard Henderson         const TCGOpDef *def;
2006c45cb8bbSRichard Henderson         TCGOpcode c;
2007bdfb460eSRichard Henderson         int col = 0;
2008c45cb8bbSRichard Henderson 
2009c45cb8bbSRichard Henderson         c = op->opc;
2010c896fe29Sbellard         def = &tcg_op_defs[c];
2011c45cb8bbSRichard Henderson 
2012765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
2013b016486eSRichard Henderson             nb_oargs = 0;
201415fa08f8SRichard Henderson             col += qemu_log("\n ----");
20159aef40edSRichard Henderson 
20169aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
20179aef40edSRichard Henderson                 target_ulong a;
20187e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
2019efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
20207e4597d7Sbellard #else
2021efee3746SRichard Henderson                 a = op->args[i];
20227e4597d7Sbellard #endif
2023bdfb460eSRichard Henderson                 col += qemu_log(" " TARGET_FMT_lx, a);
2024eeacee4dSBlue Swirl             }
20257e4597d7Sbellard         } else if (c == INDEX_op_call) {
2026c896fe29Sbellard             /* variable number of arguments */
2027cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2028cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2029c896fe29Sbellard             nb_cargs = def->nb_cargs;
2030b03cce8eSbellard 
2031cf066674SRichard Henderson             /* function name, flags, out args */
2032bdfb460eSRichard Henderson             col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name,
2033efee3746SRichard Henderson                             tcg_find_helper(s, op->args[nb_oargs + nb_iargs]),
2034efee3746SRichard Henderson                             op->args[nb_oargs + nb_iargs + 1], nb_oargs);
2035b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
203643439139SRichard Henderson                 col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf),
2037efee3746SRichard Henderson                                                        op->args[i]));
2038b03cce8eSbellard             }
2039cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
2040efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
2041cf066674SRichard Henderson                 const char *t = "<dummy>";
2042cf066674SRichard Henderson                 if (arg != TCG_CALL_DUMMY_ARG) {
204343439139SRichard Henderson                     t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
2044b03cce8eSbellard                 }
2045bdfb460eSRichard Henderson                 col += qemu_log(",%s", t);
2046e8996ee0Sbellard             }
2047b03cce8eSbellard         } else {
2048bdfb460eSRichard Henderson             col += qemu_log(" %s ", def->name);
2049c45cb8bbSRichard Henderson 
2050c896fe29Sbellard             nb_oargs = def->nb_oargs;
2051c896fe29Sbellard             nb_iargs = def->nb_iargs;
2052c896fe29Sbellard             nb_cargs = def->nb_cargs;
2053c896fe29Sbellard 
2054d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
2055d2fd745fSRichard Henderson                 col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op),
2056d2fd745fSRichard Henderson                                 8 << TCGOP_VECE(op));
2057d2fd745fSRichard Henderson             }
2058d2fd745fSRichard Henderson 
2059c896fe29Sbellard             k = 0;
2060c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
2061eeacee4dSBlue Swirl                 if (k != 0) {
2062bdfb460eSRichard Henderson                     col += qemu_log(",");
2063eeacee4dSBlue Swirl                 }
206443439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2065efee3746SRichard Henderson                                                       op->args[k++]));
2066c896fe29Sbellard             }
2067c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
2068eeacee4dSBlue Swirl                 if (k != 0) {
2069bdfb460eSRichard Henderson                     col += qemu_log(",");
2070eeacee4dSBlue Swirl                 }
207143439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2072efee3746SRichard Henderson                                                       op->args[k++]));
2073c896fe29Sbellard             }
2074be210acbSRichard Henderson             switch (c) {
2075be210acbSRichard Henderson             case INDEX_op_brcond_i32:
2076ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
2077ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
2078be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
2079be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
2080ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
2081be210acbSRichard Henderson             case INDEX_op_setcond_i64:
2082ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
2083212be173SRichard Henderson             case INDEX_op_cmp_vec:
2084f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
2085efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
2086efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
2087efee3746SRichard Henderson                     col += qemu_log(",%s", cond_name[op->args[k++]]);
2088eeacee4dSBlue Swirl                 } else {
2089efee3746SRichard Henderson                     col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]);
2090eeacee4dSBlue Swirl                 }
2091f48f3edeSblueswir1                 i = 1;
2092be210acbSRichard Henderson                 break;
2093f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
2094f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
209507ce0b05SRichard Henderson             case INDEX_op_qemu_st8_i32:
2096f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
2097f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
209859227d5dSRichard Henderson                 {
2099efee3746SRichard Henderson                     TCGMemOpIdx oi = op->args[k++];
210014776ab5STony Nguyen                     MemOp op = get_memop(oi);
210159227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
210259227d5dSRichard Henderson 
210359c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
2104bdfb460eSRichard Henderson                         col += qemu_log(",$0x%x,%u", op, ix);
210559c4b7e8SRichard Henderson                     } else {
21061f00b27fSSergey Sorokin                         const char *s_al, *s_op;
21071f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
210859c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
2109bdfb460eSRichard Henderson                         col += qemu_log(",%s%s,%u", s_al, s_op, ix);
2110f713d6adSRichard Henderson                     }
2111f713d6adSRichard Henderson                     i = 1;
211259227d5dSRichard Henderson                 }
2113f713d6adSRichard Henderson                 break;
2114be210acbSRichard Henderson             default:
2115f48f3edeSblueswir1                 i = 0;
2116be210acbSRichard Henderson                 break;
2117be210acbSRichard Henderson             }
211851e3972cSRichard Henderson             switch (c) {
211951e3972cSRichard Henderson             case INDEX_op_set_label:
212051e3972cSRichard Henderson             case INDEX_op_br:
212151e3972cSRichard Henderson             case INDEX_op_brcond_i32:
212251e3972cSRichard Henderson             case INDEX_op_brcond_i64:
212351e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2124efee3746SRichard Henderson                 col += qemu_log("%s$L%d", k ? "," : "",
2125efee3746SRichard Henderson                                 arg_label(op->args[k])->id);
212651e3972cSRichard Henderson                 i++, k++;
212751e3972cSRichard Henderson                 break;
212851e3972cSRichard Henderson             default:
212951e3972cSRichard Henderson                 break;
2130eeacee4dSBlue Swirl             }
213151e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
2132efee3746SRichard Henderson                 col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]);
2133bdfb460eSRichard Henderson             }
2134bdfb460eSRichard Henderson         }
2135bdfb460eSRichard Henderson 
21361894f69aSRichard Henderson         if (have_prefs || op->life) {
21377606488cSRobert Foley 
21387606488cSRobert Foley             QemuLogFile *logfile;
21397606488cSRobert Foley 
21407606488cSRobert Foley             rcu_read_lock();
2141d73415a3SStefan Hajnoczi             logfile = qatomic_rcu_read(&qemu_logfile);
21427606488cSRobert Foley             if (logfile) {
21431894f69aSRichard Henderson                 for (; col < 40; ++col) {
21447606488cSRobert Foley                     putc(' ', logfile->fd);
2145bdfb460eSRichard Henderson                 }
21461894f69aSRichard Henderson             }
21477606488cSRobert Foley             rcu_read_unlock();
21487606488cSRobert Foley         }
21491894f69aSRichard Henderson 
21501894f69aSRichard Henderson         if (op->life) {
21511894f69aSRichard Henderson             unsigned life = op->life;
2152bdfb460eSRichard Henderson 
2153bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
2154bdfb460eSRichard Henderson                 qemu_log("  sync:");
2155bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
2156bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
2157bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2158bdfb460eSRichard Henderson                     }
2159bdfb460eSRichard Henderson                 }
2160bdfb460eSRichard Henderson             }
2161bdfb460eSRichard Henderson             life /= DEAD_ARG;
2162bdfb460eSRichard Henderson             if (life) {
2163bdfb460eSRichard Henderson                 qemu_log("  dead:");
2164bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
2165bdfb460eSRichard Henderson                     if (life & 1) {
2166bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2167bdfb460eSRichard Henderson                     }
2168bdfb460eSRichard Henderson                 }
2169c896fe29Sbellard             }
2170b03cce8eSbellard         }
21711894f69aSRichard Henderson 
21721894f69aSRichard Henderson         if (have_prefs) {
21731894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
21741894f69aSRichard Henderson                 TCGRegSet set = op->output_pref[i];
21751894f69aSRichard Henderson 
21761894f69aSRichard Henderson                 if (i == 0) {
21771894f69aSRichard Henderson                     qemu_log("  pref=");
21781894f69aSRichard Henderson                 } else {
21791894f69aSRichard Henderson                     qemu_log(",");
21801894f69aSRichard Henderson                 }
21811894f69aSRichard Henderson                 if (set == 0) {
21821894f69aSRichard Henderson                     qemu_log("none");
21831894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
21841894f69aSRichard Henderson                     qemu_log("all");
21851894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
21861894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
21871894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
21881894f69aSRichard Henderson                     qemu_log("%s", tcg_target_reg_names[reg]);
21891894f69aSRichard Henderson #endif
21901894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
21911894f69aSRichard Henderson                     qemu_log("%#x", (uint32_t)set);
21921894f69aSRichard Henderson                 } else {
21931894f69aSRichard Henderson                     qemu_log("%#" PRIx64, (uint64_t)set);
21941894f69aSRichard Henderson                 }
21951894f69aSRichard Henderson             }
21961894f69aSRichard Henderson         }
21971894f69aSRichard Henderson 
2198eeacee4dSBlue Swirl         qemu_log("\n");
2199c896fe29Sbellard     }
2200c896fe29Sbellard }
2201c896fe29Sbellard 
2202c896fe29Sbellard /* we give more priority to constraints with less registers */
2203c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2204c896fe29Sbellard {
220574a11790SRichard Henderson     const TCGArgConstraint *arg_ct = &def->args_ct[k];
220674a11790SRichard Henderson     int n;
2207c896fe29Sbellard 
2208bc2b17e6SRichard Henderson     if (arg_ct->oalias) {
2209c896fe29Sbellard         /* an alias is equivalent to a single register */
2210c896fe29Sbellard         n = 1;
2211c896fe29Sbellard     } else {
221274a11790SRichard Henderson         n = ctpop64(arg_ct->regs);
2213c896fe29Sbellard     }
2214c896fe29Sbellard     return TCG_TARGET_NB_REGS - n + 1;
2215c896fe29Sbellard }
2216c896fe29Sbellard 
2217c896fe29Sbellard /* sort from highest priority to lowest */
2218c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2219c896fe29Sbellard {
222066792f90SRichard Henderson     int i, j;
222166792f90SRichard Henderson     TCGArgConstraint *a = def->args_ct;
2222c896fe29Sbellard 
222366792f90SRichard Henderson     for (i = 0; i < n; i++) {
222466792f90SRichard Henderson         a[start + i].sort_index = start + i;
222566792f90SRichard Henderson     }
222666792f90SRichard Henderson     if (n <= 1) {
2227c896fe29Sbellard         return;
222866792f90SRichard Henderson     }
2229c896fe29Sbellard     for (i = 0; i < n - 1; i++) {
2230c896fe29Sbellard         for (j = i + 1; j < n; j++) {
223166792f90SRichard Henderson             int p1 = get_constraint_priority(def, a[start + i].sort_index);
223266792f90SRichard Henderson             int p2 = get_constraint_priority(def, a[start + j].sort_index);
2233c896fe29Sbellard             if (p1 < p2) {
223466792f90SRichard Henderson                 int tmp = a[start + i].sort_index;
223566792f90SRichard Henderson                 a[start + i].sort_index = a[start + j].sort_index;
223666792f90SRichard Henderson                 a[start + j].sort_index = tmp;
2237c896fe29Sbellard             }
2238c896fe29Sbellard         }
2239c896fe29Sbellard     }
2240c896fe29Sbellard }
2241c896fe29Sbellard 
2242f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2243c896fe29Sbellard {
2244a9751609SRichard Henderson     TCGOpcode op;
2245c896fe29Sbellard 
2246f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
2247f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
2248f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
2249069ea736SRichard Henderson         TCGType type;
2250069ea736SRichard Henderson         int i, nb_args;
2251f69d277eSRichard Henderson 
2252f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
2253f69d277eSRichard Henderson             continue;
2254f69d277eSRichard Henderson         }
2255f69d277eSRichard Henderson 
2256c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
2257f69d277eSRichard Henderson         if (nb_args == 0) {
2258f69d277eSRichard Henderson             continue;
2259f69d277eSRichard Henderson         }
2260f69d277eSRichard Henderson 
2261f69d277eSRichard Henderson         tdefs = tcg_target_op_def(op);
2262f69d277eSRichard Henderson         /* Missing TCGTargetOpDef entry. */
2263f69d277eSRichard Henderson         tcg_debug_assert(tdefs != NULL);
2264f69d277eSRichard Henderson 
2265069ea736SRichard Henderson         type = (def->flags & TCG_OPF_64BIT ? TCG_TYPE_I64 : TCG_TYPE_I32);
2266c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2267f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
2268f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2269eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2270f69d277eSRichard Henderson 
227117280ff4SRichard Henderson             while (*ct_str != '\0') {
227217280ff4SRichard Henderson                 switch(*ct_str) {
227317280ff4SRichard Henderson                 case '0' ... '9':
227417280ff4SRichard Henderson                     {
227517280ff4SRichard Henderson                         int oarg = *ct_str - '0';
227617280ff4SRichard Henderson                         tcg_debug_assert(ct_str == tdefs->args_ct_str[i]);
2277eabb7b91SAurelien Jarno                         tcg_debug_assert(oarg < def->nb_oargs);
227874a11790SRichard Henderson                         tcg_debug_assert(def->args_ct[oarg].regs != 0);
2279c896fe29Sbellard                         def->args_ct[i] = def->args_ct[oarg];
2280bc2b17e6SRichard Henderson                         /* The output sets oalias.  */
2281bc2b17e6SRichard Henderson                         def->args_ct[oarg].oalias = true;
22825ff9d6a4Sbellard                         def->args_ct[oarg].alias_index = i;
2283bc2b17e6SRichard Henderson                         /* The input sets ialias. */
2284bc2b17e6SRichard Henderson                         def->args_ct[i].ialias = true;
22855ff9d6a4Sbellard                         def->args_ct[i].alias_index = oarg;
228617280ff4SRichard Henderson                     }
228717280ff4SRichard Henderson                     ct_str++;
2288c896fe29Sbellard                     break;
228982790a87SRichard Henderson                 case '&':
2290bc2b17e6SRichard Henderson                     def->args_ct[i].newreg = true;
229182790a87SRichard Henderson                     ct_str++;
229282790a87SRichard Henderson                     break;
2293c896fe29Sbellard                 case 'i':
2294c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2295c896fe29Sbellard                     ct_str++;
2296c896fe29Sbellard                     break;
2297c896fe29Sbellard                 default:
2298069ea736SRichard Henderson                     ct_str = target_parse_constraint(&def->args_ct[i],
2299069ea736SRichard Henderson                                                      ct_str, type);
2300f69d277eSRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2301069ea736SRichard Henderson                     tcg_debug_assert(ct_str != NULL);
2302c896fe29Sbellard                 }
2303c896fe29Sbellard             }
2304c896fe29Sbellard         }
2305c896fe29Sbellard 
2306c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2307eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2308c68aaa18SStefan Weil 
2309c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
2310c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
2311c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
2312c896fe29Sbellard     }
2313c896fe29Sbellard }
2314c896fe29Sbellard 
23150c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
23160c627cdcSRichard Henderson {
2317d88a117eSRichard Henderson     TCGLabel *label;
2318d88a117eSRichard Henderson 
2319d88a117eSRichard Henderson     switch (op->opc) {
2320d88a117eSRichard Henderson     case INDEX_op_br:
2321d88a117eSRichard Henderson         label = arg_label(op->args[0]);
2322d88a117eSRichard Henderson         label->refs--;
2323d88a117eSRichard Henderson         break;
2324d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
2325d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
2326d88a117eSRichard Henderson         label = arg_label(op->args[3]);
2327d88a117eSRichard Henderson         label->refs--;
2328d88a117eSRichard Henderson         break;
2329d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
2330d88a117eSRichard Henderson         label = arg_label(op->args[5]);
2331d88a117eSRichard Henderson         label->refs--;
2332d88a117eSRichard Henderson         break;
2333d88a117eSRichard Henderson     default:
2334d88a117eSRichard Henderson         break;
2335d88a117eSRichard Henderson     }
2336d88a117eSRichard Henderson 
233715fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
233815fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
2339abebf925SRichard Henderson     s->nb_ops--;
23400c627cdcSRichard Henderson 
23410c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
2342d73415a3SStefan Hajnoczi     qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
23430c627cdcSRichard Henderson #endif
23440c627cdcSRichard Henderson }
23450c627cdcSRichard Henderson 
234615fa08f8SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc)
234715fa08f8SRichard Henderson {
234815fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
234915fa08f8SRichard Henderson     TCGOp *op;
235015fa08f8SRichard Henderson 
235115fa08f8SRichard Henderson     if (likely(QTAILQ_EMPTY(&s->free_ops))) {
235215fa08f8SRichard Henderson         op = tcg_malloc(sizeof(TCGOp));
235315fa08f8SRichard Henderson     } else {
235415fa08f8SRichard Henderson         op = QTAILQ_FIRST(&s->free_ops);
235515fa08f8SRichard Henderson         QTAILQ_REMOVE(&s->free_ops, op, link);
235615fa08f8SRichard Henderson     }
235715fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
235815fa08f8SRichard Henderson     op->opc = opc;
2359abebf925SRichard Henderson     s->nb_ops++;
236015fa08f8SRichard Henderson 
236115fa08f8SRichard Henderson     return op;
236215fa08f8SRichard Henderson }
236315fa08f8SRichard Henderson 
236415fa08f8SRichard Henderson TCGOp *tcg_emit_op(TCGOpcode opc)
236515fa08f8SRichard Henderson {
236615fa08f8SRichard Henderson     TCGOp *op = tcg_op_alloc(opc);
236715fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
236815fa08f8SRichard Henderson     return op;
236915fa08f8SRichard Henderson }
237015fa08f8SRichard Henderson 
2371ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
23725a18407fSRichard Henderson {
237315fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
237415fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
23755a18407fSRichard Henderson     return new_op;
23765a18407fSRichard Henderson }
23775a18407fSRichard Henderson 
2378ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
23795a18407fSRichard Henderson {
238015fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
238115fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
23825a18407fSRichard Henderson     return new_op;
23835a18407fSRichard Henderson }
23845a18407fSRichard Henderson 
2385b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
2386b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s)
2387b4fc67c7SRichard Henderson {
2388b4fc67c7SRichard Henderson     TCGOp *op, *op_next;
2389b4fc67c7SRichard Henderson     bool dead = false;
2390b4fc67c7SRichard Henderson 
2391b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
2392b4fc67c7SRichard Henderson         bool remove = dead;
2393b4fc67c7SRichard Henderson         TCGLabel *label;
2394b4fc67c7SRichard Henderson         int call_flags;
2395b4fc67c7SRichard Henderson 
2396b4fc67c7SRichard Henderson         switch (op->opc) {
2397b4fc67c7SRichard Henderson         case INDEX_op_set_label:
2398b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
2399b4fc67c7SRichard Henderson             if (label->refs == 0) {
2400b4fc67c7SRichard Henderson                 /*
2401b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
2402b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
2403b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
2404b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
2405b4fc67c7SRichard Henderson                  * little to be gained by iterating.
2406b4fc67c7SRichard Henderson                  */
2407b4fc67c7SRichard Henderson                 remove = true;
2408b4fc67c7SRichard Henderson             } else {
2409b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
2410b4fc67c7SRichard Henderson                 dead = false;
2411b4fc67c7SRichard Henderson                 remove = false;
2412b4fc67c7SRichard Henderson 
2413b4fc67c7SRichard Henderson                 /*
2414b4fc67c7SRichard Henderson                  * Optimization can fold conditional branches to unconditional.
2415b4fc67c7SRichard Henderson                  * If we find a label with one reference which is preceded by
2416b4fc67c7SRichard Henderson                  * an unconditional branch to it, remove both.  This needed to
2417b4fc67c7SRichard Henderson                  * wait until the dead code in between them was removed.
2418b4fc67c7SRichard Henderson                  */
2419b4fc67c7SRichard Henderson                 if (label->refs == 1) {
2420eae3eb3eSPaolo Bonzini                     TCGOp *op_prev = QTAILQ_PREV(op, link);
2421b4fc67c7SRichard Henderson                     if (op_prev->opc == INDEX_op_br &&
2422b4fc67c7SRichard Henderson                         label == arg_label(op_prev->args[0])) {
2423b4fc67c7SRichard Henderson                         tcg_op_remove(s, op_prev);
2424b4fc67c7SRichard Henderson                         remove = true;
2425b4fc67c7SRichard Henderson                     }
2426b4fc67c7SRichard Henderson                 }
2427b4fc67c7SRichard Henderson             }
2428b4fc67c7SRichard Henderson             break;
2429b4fc67c7SRichard Henderson 
2430b4fc67c7SRichard Henderson         case INDEX_op_br:
2431b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
2432b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
2433b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
2434b4fc67c7SRichard Henderson             dead = true;
2435b4fc67c7SRichard Henderson             break;
2436b4fc67c7SRichard Henderson 
2437b4fc67c7SRichard Henderson         case INDEX_op_call:
2438b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
2439b4fc67c7SRichard Henderson             call_flags = op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1];
2440b4fc67c7SRichard Henderson             if (call_flags & TCG_CALL_NO_RETURN) {
2441b4fc67c7SRichard Henderson                 dead = true;
2442b4fc67c7SRichard Henderson             }
2443b4fc67c7SRichard Henderson             break;
2444b4fc67c7SRichard Henderson 
2445b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
2446b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
2447b4fc67c7SRichard Henderson             remove = false;
2448b4fc67c7SRichard Henderson             break;
2449b4fc67c7SRichard Henderson 
2450b4fc67c7SRichard Henderson         default:
2451b4fc67c7SRichard Henderson             break;
2452b4fc67c7SRichard Henderson         }
2453b4fc67c7SRichard Henderson 
2454b4fc67c7SRichard Henderson         if (remove) {
2455b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
2456b4fc67c7SRichard Henderson         }
2457b4fc67c7SRichard Henderson     }
2458b4fc67c7SRichard Henderson }
2459b4fc67c7SRichard Henderson 
2460c70fbf0aSRichard Henderson #define TS_DEAD  1
2461c70fbf0aSRichard Henderson #define TS_MEM   2
2462c70fbf0aSRichard Henderson 
24635a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
24645a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
24655a18407fSRichard Henderson 
246625f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
246725f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
246825f49c5fSRichard Henderson {
246925f49c5fSRichard Henderson     return ts->state_ptr;
247025f49c5fSRichard Henderson }
247125f49c5fSRichard Henderson 
247225f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
247325f49c5fSRichard Henderson  * maximal regset for its type.
247425f49c5fSRichard Henderson  */
247525f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
247625f49c5fSRichard Henderson {
247725f49c5fSRichard Henderson     *la_temp_pref(ts)
247825f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
247925f49c5fSRichard Henderson }
248025f49c5fSRichard Henderson 
24819c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
24829c43b68dSAurelien Jarno    should be in memory. */
24832616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
2484c896fe29Sbellard {
2485b83eabeaSRichard Henderson     int i;
2486b83eabeaSRichard Henderson 
2487b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2488b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
248925f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2490b83eabeaSRichard Henderson     }
2491b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2492b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
249325f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2494b83eabeaSRichard Henderson     }
2495c896fe29Sbellard }
2496c896fe29Sbellard 
24979c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
24989c43b68dSAurelien Jarno    and local temps should be in memory. */
24992616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
2500641d5fbeSbellard {
2501b83eabeaSRichard Henderson     int i;
2502641d5fbeSbellard 
2503b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2504b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
250525f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2506c70fbf0aSRichard Henderson     }
2507b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2508b83eabeaSRichard Henderson         s->temps[i].state = (s->temps[i].temp_local
2509b83eabeaSRichard Henderson                              ? TS_DEAD | TS_MEM
2510b83eabeaSRichard Henderson                              : TS_DEAD);
251125f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2512641d5fbeSbellard     }
2513641d5fbeSbellard }
2514641d5fbeSbellard 
2515f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
2516f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
2517f65a061cSRichard Henderson {
2518f65a061cSRichard Henderson     int i;
2519f65a061cSRichard Henderson 
2520f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
252125f49c5fSRichard Henderson         int state = s->temps[i].state;
252225f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
252325f49c5fSRichard Henderson         if (state == TS_DEAD) {
252425f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
252525f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
252625f49c5fSRichard Henderson         }
2527f65a061cSRichard Henderson     }
2528f65a061cSRichard Henderson }
2529f65a061cSRichard Henderson 
2530b4cb76e6SRichard Henderson /*
2531b4cb76e6SRichard Henderson  * liveness analysis: conditional branch: all temps are dead,
2532b4cb76e6SRichard Henderson  * globals and local temps should be synced.
2533b4cb76e6SRichard Henderson  */
2534b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
2535b4cb76e6SRichard Henderson {
2536b4cb76e6SRichard Henderson     la_global_sync(s, ng);
2537b4cb76e6SRichard Henderson 
2538b4cb76e6SRichard Henderson     for (int i = ng; i < nt; ++i) {
2539b4cb76e6SRichard Henderson         if (s->temps[i].temp_local) {
2540b4cb76e6SRichard Henderson             int state = s->temps[i].state;
2541b4cb76e6SRichard Henderson             s->temps[i].state = state | TS_MEM;
2542b4cb76e6SRichard Henderson             if (state != TS_DEAD) {
2543b4cb76e6SRichard Henderson                 continue;
2544b4cb76e6SRichard Henderson             }
2545b4cb76e6SRichard Henderson         } else {
2546b4cb76e6SRichard Henderson             s->temps[i].state = TS_DEAD;
2547b4cb76e6SRichard Henderson         }
2548b4cb76e6SRichard Henderson         la_reset_pref(&s->temps[i]);
2549b4cb76e6SRichard Henderson     }
2550b4cb76e6SRichard Henderson }
2551b4cb76e6SRichard Henderson 
2552f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
2553f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
2554f65a061cSRichard Henderson {
2555f65a061cSRichard Henderson     int i;
2556f65a061cSRichard Henderson 
2557f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
2558f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
255925f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
256025f49c5fSRichard Henderson     }
256125f49c5fSRichard Henderson }
256225f49c5fSRichard Henderson 
256325f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
256425f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
256525f49c5fSRichard Henderson {
256625f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
256725f49c5fSRichard Henderson     int i;
256825f49c5fSRichard Henderson 
256925f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
257025f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
257125f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
257225f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
257325f49c5fSRichard Henderson             TCGRegSet set = *pset;
257425f49c5fSRichard Henderson 
257525f49c5fSRichard Henderson             set &= mask;
257625f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
257725f49c5fSRichard Henderson             if (set == 0) {
257825f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
257925f49c5fSRichard Henderson             }
258025f49c5fSRichard Henderson             *pset = set;
258125f49c5fSRichard Henderson         }
2582f65a061cSRichard Henderson     }
2583f65a061cSRichard Henderson }
2584f65a061cSRichard Henderson 
2585a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
2586c896fe29Sbellard    given input arguments is dead. Instructions updating dead
2587c896fe29Sbellard    temporaries are removed. */
2588b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s)
2589c896fe29Sbellard {
2590c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
25912616c808SRichard Henderson     int nb_temps = s->nb_temps;
259215fa08f8SRichard Henderson     TCGOp *op, *op_prev;
259325f49c5fSRichard Henderson     TCGRegSet *prefs;
259425f49c5fSRichard Henderson     int i;
259525f49c5fSRichard Henderson 
259625f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
259725f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
259825f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
259925f49c5fSRichard Henderson     }
2600c896fe29Sbellard 
2601ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
26022616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
2603c896fe29Sbellard 
2604eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
260525f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
2606c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
2607c45cb8bbSRichard Henderson         bool have_opc_new2;
2608a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
260925f49c5fSRichard Henderson         TCGTemp *ts;
2610c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2611c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2612c45cb8bbSRichard Henderson 
2613c45cb8bbSRichard Henderson         switch (opc) {
2614c896fe29Sbellard         case INDEX_op_call:
2615c6e113f5Sbellard             {
2616c6e113f5Sbellard                 int call_flags;
261725f49c5fSRichard Henderson                 int nb_call_regs;
2618c6e113f5Sbellard 
2619cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
2620cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
2621efee3746SRichard Henderson                 call_flags = op->args[nb_oargs + nb_iargs + 1];
2622c6e113f5Sbellard 
2623c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
262478505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
2625c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
262625f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
262725f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
2628c6e113f5Sbellard                             goto do_not_remove_call;
2629c6e113f5Sbellard                         }
26309c43b68dSAurelien Jarno                     }
2631c45cb8bbSRichard Henderson                     goto do_remove;
2632152c35aaSRichard Henderson                 }
2633c6e113f5Sbellard             do_not_remove_call:
2634c896fe29Sbellard 
263525f49c5fSRichard Henderson                 /* Output args are dead.  */
2636c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
263725f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
263825f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
2639a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
26406b64b624SAurelien Jarno                     }
264125f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
2642a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
26439c43b68dSAurelien Jarno                     }
264425f49c5fSRichard Henderson                     ts->state = TS_DEAD;
264525f49c5fSRichard Henderson                     la_reset_pref(ts);
264625f49c5fSRichard Henderson 
264725f49c5fSRichard Henderson                     /* Not used -- it will be tcg_target_call_oarg_regs[i].  */
264825f49c5fSRichard Henderson                     op->output_pref[i] = 0;
2649c896fe29Sbellard                 }
2650c896fe29Sbellard 
265178505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
265278505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
2653f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
2654c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
2655f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
2656b9c18f56Saurel32                 }
2657c896fe29Sbellard 
265825f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
2659866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
266025f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
266125f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
2662a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
2663c896fe29Sbellard                     }
2664c896fe29Sbellard                 }
266525f49c5fSRichard Henderson 
266625f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
266725f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
266825f49c5fSRichard Henderson 
266925f49c5fSRichard Henderson                 nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
267025f49c5fSRichard Henderson 
267125f49c5fSRichard Henderson                 /* Input arguments are live for preceding opcodes.  */
267225f49c5fSRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
267325f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
267425f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
267525f49c5fSRichard Henderson                         /* For those arguments that die, and will be allocated
267625f49c5fSRichard Henderson                          * in registers, clear the register set for that arg,
267725f49c5fSRichard Henderson                          * to be filled in below.  For args that will be on
267825f49c5fSRichard Henderson                          * the stack, reset to any available reg.
267925f49c5fSRichard Henderson                          */
268025f49c5fSRichard Henderson                         *la_temp_pref(ts)
268125f49c5fSRichard Henderson                             = (i < nb_call_regs ? 0 :
268225f49c5fSRichard Henderson                                tcg_target_available_regs[ts->type]);
268325f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
268425f49c5fSRichard Henderson                     }
268525f49c5fSRichard Henderson                 }
268625f49c5fSRichard Henderson 
268725f49c5fSRichard Henderson                 /* For each input argument, add its input register to prefs.
268825f49c5fSRichard Henderson                    If a temp is used once, this produces a single set bit.  */
268925f49c5fSRichard Henderson                 for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) {
269025f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
269125f49c5fSRichard Henderson                     if (ts) {
269225f49c5fSRichard Henderson                         tcg_regset_set_reg(*la_temp_pref(ts),
269325f49c5fSRichard Henderson                                            tcg_target_call_iarg_regs[i]);
2694c70fbf0aSRichard Henderson                     }
2695c19f47bfSAurelien Jarno                 }
2696c6e113f5Sbellard             }
2697c896fe29Sbellard             break;
2698765b842aSRichard Henderson         case INDEX_op_insn_start:
2699c896fe29Sbellard             break;
27005ff9d6a4Sbellard         case INDEX_op_discard:
27015ff9d6a4Sbellard             /* mark the temporary as dead */
270225f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
270325f49c5fSRichard Henderson             ts->state = TS_DEAD;
270425f49c5fSRichard Henderson             la_reset_pref(ts);
27055ff9d6a4Sbellard             break;
27061305c451SRichard Henderson 
27071305c451SRichard Henderson         case INDEX_op_add2_i32:
2708c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
2709f1fae40cSRichard Henderson             goto do_addsub2;
27101305c451SRichard Henderson         case INDEX_op_sub2_i32:
2711c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
2712f1fae40cSRichard Henderson             goto do_addsub2;
2713f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
2714c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
2715f1fae40cSRichard Henderson             goto do_addsub2;
2716f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
2717c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
2718f1fae40cSRichard Henderson         do_addsub2:
27191305c451SRichard Henderson             nb_iargs = 4;
27201305c451SRichard Henderson             nb_oargs = 2;
27211305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
27221305c451SRichard Henderson                the low part.  The result can be optimized to a simple
27231305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
27241305c451SRichard Henderson                cpu mode is set to 32 bit.  */
2725b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2726b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
27271305c451SRichard Henderson                     goto do_remove;
27281305c451SRichard Henderson                 }
2729c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
2730c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
2731c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2732efee3746SRichard Henderson                 op->args[1] = op->args[2];
2733efee3746SRichard Henderson                 op->args[2] = op->args[4];
27341305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
27351305c451SRichard Henderson                 nb_iargs = 2;
27361305c451SRichard Henderson                 nb_oargs = 1;
27371305c451SRichard Henderson             }
27381305c451SRichard Henderson             goto do_not_remove;
27391305c451SRichard Henderson 
27401414968aSRichard Henderson         case INDEX_op_mulu2_i32:
2741c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2742c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
2743c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
274403271524SRichard Henderson             goto do_mul2;
2745f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
2746c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2747c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
2748c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
2749f1fae40cSRichard Henderson             goto do_mul2;
2750f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
2751c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2752c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
2753c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
275403271524SRichard Henderson             goto do_mul2;
2755f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
2756c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2757c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
2758c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
275903271524SRichard Henderson             goto do_mul2;
2760f1fae40cSRichard Henderson         do_mul2:
27611414968aSRichard Henderson             nb_iargs = 2;
27621414968aSRichard Henderson             nb_oargs = 2;
2763b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2764b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
276503271524SRichard Henderson                     /* Both parts of the operation are dead.  */
27661414968aSRichard Henderson                     goto do_remove;
27671414968aSRichard Henderson                 }
276803271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
2769c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2770efee3746SRichard Henderson                 op->args[1] = op->args[2];
2771efee3746SRichard Henderson                 op->args[2] = op->args[3];
2772b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
277303271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
2774c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
2775efee3746SRichard Henderson                 op->args[0] = op->args[1];
2776efee3746SRichard Henderson                 op->args[1] = op->args[2];
2777efee3746SRichard Henderson                 op->args[2] = op->args[3];
277803271524SRichard Henderson             } else {
277903271524SRichard Henderson                 goto do_not_remove;
278003271524SRichard Henderson             }
278103271524SRichard Henderson             /* Mark the single-word operation live.  */
27821414968aSRichard Henderson             nb_oargs = 1;
27831414968aSRichard Henderson             goto do_not_remove;
27841414968aSRichard Henderson 
2785c896fe29Sbellard         default:
27861305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
2787c896fe29Sbellard             nb_iargs = def->nb_iargs;
2788c896fe29Sbellard             nb_oargs = def->nb_oargs;
2789c896fe29Sbellard 
2790c896fe29Sbellard             /* Test if the operation can be removed because all
27915ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
27925ff9d6a4Sbellard                implies side effects */
27935ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
2794c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
2795b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
2796c896fe29Sbellard                         goto do_not_remove;
2797c896fe29Sbellard                     }
27989c43b68dSAurelien Jarno                 }
2799152c35aaSRichard Henderson                 goto do_remove;
2800152c35aaSRichard Henderson             }
2801152c35aaSRichard Henderson             goto do_not_remove;
2802152c35aaSRichard Henderson 
28031305c451SRichard Henderson         do_remove:
28040c627cdcSRichard Henderson             tcg_op_remove(s, op);
2805152c35aaSRichard Henderson             break;
2806152c35aaSRichard Henderson 
2807c896fe29Sbellard         do_not_remove:
2808c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
280925f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
281025f49c5fSRichard Henderson 
281125f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
281225f49c5fSRichard Henderson                 op->output_pref[i] = *la_temp_pref(ts);
281325f49c5fSRichard Henderson 
281425f49c5fSRichard Henderson                 /* Output args are dead.  */
281525f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2816a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
28176b64b624SAurelien Jarno                 }
281825f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
2819a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
28209c43b68dSAurelien Jarno                 }
282125f49c5fSRichard Henderson                 ts->state = TS_DEAD;
282225f49c5fSRichard Henderson                 la_reset_pref(ts);
2823c896fe29Sbellard             }
2824c896fe29Sbellard 
282525f49c5fSRichard Henderson             /* If end of basic block, update.  */
2826ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
2827ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
2828b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_COND_BRANCH) {
2829b4cb76e6SRichard Henderson                 la_bb_sync(s, nb_globals, nb_temps);
2830ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
28312616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
28323d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
2833f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
283425f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
283525f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
283625f49c5fSRichard Henderson                 }
2837c896fe29Sbellard             }
2838c896fe29Sbellard 
283925f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
2840866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
284125f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
284225f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2843a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
2844c896fe29Sbellard                 }
2845c19f47bfSAurelien Jarno             }
284625f49c5fSRichard Henderson 
284725f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
2848c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
284925f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
285025f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
285125f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
285225f49c5fSRichard Henderson                        all regs for the type.  */
285325f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
285425f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
285525f49c5fSRichard Henderson                 }
285625f49c5fSRichard Henderson             }
285725f49c5fSRichard Henderson 
285825f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
285925f49c5fSRichard Henderson             switch (opc) {
286025f49c5fSRichard Henderson             case INDEX_op_mov_i32:
286125f49c5fSRichard Henderson             case INDEX_op_mov_i64:
286225f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
286325f49c5fSRichard Henderson                    have proper constraints.  That said, special case
286425f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
286525f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
286625f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
286725f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
286825f49c5fSRichard Henderson                 }
286925f49c5fSRichard Henderson                 break;
287025f49c5fSRichard Henderson 
287125f49c5fSRichard Henderson             default:
287225f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
287325f49c5fSRichard Henderson                     const TCGArgConstraint *ct = &def->args_ct[i];
287425f49c5fSRichard Henderson                     TCGRegSet set, *pset;
287525f49c5fSRichard Henderson 
287625f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
287725f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
287825f49c5fSRichard Henderson                     set = *pset;
287925f49c5fSRichard Henderson 
28809be0d080SRichard Henderson                     set &= ct->regs;
2881bc2b17e6SRichard Henderson                     if (ct->ialias) {
288225f49c5fSRichard Henderson                         set &= op->output_pref[ct->alias_index];
288325f49c5fSRichard Henderson                     }
288425f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
288525f49c5fSRichard Henderson                     if (set == 0) {
28869be0d080SRichard Henderson                         set = ct->regs;
288725f49c5fSRichard Henderson                     }
288825f49c5fSRichard Henderson                     *pset = set;
288925f49c5fSRichard Henderson                 }
289025f49c5fSRichard Henderson                 break;
2891c896fe29Sbellard             }
2892c896fe29Sbellard             break;
2893c896fe29Sbellard         }
2894bee158cbSRichard Henderson         op->life = arg_life;
2895c896fe29Sbellard     }
28961ff0a2c5SEvgeny Voevodin }
2897c896fe29Sbellard 
28985a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
2899b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s)
29005a18407fSRichard Henderson {
29015a18407fSRichard Henderson     int nb_globals = s->nb_globals;
290215fa08f8SRichard Henderson     int nb_temps, i;
29035a18407fSRichard Henderson     bool changes = false;
290415fa08f8SRichard Henderson     TCGOp *op, *op_next;
29055a18407fSRichard Henderson 
29065a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
29075a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
29085a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
29095a18407fSRichard Henderson         if (its->indirect_reg) {
29105a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
29115a18407fSRichard Henderson             dts->type = its->type;
29125a18407fSRichard Henderson             dts->base_type = its->base_type;
2913b83eabeaSRichard Henderson             its->state_ptr = dts;
2914b83eabeaSRichard Henderson         } else {
2915b83eabeaSRichard Henderson             its->state_ptr = NULL;
29165a18407fSRichard Henderson         }
2917b83eabeaSRichard Henderson         /* All globals begin dead.  */
2918b83eabeaSRichard Henderson         its->state = TS_DEAD;
29195a18407fSRichard Henderson     }
2920b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
2921b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
2922b83eabeaSRichard Henderson         its->state_ptr = NULL;
2923b83eabeaSRichard Henderson         its->state = TS_DEAD;
2924b83eabeaSRichard Henderson     }
29255a18407fSRichard Henderson 
292615fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
29275a18407fSRichard Henderson         TCGOpcode opc = op->opc;
29285a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
29295a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
29305a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
2931b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
29325a18407fSRichard Henderson 
29335a18407fSRichard Henderson         if (opc == INDEX_op_call) {
2934cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2935cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2936efee3746SRichard Henderson             call_flags = op->args[nb_oargs + nb_iargs + 1];
29375a18407fSRichard Henderson         } else {
29385a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
29395a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
29405a18407fSRichard Henderson 
29415a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
2942b4cb76e6SRichard Henderson             if (def->flags & TCG_OPF_COND_BRANCH) {
2943b4cb76e6SRichard Henderson                 /* Like reading globals: sync_globals */
2944b4cb76e6SRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
2945b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
29465a18407fSRichard Henderson                 /* Like writing globals: save_globals */
29475a18407fSRichard Henderson                 call_flags = 0;
29485a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
29495a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
29505a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
29515a18407fSRichard Henderson             } else {
29525a18407fSRichard Henderson                 /* No effect on globals.  */
29535a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
29545a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
29555a18407fSRichard Henderson             }
29565a18407fSRichard Henderson         }
29575a18407fSRichard Henderson 
29585a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
29595a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2960b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2961b83eabeaSRichard Henderson             if (arg_ts) {
2962b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
2963b83eabeaSRichard Henderson                 if (dir_ts && arg_ts->state == TS_DEAD) {
2964b83eabeaSRichard Henderson                     TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
29655a18407fSRichard Henderson                                       ? INDEX_op_ld_i32
29665a18407fSRichard Henderson                                       : INDEX_op_ld_i64);
2967ac1043f6SEmilio G. Cota                     TCGOp *lop = tcg_op_insert_before(s, op, lopc);
29685a18407fSRichard Henderson 
2969b83eabeaSRichard Henderson                     lop->args[0] = temp_arg(dir_ts);
2970b83eabeaSRichard Henderson                     lop->args[1] = temp_arg(arg_ts->mem_base);
2971b83eabeaSRichard Henderson                     lop->args[2] = arg_ts->mem_offset;
29725a18407fSRichard Henderson 
29735a18407fSRichard Henderson                     /* Loaded, but synced with memory.  */
2974b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
29755a18407fSRichard Henderson                 }
29765a18407fSRichard Henderson             }
29775a18407fSRichard Henderson         }
29785a18407fSRichard Henderson 
29795a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
29805a18407fSRichard Henderson            No action is required except keeping temp_state up to date
29815a18407fSRichard Henderson            so that we reload when needed.  */
29825a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2983b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2984b83eabeaSRichard Henderson             if (arg_ts) {
2985b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
2986b83eabeaSRichard Henderson                 if (dir_ts) {
2987b83eabeaSRichard Henderson                     op->args[i] = temp_arg(dir_ts);
29885a18407fSRichard Henderson                     changes = true;
29895a18407fSRichard Henderson                     if (IS_DEAD_ARG(i)) {
2990b83eabeaSRichard Henderson                         arg_ts->state = TS_DEAD;
29915a18407fSRichard Henderson                     }
29925a18407fSRichard Henderson                 }
29935a18407fSRichard Henderson             }
29945a18407fSRichard Henderson         }
29955a18407fSRichard Henderson 
29965a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
29975a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
29985a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
29995a18407fSRichard Henderson             /* Nothing to do */
30005a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
30015a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
30025a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
30035a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
3004b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3005b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3006b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
30075a18407fSRichard Henderson             }
30085a18407fSRichard Henderson         } else {
30095a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
30105a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
30115a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
3012b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3013b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3014b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
30155a18407fSRichard Henderson             }
30165a18407fSRichard Henderson         }
30175a18407fSRichard Henderson 
30185a18407fSRichard Henderson         /* Outputs become available.  */
301961f15c48SRichard Henderson         if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) {
302061f15c48SRichard Henderson             arg_ts = arg_temp(op->args[0]);
302161f15c48SRichard Henderson             dir_ts = arg_ts->state_ptr;
302261f15c48SRichard Henderson             if (dir_ts) {
302361f15c48SRichard Henderson                 op->args[0] = temp_arg(dir_ts);
302461f15c48SRichard Henderson                 changes = true;
302561f15c48SRichard Henderson 
302661f15c48SRichard Henderson                 /* The output is now live and modified.  */
302761f15c48SRichard Henderson                 arg_ts->state = 0;
302861f15c48SRichard Henderson 
302961f15c48SRichard Henderson                 if (NEED_SYNC_ARG(0)) {
303061f15c48SRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
303161f15c48SRichard Henderson                                       ? INDEX_op_st_i32
303261f15c48SRichard Henderson                                       : INDEX_op_st_i64);
303361f15c48SRichard Henderson                     TCGOp *sop = tcg_op_insert_after(s, op, sopc);
303461f15c48SRichard Henderson                     TCGTemp *out_ts = dir_ts;
303561f15c48SRichard Henderson 
303661f15c48SRichard Henderson                     if (IS_DEAD_ARG(0)) {
303761f15c48SRichard Henderson                         out_ts = arg_temp(op->args[1]);
303861f15c48SRichard Henderson                         arg_ts->state = TS_DEAD;
303961f15c48SRichard Henderson                         tcg_op_remove(s, op);
304061f15c48SRichard Henderson                     } else {
304161f15c48SRichard Henderson                         arg_ts->state = TS_MEM;
304261f15c48SRichard Henderson                     }
304361f15c48SRichard Henderson 
304461f15c48SRichard Henderson                     sop->args[0] = temp_arg(out_ts);
304561f15c48SRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
304661f15c48SRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
304761f15c48SRichard Henderson                 } else {
304861f15c48SRichard Henderson                     tcg_debug_assert(!IS_DEAD_ARG(0));
304961f15c48SRichard Henderson                 }
305061f15c48SRichard Henderson             }
305161f15c48SRichard Henderson         } else {
30525a18407fSRichard Henderson             for (i = 0; i < nb_oargs; i++) {
3053b83eabeaSRichard Henderson                 arg_ts = arg_temp(op->args[i]);
3054b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3055b83eabeaSRichard Henderson                 if (!dir_ts) {
30565a18407fSRichard Henderson                     continue;
30575a18407fSRichard Henderson                 }
3058b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
30595a18407fSRichard Henderson                 changes = true;
30605a18407fSRichard Henderson 
30615a18407fSRichard Henderson                 /* The output is now live and modified.  */
3062b83eabeaSRichard Henderson                 arg_ts->state = 0;
30635a18407fSRichard Henderson 
30645a18407fSRichard Henderson                 /* Sync outputs upon their last write.  */
30655a18407fSRichard Henderson                 if (NEED_SYNC_ARG(i)) {
3066b83eabeaSRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
30675a18407fSRichard Henderson                                       ? INDEX_op_st_i32
30685a18407fSRichard Henderson                                       : INDEX_op_st_i64);
3069ac1043f6SEmilio G. Cota                     TCGOp *sop = tcg_op_insert_after(s, op, sopc);
30705a18407fSRichard Henderson 
3071b83eabeaSRichard Henderson                     sop->args[0] = temp_arg(dir_ts);
3072b83eabeaSRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
3073b83eabeaSRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
30745a18407fSRichard Henderson 
3075b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
30765a18407fSRichard Henderson                 }
30775a18407fSRichard Henderson                 /* Drop outputs that are dead.  */
30785a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3079b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
30805a18407fSRichard Henderson                 }
30815a18407fSRichard Henderson             }
30825a18407fSRichard Henderson         }
308361f15c48SRichard Henderson     }
30845a18407fSRichard Henderson 
30855a18407fSRichard Henderson     return changes;
30865a18407fSRichard Henderson }
30875a18407fSRichard Henderson 
30888d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
3089c896fe29Sbellard static void dump_regs(TCGContext *s)
3090c896fe29Sbellard {
3091c896fe29Sbellard     TCGTemp *ts;
3092c896fe29Sbellard     int i;
3093c896fe29Sbellard     char buf[64];
3094c896fe29Sbellard 
3095c896fe29Sbellard     for(i = 0; i < s->nb_temps; i++) {
3096c896fe29Sbellard         ts = &s->temps[i];
309743439139SRichard Henderson         printf("  %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3098c896fe29Sbellard         switch(ts->val_type) {
3099c896fe29Sbellard         case TEMP_VAL_REG:
3100c896fe29Sbellard             printf("%s", tcg_target_reg_names[ts->reg]);
3101c896fe29Sbellard             break;
3102c896fe29Sbellard         case TEMP_VAL_MEM:
3103b3a62939SRichard Henderson             printf("%d(%s)", (int)ts->mem_offset,
3104b3a62939SRichard Henderson                    tcg_target_reg_names[ts->mem_base->reg]);
3105c896fe29Sbellard             break;
3106c896fe29Sbellard         case TEMP_VAL_CONST:
3107c896fe29Sbellard             printf("$0x%" TCG_PRIlx, ts->val);
3108c896fe29Sbellard             break;
3109c896fe29Sbellard         case TEMP_VAL_DEAD:
3110c896fe29Sbellard             printf("D");
3111c896fe29Sbellard             break;
3112c896fe29Sbellard         default:
3113c896fe29Sbellard             printf("???");
3114c896fe29Sbellard             break;
3115c896fe29Sbellard         }
3116c896fe29Sbellard         printf("\n");
3117c896fe29Sbellard     }
3118c896fe29Sbellard 
3119c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
3120f8b2f202SRichard Henderson         if (s->reg_to_temp[i] != NULL) {
3121c896fe29Sbellard             printf("%s: %s\n",
3122c896fe29Sbellard                    tcg_target_reg_names[i],
3123f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i]));
3124c896fe29Sbellard         }
3125c896fe29Sbellard     }
3126c896fe29Sbellard }
3127c896fe29Sbellard 
3128c896fe29Sbellard static void check_regs(TCGContext *s)
3129c896fe29Sbellard {
3130869938aeSRichard Henderson     int reg;
3131b6638662SRichard Henderson     int k;
3132c896fe29Sbellard     TCGTemp *ts;
3133c896fe29Sbellard     char buf[64];
3134c896fe29Sbellard 
3135c896fe29Sbellard     for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
3136f8b2f202SRichard Henderson         ts = s->reg_to_temp[reg];
3137f8b2f202SRichard Henderson         if (ts != NULL) {
3138f8b2f202SRichard Henderson             if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) {
3139c896fe29Sbellard                 printf("Inconsistency for register %s:\n",
3140c896fe29Sbellard                        tcg_target_reg_names[reg]);
3141b03cce8eSbellard                 goto fail;
3142c896fe29Sbellard             }
3143c896fe29Sbellard         }
3144c896fe29Sbellard     }
3145c896fe29Sbellard     for (k = 0; k < s->nb_temps; k++) {
3146c896fe29Sbellard         ts = &s->temps[k];
3147f8b2f202SRichard Henderson         if (ts->val_type == TEMP_VAL_REG && !ts->fixed_reg
3148f8b2f202SRichard Henderson             && s->reg_to_temp[ts->reg] != ts) {
3149c896fe29Sbellard             printf("Inconsistency for temp %s:\n",
3150f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3151b03cce8eSbellard         fail:
3152c896fe29Sbellard             printf("reg state:\n");
3153c896fe29Sbellard             dump_regs(s);
3154c896fe29Sbellard             tcg_abort();
3155c896fe29Sbellard         }
3156c896fe29Sbellard     }
3157c896fe29Sbellard }
3158c896fe29Sbellard #endif
3159c896fe29Sbellard 
31602272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
3161c896fe29Sbellard {
31629b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64)
31639b9c37c3SRichard Henderson     /* Sparc64 stack is accessed with offset of 2047 */
3164b591dc59SBlue Swirl     s->current_frame_offset = (s->current_frame_offset +
3165b591dc59SBlue Swirl                                (tcg_target_long)sizeof(tcg_target_long) - 1) &
3166b591dc59SBlue Swirl         ~(sizeof(tcg_target_long) - 1);
3167f44c9960SBlue Swirl #endif
3168b591dc59SBlue Swirl     if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
3169b591dc59SBlue Swirl         s->frame_end) {
31705ff9d6a4Sbellard         tcg_abort();
3171b591dc59SBlue Swirl     }
3172c896fe29Sbellard     ts->mem_offset = s->current_frame_offset;
3173b3a62939SRichard Henderson     ts->mem_base = s->frame_temp;
3174c896fe29Sbellard     ts->mem_allocated = 1;
3175e2c6d1b4SRichard Henderson     s->current_frame_offset += sizeof(tcg_target_long);
3176c896fe29Sbellard }
3177c896fe29Sbellard 
3178b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
3179b3915dbbSRichard Henderson 
318059d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
318159d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
318259d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
3183c896fe29Sbellard {
318459d7c14eSRichard Henderson     if (ts->fixed_reg) {
318559d7c14eSRichard Henderson         return;
318659d7c14eSRichard Henderson     }
318759d7c14eSRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
318859d7c14eSRichard Henderson         s->reg_to_temp[ts->reg] = NULL;
318959d7c14eSRichard Henderson     }
319059d7c14eSRichard Henderson     ts->val_type = (free_or_dead < 0
319159d7c14eSRichard Henderson                     || ts->temp_local
3192fa477d25SRichard Henderson                     || ts->temp_global
319359d7c14eSRichard Henderson                     ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
319459d7c14eSRichard Henderson }
3195c896fe29Sbellard 
319659d7c14eSRichard Henderson /* Mark a temporary as dead.  */
319759d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
319859d7c14eSRichard Henderson {
319959d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
320059d7c14eSRichard Henderson }
320159d7c14eSRichard Henderson 
320259d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
320359d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
320459d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
320559d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
320698b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
320798b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
320859d7c14eSRichard Henderson {
320959d7c14eSRichard Henderson     if (ts->fixed_reg) {
321059d7c14eSRichard Henderson         return;
321159d7c14eSRichard Henderson     }
321259d7c14eSRichard Henderson     if (!ts->mem_coherent) {
32137f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
32142272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
321559d7c14eSRichard Henderson         }
321659d7c14eSRichard Henderson         switch (ts->val_type) {
321759d7c14eSRichard Henderson         case TEMP_VAL_CONST:
321859d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
321959d7c14eSRichard Henderson                require it later in a register, so attempt to store the
322059d7c14eSRichard Henderson                constant to memory directly.  */
322159d7c14eSRichard Henderson             if (free_or_dead
322259d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
322359d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
322459d7c14eSRichard Henderson                 break;
322559d7c14eSRichard Henderson             }
322659d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
322798b4e186SRichard Henderson                       allocated_regs, preferred_regs);
322859d7c14eSRichard Henderson             /* fallthrough */
322959d7c14eSRichard Henderson 
323059d7c14eSRichard Henderson         case TEMP_VAL_REG:
323159d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
323259d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
323359d7c14eSRichard Henderson             break;
323459d7c14eSRichard Henderson 
323559d7c14eSRichard Henderson         case TEMP_VAL_MEM:
323659d7c14eSRichard Henderson             break;
323759d7c14eSRichard Henderson 
323859d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
323959d7c14eSRichard Henderson         default:
324059d7c14eSRichard Henderson             tcg_abort();
3241c896fe29Sbellard         }
32427f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
32437f6ceedfSAurelien Jarno     }
324459d7c14eSRichard Henderson     if (free_or_dead) {
324559d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
324659d7c14eSRichard Henderson     }
324759d7c14eSRichard Henderson }
32487f6ceedfSAurelien Jarno 
32497f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
3250b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
32517f6ceedfSAurelien Jarno {
3252f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
3253f8b2f202SRichard Henderson     if (ts != NULL) {
325498b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
3255c896fe29Sbellard     }
3256c896fe29Sbellard }
3257c896fe29Sbellard 
3258b016486eSRichard Henderson /**
3259b016486eSRichard Henderson  * tcg_reg_alloc:
3260b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
3261b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
3262b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
3263b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
3264b016486eSRichard Henderson  *
3265b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
3266b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
3267b016486eSRichard Henderson  */
3268b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
3269b016486eSRichard Henderson                             TCGRegSet allocated_regs,
3270b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
3271c896fe29Sbellard {
3272b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
3273b016486eSRichard Henderson     TCGRegSet reg_ct[2];
327491478cefSRichard Henderson     const int *order;
3275c896fe29Sbellard 
3276b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
3277b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
3278b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
3279b016486eSRichard Henderson 
3280b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
3281b016486eSRichard Henderson        or if the preference made no difference.  */
3282b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
3283b016486eSRichard Henderson 
328491478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
3285c896fe29Sbellard 
3286b016486eSRichard Henderson     /* Try free registers, preferences first.  */
3287b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3288b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3289b016486eSRichard Henderson 
3290b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3291b016486eSRichard Henderson             /* One register in the set.  */
3292b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3293b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
3294c896fe29Sbellard                 return reg;
3295c896fe29Sbellard             }
3296b016486eSRichard Henderson         } else {
329791478cefSRichard Henderson             for (i = 0; i < n; i++) {
3298b016486eSRichard Henderson                 TCGReg reg = order[i];
3299b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
3300b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
3301b016486eSRichard Henderson                     return reg;
3302b016486eSRichard Henderson                 }
3303b016486eSRichard Henderson             }
3304b016486eSRichard Henderson         }
3305b016486eSRichard Henderson     }
3306b016486eSRichard Henderson 
3307b016486eSRichard Henderson     /* We must spill something.  */
3308b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3309b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3310b016486eSRichard Henderson 
3311b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3312b016486eSRichard Henderson             /* One register in the set.  */
3313b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3314b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
3315c896fe29Sbellard             return reg;
3316b016486eSRichard Henderson         } else {
3317b016486eSRichard Henderson             for (i = 0; i < n; i++) {
3318b016486eSRichard Henderson                 TCGReg reg = order[i];
3319b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
3320b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
3321b016486eSRichard Henderson                     return reg;
3322b016486eSRichard Henderson                 }
3323b016486eSRichard Henderson             }
3324c896fe29Sbellard         }
3325c896fe29Sbellard     }
3326c896fe29Sbellard 
3327c896fe29Sbellard     tcg_abort();
3328c896fe29Sbellard }
3329c896fe29Sbellard 
333040ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
333140ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
333240ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
3333b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
333440ae5c62SRichard Henderson {
333540ae5c62SRichard Henderson     TCGReg reg;
333640ae5c62SRichard Henderson 
333740ae5c62SRichard Henderson     switch (ts->val_type) {
333840ae5c62SRichard Henderson     case TEMP_VAL_REG:
333940ae5c62SRichard Henderson         return;
334040ae5c62SRichard Henderson     case TEMP_VAL_CONST:
3341b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3342b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
334340ae5c62SRichard Henderson         tcg_out_movi(s, ts->type, reg, ts->val);
334440ae5c62SRichard Henderson         ts->mem_coherent = 0;
334540ae5c62SRichard Henderson         break;
334640ae5c62SRichard Henderson     case TEMP_VAL_MEM:
3347b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3348b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
334940ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
335040ae5c62SRichard Henderson         ts->mem_coherent = 1;
335140ae5c62SRichard Henderson         break;
335240ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
335340ae5c62SRichard Henderson     default:
335440ae5c62SRichard Henderson         tcg_abort();
335540ae5c62SRichard Henderson     }
335640ae5c62SRichard Henderson     ts->reg = reg;
335740ae5c62SRichard Henderson     ts->val_type = TEMP_VAL_REG;
335840ae5c62SRichard Henderson     s->reg_to_temp[reg] = ts;
335940ae5c62SRichard Henderson }
336040ae5c62SRichard Henderson 
336159d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
3362e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
336359d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
33641ad80729SAurelien Jarno {
33652c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
3366eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
3367f8bf00f1SRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg);
33681ad80729SAurelien Jarno }
33691ad80729SAurelien Jarno 
33709814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
3371641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
3372641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
3373641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
3374641d5fbeSbellard {
3375ac3b8891SRichard Henderson     int i, n;
3376641d5fbeSbellard 
3377ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
3378b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
3379641d5fbeSbellard     }
3380e5097dc8Sbellard }
3381e5097dc8Sbellard 
33823d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
33833d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
33843d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
33853d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
33863d5c5f87SAurelien Jarno {
3387ac3b8891SRichard Henderson     int i, n;
33883d5c5f87SAurelien Jarno 
3389ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
339012b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
339112b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
339212b9b11aSRichard Henderson                          || ts->fixed_reg
339312b9b11aSRichard Henderson                          || ts->mem_coherent);
33943d5c5f87SAurelien Jarno     }
33953d5c5f87SAurelien Jarno }
33963d5c5f87SAurelien Jarno 
3397e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
3398e8996ee0Sbellard    all globals are stored at their canonical location. */
3399e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
3400e5097dc8Sbellard {
3401e5097dc8Sbellard     int i;
3402e5097dc8Sbellard 
3403c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
3404b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
3405641d5fbeSbellard         if (ts->temp_local) {
3406b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
3407641d5fbeSbellard         } else {
34082c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
3409eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
3410eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3411c896fe29Sbellard         }
3412641d5fbeSbellard     }
3413e8996ee0Sbellard 
3414e8996ee0Sbellard     save_globals(s, allocated_regs);
3415c896fe29Sbellard }
3416c896fe29Sbellard 
3417bab1671fSRichard Henderson /*
3418b4cb76e6SRichard Henderson  * At a conditional branch, we assume all temporaries are dead and
3419b4cb76e6SRichard Henderson  * all globals and local temps are synced to their location.
3420b4cb76e6SRichard Henderson  */
3421b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
3422b4cb76e6SRichard Henderson {
3423b4cb76e6SRichard Henderson     sync_globals(s, allocated_regs);
3424b4cb76e6SRichard Henderson 
3425b4cb76e6SRichard Henderson     for (int i = s->nb_globals; i < s->nb_temps; i++) {
3426b4cb76e6SRichard Henderson         TCGTemp *ts = &s->temps[i];
3427b4cb76e6SRichard Henderson         /*
3428b4cb76e6SRichard Henderson          * The liveness analysis already ensures that temps are dead.
3429b4cb76e6SRichard Henderson          * Keep tcg_debug_asserts for safety.
3430b4cb76e6SRichard Henderson          */
3431b4cb76e6SRichard Henderson         if (ts->temp_local) {
3432b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
3433b4cb76e6SRichard Henderson         } else {
3434b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3435b4cb76e6SRichard Henderson         }
3436b4cb76e6SRichard Henderson     }
3437b4cb76e6SRichard Henderson }
3438b4cb76e6SRichard Henderson 
3439b4cb76e6SRichard Henderson /*
3440bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_movi_*.
3441bab1671fSRichard Henderson  */
34420fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
3443ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
3444ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
3445e8996ee0Sbellard {
3446d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3447d63e3b6eSRichard Henderson     tcg_debug_assert(!ots->fixed_reg);
344859d7c14eSRichard Henderson 
344959d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
3450f8b2f202SRichard Henderson     if (ots->val_type == TEMP_VAL_REG) {
3451f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = NULL;
3452f8b2f202SRichard Henderson     }
3453e8996ee0Sbellard     ots->val_type = TEMP_VAL_CONST;
3454e8996ee0Sbellard     ots->val = val;
345559d7c14eSRichard Henderson     ots->mem_coherent = 0;
3456ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
3457ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
345859d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
3459f8bf00f1SRichard Henderson         temp_dead(s, ots);
34604c4e1ab2SAurelien Jarno     }
3461e8996ee0Sbellard }
3462e8996ee0Sbellard 
3463dd186292SRichard Henderson static void tcg_reg_alloc_movi(TCGContext *s, const TCGOp *op)
34640fe4fca4SPaolo Bonzini {
346543439139SRichard Henderson     TCGTemp *ots = arg_temp(op->args[0]);
3466dd186292SRichard Henderson     tcg_target_ulong val = op->args[1];
34670fe4fca4SPaolo Bonzini 
346869e3706dSRichard Henderson     tcg_reg_alloc_do_movi(s, ots, val, op->life, op->output_pref[0]);
34690fe4fca4SPaolo Bonzini }
34700fe4fca4SPaolo Bonzini 
3471bab1671fSRichard Henderson /*
3472bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
3473bab1671fSRichard Henderson  */
3474dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
3475c896fe29Sbellard {
3476dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
347769e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
3478c896fe29Sbellard     TCGTemp *ts, *ots;
3479450445d5SRichard Henderson     TCGType otype, itype;
3480c896fe29Sbellard 
3481d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
348269e3706dSRichard Henderson     preferred_regs = op->output_pref[0];
348343439139SRichard Henderson     ots = arg_temp(op->args[0]);
348443439139SRichard Henderson     ts = arg_temp(op->args[1]);
3485450445d5SRichard Henderson 
3486d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3487d63e3b6eSRichard Henderson     tcg_debug_assert(!ots->fixed_reg);
3488d63e3b6eSRichard Henderson 
3489450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
3490450445d5SRichard Henderson     otype = ots->type;
3491450445d5SRichard Henderson     itype = ts->type;
3492c896fe29Sbellard 
34930fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
34940fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
34950fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
34960fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
34970fe4fca4SPaolo Bonzini             temp_dead(s, ts);
34980fe4fca4SPaolo Bonzini         }
349969e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
35000fe4fca4SPaolo Bonzini         return;
35010fe4fca4SPaolo Bonzini     }
35020fe4fca4SPaolo Bonzini 
35030fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
35040fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
35050fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
35060fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
35070fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
350869e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
350969e3706dSRichard Henderson                   allocated_regs, preferred_regs);
3510c29c1d7eSAurelien Jarno     }
3511c29c1d7eSAurelien Jarno 
35120fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
3513d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
3514c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
3515c29c1d7eSAurelien Jarno            liveness analysis disabled). */
3516eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
3517c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
35182272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
3519c29c1d7eSAurelien Jarno         }
3520b3a62939SRichard Henderson         tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset);
3521c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
3522f8bf00f1SRichard Henderson             temp_dead(s, ts);
3523c29c1d7eSAurelien Jarno         }
3524f8bf00f1SRichard Henderson         temp_dead(s, ots);
3525e8996ee0Sbellard     } else {
3526d63e3b6eSRichard Henderson         if (IS_DEAD_ARG(1) && !ts->fixed_reg) {
3527c29c1d7eSAurelien Jarno             /* the mov can be suppressed */
3528c29c1d7eSAurelien Jarno             if (ots->val_type == TEMP_VAL_REG) {
3529f8b2f202SRichard Henderson                 s->reg_to_temp[ots->reg] = NULL;
3530c896fe29Sbellard             }
3531c29c1d7eSAurelien Jarno             ots->reg = ts->reg;
3532f8bf00f1SRichard Henderson             temp_dead(s, ts);
3533c29c1d7eSAurelien Jarno         } else {
3534c29c1d7eSAurelien Jarno             if (ots->val_type != TEMP_VAL_REG) {
3535c29c1d7eSAurelien Jarno                 /* When allocating a new register, make sure to not spill the
3536c29c1d7eSAurelien Jarno                    input one. */
3537c29c1d7eSAurelien Jarno                 tcg_regset_set_reg(allocated_regs, ts->reg);
3538450445d5SRichard Henderson                 ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
353969e3706dSRichard Henderson                                          allocated_regs, preferred_regs,
3540b016486eSRichard Henderson                                          ots->indirect_base);
3541c29c1d7eSAurelien Jarno             }
354278113e83SRichard Henderson             if (!tcg_out_mov(s, otype, ots->reg, ts->reg)) {
3543240c08d0SRichard Henderson                 /*
3544240c08d0SRichard Henderson                  * Cross register class move not supported.
3545240c08d0SRichard Henderson                  * Store the source register into the destination slot
3546240c08d0SRichard Henderson                  * and leave the destination temp as TEMP_VAL_MEM.
3547240c08d0SRichard Henderson                  */
3548240c08d0SRichard Henderson                 assert(!ots->fixed_reg);
3549240c08d0SRichard Henderson                 if (!ts->mem_allocated) {
3550240c08d0SRichard Henderson                     temp_allocate_frame(s, ots);
3551240c08d0SRichard Henderson                 }
3552240c08d0SRichard Henderson                 tcg_out_st(s, ts->type, ts->reg,
3553240c08d0SRichard Henderson                            ots->mem_base->reg, ots->mem_offset);
3554240c08d0SRichard Henderson                 ots->mem_coherent = 1;
3555240c08d0SRichard Henderson                 temp_free_or_dead(s, ots, -1);
3556240c08d0SRichard Henderson                 return;
355778113e83SRichard Henderson             }
3558c29c1d7eSAurelien Jarno         }
3559c896fe29Sbellard         ots->val_type = TEMP_VAL_REG;
3560c896fe29Sbellard         ots->mem_coherent = 0;
3561f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3562ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(0)) {
356398b4e186SRichard Henderson             temp_sync(s, ots, allocated_regs, 0, 0);
3564c29c1d7eSAurelien Jarno         }
3565ec7a869dSAurelien Jarno     }
3566c896fe29Sbellard }
3567c896fe29Sbellard 
3568bab1671fSRichard Henderson /*
3569bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
3570bab1671fSRichard Henderson  */
3571bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
3572bab1671fSRichard Henderson {
3573bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
3574bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
3575bab1671fSRichard Henderson     TCGTemp *its, *ots;
3576bab1671fSRichard Henderson     TCGType itype, vtype;
3577d6ecb4a9SRichard Henderson     intptr_t endian_fixup;
3578bab1671fSRichard Henderson     unsigned vece;
3579bab1671fSRichard Henderson     bool ok;
3580bab1671fSRichard Henderson 
3581bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
3582bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
3583bab1671fSRichard Henderson 
3584bab1671fSRichard Henderson     /* ENV should not be modified.  */
3585bab1671fSRichard Henderson     tcg_debug_assert(!ots->fixed_reg);
3586bab1671fSRichard Henderson 
3587bab1671fSRichard Henderson     itype = its->type;
3588bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
3589bab1671fSRichard Henderson     vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
3590bab1671fSRichard Henderson 
3591bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
3592bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
3593bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
3594bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
3595bab1671fSRichard Henderson             temp_dead(s, its);
3596bab1671fSRichard Henderson         }
3597bab1671fSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, op->output_pref[0]);
3598bab1671fSRichard Henderson         return;
3599bab1671fSRichard Henderson     }
3600bab1671fSRichard Henderson 
36019be0d080SRichard Henderson     dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
36029be0d080SRichard Henderson     dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs;
3603bab1671fSRichard Henderson 
3604bab1671fSRichard Henderson     /* Allocate the output register now.  */
3605bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
3606bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
3607bab1671fSRichard Henderson 
3608bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
3609bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
3610bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
3611bab1671fSRichard Henderson         }
3612bab1671fSRichard Henderson         ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
3613bab1671fSRichard Henderson                                  op->output_pref[0], ots->indirect_base);
3614bab1671fSRichard Henderson         ots->val_type = TEMP_VAL_REG;
3615bab1671fSRichard Henderson         ots->mem_coherent = 0;
3616bab1671fSRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3617bab1671fSRichard Henderson     }
3618bab1671fSRichard Henderson 
3619bab1671fSRichard Henderson     switch (its->val_type) {
3620bab1671fSRichard Henderson     case TEMP_VAL_REG:
3621bab1671fSRichard Henderson         /*
3622bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
3623bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
3624bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
3625bab1671fSRichard Henderson          */
3626bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
3627bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
3628bab1671fSRichard Henderson                 goto done;
3629bab1671fSRichard Henderson             }
3630bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
3631bab1671fSRichard Henderson         }
3632bab1671fSRichard Henderson         if (!its->mem_coherent) {
3633bab1671fSRichard Henderson             /*
3634bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
3635bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
3636bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
3637bab1671fSRichard Henderson              */
3638bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
3639bab1671fSRichard Henderson                 break;
3640bab1671fSRichard Henderson             }
3641bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
3642bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
3643bab1671fSRichard Henderson         }
3644bab1671fSRichard Henderson         /* fall through */
3645bab1671fSRichard Henderson 
3646bab1671fSRichard Henderson     case TEMP_VAL_MEM:
3647d6ecb4a9SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
3648d6ecb4a9SRichard Henderson         endian_fixup = itype == TCG_TYPE_I32 ? 4 : 8;
3649d6ecb4a9SRichard Henderson         endian_fixup -= 1 << vece;
3650d6ecb4a9SRichard Henderson #else
3651d6ecb4a9SRichard Henderson         endian_fixup = 0;
3652d6ecb4a9SRichard Henderson #endif
3653d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
3654d6ecb4a9SRichard Henderson                              its->mem_offset + endian_fixup)) {
3655d6ecb4a9SRichard Henderson             goto done;
3656d6ecb4a9SRichard Henderson         }
3657bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
3658bab1671fSRichard Henderson         break;
3659bab1671fSRichard Henderson 
3660bab1671fSRichard Henderson     default:
3661bab1671fSRichard Henderson         g_assert_not_reached();
3662bab1671fSRichard Henderson     }
3663bab1671fSRichard Henderson 
3664bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
3665bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
3666bab1671fSRichard Henderson     tcg_debug_assert(ok);
3667bab1671fSRichard Henderson 
3668bab1671fSRichard Henderson  done:
3669bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
3670bab1671fSRichard Henderson         temp_dead(s, its);
3671bab1671fSRichard Henderson     }
3672bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
3673bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
3674bab1671fSRichard Henderson     }
3675bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
3676bab1671fSRichard Henderson         temp_dead(s, ots);
3677bab1671fSRichard Henderson     }
3678bab1671fSRichard Henderson }
3679bab1671fSRichard Henderson 
3680dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
3681c896fe29Sbellard {
3682dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3683dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
368482790a87SRichard Henderson     TCGRegSet i_allocated_regs;
368582790a87SRichard Henderson     TCGRegSet o_allocated_regs;
3686b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
3687b6638662SRichard Henderson     TCGReg reg;
3688c896fe29Sbellard     TCGArg arg;
3689c896fe29Sbellard     const TCGArgConstraint *arg_ct;
3690c896fe29Sbellard     TCGTemp *ts;
3691c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
3692c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
3693c896fe29Sbellard 
3694c896fe29Sbellard     nb_oargs = def->nb_oargs;
3695c896fe29Sbellard     nb_iargs = def->nb_iargs;
3696c896fe29Sbellard 
3697c896fe29Sbellard     /* copy constants */
3698c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
3699dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
3700c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
3701c896fe29Sbellard 
3702d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
3703d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
370482790a87SRichard Henderson 
3705c896fe29Sbellard     /* satisfy input constraints */
3706c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
3707d62816f2SRichard Henderson         TCGRegSet i_preferred_regs, o_preferred_regs;
3708d62816f2SRichard Henderson 
370966792f90SRichard Henderson         i = def->args_ct[nb_oargs + k].sort_index;
3710dd186292SRichard Henderson         arg = op->args[i];
3711c896fe29Sbellard         arg_ct = &def->args_ct[i];
371243439139SRichard Henderson         ts = arg_temp(arg);
371340ae5c62SRichard Henderson 
371440ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
371540ae5c62SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct)) {
3716c896fe29Sbellard             /* constant is OK for instruction */
3717c896fe29Sbellard             const_args[i] = 1;
3718c896fe29Sbellard             new_args[i] = ts->val;
3719d62816f2SRichard Henderson             continue;
3720c896fe29Sbellard         }
372140ae5c62SRichard Henderson 
3722d62816f2SRichard Henderson         i_preferred_regs = o_preferred_regs = 0;
3723bc2b17e6SRichard Henderson         if (arg_ct->ialias) {
3724d62816f2SRichard Henderson             o_preferred_regs = op->output_pref[arg_ct->alias_index];
37255ff9d6a4Sbellard             if (ts->fixed_reg) {
37265ff9d6a4Sbellard                 /* if fixed register, we must allocate a new register
37275ff9d6a4Sbellard                    if the alias is not the same register */
3728d62816f2SRichard Henderson                 if (arg != op->args[arg_ct->alias_index]) {
37295ff9d6a4Sbellard                     goto allocate_in_reg;
3730d62816f2SRichard Henderson                 }
37315ff9d6a4Sbellard             } else {
3732c896fe29Sbellard                 /* if the input is aliased to an output and if it is
3733c896fe29Sbellard                    not dead after the instruction, we must allocate
3734c896fe29Sbellard                    a new register and move it */
3735866cb6cbSAurelien Jarno                 if (!IS_DEAD_ARG(i)) {
3736c896fe29Sbellard                     goto allocate_in_reg;
3737c896fe29Sbellard                 }
3738d62816f2SRichard Henderson 
37397e1df267SAurelien Jarno                 /* check if the current register has already been allocated
37407e1df267SAurelien Jarno                    for another input aliased to an output */
3741d62816f2SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG) {
37427e1df267SAurelien Jarno                     int k2, i2;
3743d62816f2SRichard Henderson                     reg = ts->reg;
37447e1df267SAurelien Jarno                     for (k2 = 0 ; k2 < k ; k2++) {
374566792f90SRichard Henderson                         i2 = def->args_ct[nb_oargs + k2].sort_index;
3746bc2b17e6SRichard Henderson                         if (def->args_ct[i2].ialias && reg == new_args[i2]) {
37477e1df267SAurelien Jarno                             goto allocate_in_reg;
37487e1df267SAurelien Jarno                         }
37497e1df267SAurelien Jarno                     }
37505ff9d6a4Sbellard                 }
3751d62816f2SRichard Henderson                 i_preferred_regs = o_preferred_regs;
3752866cb6cbSAurelien Jarno             }
3753d62816f2SRichard Henderson         }
3754d62816f2SRichard Henderson 
37559be0d080SRichard Henderson         temp_load(s, ts, arg_ct->regs, i_allocated_regs, i_preferred_regs);
3756c896fe29Sbellard         reg = ts->reg;
3757d62816f2SRichard Henderson 
37589be0d080SRichard Henderson         if (tcg_regset_test_reg(arg_ct->regs, reg)) {
3759c896fe29Sbellard             /* nothing to do : the constraint is satisfied */
3760c896fe29Sbellard         } else {
3761c896fe29Sbellard         allocate_in_reg:
3762c896fe29Sbellard             /* allocate a new register matching the constraint
3763c896fe29Sbellard                and move the temporary register into it */
3764d62816f2SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
3765d62816f2SRichard Henderson                       i_allocated_regs, 0);
37669be0d080SRichard Henderson             reg = tcg_reg_alloc(s, arg_ct->regs, i_allocated_regs,
3767d62816f2SRichard Henderson                                 o_preferred_regs, ts->indirect_base);
376878113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
3769240c08d0SRichard Henderson                 /*
3770240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
3771240c08d0SRichard Henderson                  * temp back to its slot and load from there.
3772240c08d0SRichard Henderson                  */
3773240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
3774240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
3775240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
377678113e83SRichard Henderson             }
3777c896fe29Sbellard         }
3778c896fe29Sbellard         new_args[i] = reg;
3779c896fe29Sbellard         const_args[i] = 0;
378082790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
3781c896fe29Sbellard     }
3782c896fe29Sbellard 
3783c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
3784866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
3785866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
378643439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
3787c896fe29Sbellard         }
3788c896fe29Sbellard     }
3789c896fe29Sbellard 
3790b4cb76e6SRichard Henderson     if (def->flags & TCG_OPF_COND_BRANCH) {
3791b4cb76e6SRichard Henderson         tcg_reg_alloc_cbranch(s, i_allocated_regs);
3792b4cb76e6SRichard Henderson     } else if (def->flags & TCG_OPF_BB_END) {
379382790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
3794a52ad07eSAurelien Jarno     } else {
3795c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
3796b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
3797c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
3798c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
379982790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
3800c896fe29Sbellard                 }
3801c896fe29Sbellard             }
38023d5c5f87SAurelien Jarno         }
38033d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
38043d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
38053d5c5f87SAurelien Jarno                an exception. */
380682790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
3807c896fe29Sbellard         }
3808c896fe29Sbellard 
3809c896fe29Sbellard         /* satisfy the output constraints */
3810c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
381166792f90SRichard Henderson             i = def->args_ct[k].sort_index;
3812dd186292SRichard Henderson             arg = op->args[i];
3813c896fe29Sbellard             arg_ct = &def->args_ct[i];
381443439139SRichard Henderson             ts = arg_temp(arg);
3815d63e3b6eSRichard Henderson 
3816d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
3817d63e3b6eSRichard Henderson             tcg_debug_assert(!ts->fixed_reg);
3818d63e3b6eSRichard Henderson 
3819bc2b17e6SRichard Henderson             if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
38205ff9d6a4Sbellard                 reg = new_args[arg_ct->alias_index];
3821bc2b17e6SRichard Henderson             } else if (arg_ct->newreg) {
38229be0d080SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->regs,
382382790a87SRichard Henderson                                     i_allocated_regs | o_allocated_regs,
382469e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
3825c896fe29Sbellard             } else {
38269be0d080SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
382769e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
3828c896fe29Sbellard             }
382982790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
3830639368ddSAurelien Jarno             if (ts->val_type == TEMP_VAL_REG) {
3831f8b2f202SRichard Henderson                 s->reg_to_temp[ts->reg] = NULL;
3832639368ddSAurelien Jarno             }
3833c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
3834c896fe29Sbellard             ts->reg = reg;
3835d63e3b6eSRichard Henderson             /*
3836d63e3b6eSRichard Henderson              * Temp value is modified, so the value kept in memory is
3837d63e3b6eSRichard Henderson              * potentially not the same.
3838d63e3b6eSRichard Henderson              */
3839c896fe29Sbellard             ts->mem_coherent = 0;
3840f8b2f202SRichard Henderson             s->reg_to_temp[reg] = ts;
3841c896fe29Sbellard             new_args[i] = reg;
3842c896fe29Sbellard         }
3843e8996ee0Sbellard     }
3844c896fe29Sbellard 
3845c896fe29Sbellard     /* emit instruction */
3846d2fd745fSRichard Henderson     if (def->flags & TCG_OPF_VECTOR) {
3847d2fd745fSRichard Henderson         tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
3848d2fd745fSRichard Henderson                        new_args, const_args);
3849d2fd745fSRichard Henderson     } else {
3850dd186292SRichard Henderson         tcg_out_op(s, op->opc, new_args, const_args);
3851d2fd745fSRichard Henderson     }
3852c896fe29Sbellard 
3853c896fe29Sbellard     /* move the outputs in the correct register if needed */
3854c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
385543439139SRichard Henderson         ts = arg_temp(op->args[i]);
3856d63e3b6eSRichard Henderson 
3857d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
3858d63e3b6eSRichard Henderson         tcg_debug_assert(!ts->fixed_reg);
3859d63e3b6eSRichard Henderson 
3860ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
386198b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
386259d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
3863f8bf00f1SRichard Henderson             temp_dead(s, ts);
3864ec7a869dSAurelien Jarno         }
3865c896fe29Sbellard     }
3866c896fe29Sbellard }
3867c896fe29Sbellard 
3868b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP
3869b03cce8eSbellard #define STACK_DIR(x) (-(x))
3870b03cce8eSbellard #else
3871b03cce8eSbellard #define STACK_DIR(x) (x)
3872b03cce8eSbellard #endif
3873b03cce8eSbellard 
3874dd186292SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
3875c896fe29Sbellard {
3876cd9090aaSRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
3877cd9090aaSRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
3878dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3879b6638662SRichard Henderson     int flags, nb_regs, i;
3880b6638662SRichard Henderson     TCGReg reg;
3881cf066674SRichard Henderson     TCGArg arg;
3882c896fe29Sbellard     TCGTemp *ts;
3883d3452f1fSRichard Henderson     intptr_t stack_offset;
3884d3452f1fSRichard Henderson     size_t call_stack_size;
3885cf066674SRichard Henderson     tcg_insn_unit *func_addr;
3886cf066674SRichard Henderson     int allocate_args;
3887c896fe29Sbellard     TCGRegSet allocated_regs;
3888c896fe29Sbellard 
3889dd186292SRichard Henderson     func_addr = (tcg_insn_unit *)(intptr_t)op->args[nb_oargs + nb_iargs];
3890dd186292SRichard Henderson     flags = op->args[nb_oargs + nb_iargs + 1];
3891c896fe29Sbellard 
38926e17d0c5SStefan Weil     nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
3893c45cb8bbSRichard Henderson     if (nb_regs > nb_iargs) {
3894c45cb8bbSRichard Henderson         nb_regs = nb_iargs;
3895cf066674SRichard Henderson     }
3896c896fe29Sbellard 
3897c896fe29Sbellard     /* assign stack slots first */
3898c45cb8bbSRichard Henderson     call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long);
3899c896fe29Sbellard     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
3900c896fe29Sbellard         ~(TCG_TARGET_STACK_ALIGN - 1);
3901b03cce8eSbellard     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
3902b03cce8eSbellard     if (allocate_args) {
3903345649c0SBlue Swirl         /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
3904345649c0SBlue Swirl            preallocate call stack */
3905345649c0SBlue Swirl         tcg_abort();
3906b03cce8eSbellard     }
390739cf05d3Sbellard 
390839cf05d3Sbellard     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
3909c45cb8bbSRichard Henderson     for (i = nb_regs; i < nb_iargs; i++) {
3910dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
391139cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP
391239cf05d3Sbellard         stack_offset -= sizeof(tcg_target_long);
391339cf05d3Sbellard #endif
391439cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
391543439139SRichard Henderson             ts = arg_temp(arg);
391640ae5c62SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
3917b722452aSRichard Henderson                       s->reserved_regs, 0);
3918e4d5434cSblueswir1             tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
391939cf05d3Sbellard         }
392039cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP
392139cf05d3Sbellard         stack_offset += sizeof(tcg_target_long);
392239cf05d3Sbellard #endif
3923c896fe29Sbellard     }
3924c896fe29Sbellard 
3925c896fe29Sbellard     /* assign input registers */
3926d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
3927c896fe29Sbellard     for (i = 0; i < nb_regs; i++) {
3928dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
392939cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
393043439139SRichard Henderson             ts = arg_temp(arg);
3931c896fe29Sbellard             reg = tcg_target_call_iarg_regs[i];
393240ae5c62SRichard Henderson 
3933c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
3934c896fe29Sbellard                 if (ts->reg != reg) {
39354250da10SRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
393678113e83SRichard Henderson                     if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
3937240c08d0SRichard Henderson                         /*
3938240c08d0SRichard Henderson                          * Cross register class move not supported.  Sync the
3939240c08d0SRichard Henderson                          * temp back to its slot and load from there.
3940240c08d0SRichard Henderson                          */
3941240c08d0SRichard Henderson                         temp_sync(s, ts, allocated_regs, 0, 0);
3942240c08d0SRichard Henderson                         tcg_out_ld(s, ts->type, reg,
3943240c08d0SRichard Henderson                                    ts->mem_base->reg, ts->mem_offset);
394478113e83SRichard Henderson                     }
3945c896fe29Sbellard                 }
3946c896fe29Sbellard             } else {
3947ccb1bb66SRichard Henderson                 TCGRegSet arg_set = 0;
394840ae5c62SRichard Henderson 
39494250da10SRichard Henderson                 tcg_reg_free(s, reg, allocated_regs);
395040ae5c62SRichard Henderson                 tcg_regset_set_reg(arg_set, reg);
3951b722452aSRichard Henderson                 temp_load(s, ts, arg_set, allocated_regs, 0);
3952c896fe29Sbellard             }
395340ae5c62SRichard Henderson 
3954c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
3955c896fe29Sbellard         }
395639cf05d3Sbellard     }
3957c896fe29Sbellard 
3958c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
3959866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3960866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
396143439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
3962c896fe29Sbellard         }
3963c896fe29Sbellard     }
3964c896fe29Sbellard 
3965c896fe29Sbellard     /* clobber call registers */
3966c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
3967c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
3968b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
3969c896fe29Sbellard         }
3970c896fe29Sbellard     }
3971c896fe29Sbellard 
397278505279SAurelien Jarno     /* Save globals if they might be written by the helper, sync them if
397378505279SAurelien Jarno        they might be read. */
397478505279SAurelien Jarno     if (flags & TCG_CALL_NO_READ_GLOBALS) {
397578505279SAurelien Jarno         /* Nothing to do */
397678505279SAurelien Jarno     } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) {
397778505279SAurelien Jarno         sync_globals(s, allocated_regs);
397878505279SAurelien Jarno     } else {
3979e8996ee0Sbellard         save_globals(s, allocated_regs);
3980b9c18f56Saurel32     }
3981c896fe29Sbellard 
3982cf066674SRichard Henderson     tcg_out_call(s, func_addr);
3983c896fe29Sbellard 
3984c896fe29Sbellard     /* assign output registers and emit moves if needed */
3985c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
3986dd186292SRichard Henderson         arg = op->args[i];
398743439139SRichard Henderson         ts = arg_temp(arg);
3988d63e3b6eSRichard Henderson 
3989d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
3990d63e3b6eSRichard Henderson         tcg_debug_assert(!ts->fixed_reg);
3991d63e3b6eSRichard Henderson 
3992c896fe29Sbellard         reg = tcg_target_call_oarg_regs[i];
3993eabb7b91SAurelien Jarno         tcg_debug_assert(s->reg_to_temp[reg] == NULL);
3994639368ddSAurelien Jarno         if (ts->val_type == TEMP_VAL_REG) {
3995f8b2f202SRichard Henderson             s->reg_to_temp[ts->reg] = NULL;
3996639368ddSAurelien Jarno         }
3997c896fe29Sbellard         ts->val_type = TEMP_VAL_REG;
3998c896fe29Sbellard         ts->reg = reg;
3999c896fe29Sbellard         ts->mem_coherent = 0;
4000f8b2f202SRichard Henderson         s->reg_to_temp[reg] = ts;
4001ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
400298b4e186SRichard Henderson             temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i));
400359d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4004f8bf00f1SRichard Henderson             temp_dead(s, ts);
4005c896fe29Sbellard         }
4006c896fe29Sbellard     }
40078c11ad25SAurelien Jarno }
4008c896fe29Sbellard 
4009c896fe29Sbellard #ifdef CONFIG_PROFILER
4010c896fe29Sbellard 
4011c3fac113SEmilio G. Cota /* avoid copy/paste errors */
4012c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field)                       \
4013c3fac113SEmilio G. Cota     do {                                                \
4014d73415a3SStefan Hajnoczi         (to)->field += qatomic_read(&((from)->field));  \
4015c3fac113SEmilio G. Cota     } while (0)
4016c896fe29Sbellard 
4017c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field)                                       \
4018c3fac113SEmilio G. Cota     do {                                                                \
4019d73415a3SStefan Hajnoczi         typeof((from)->field) val__ = qatomic_read(&((from)->field));   \
4020c3fac113SEmilio G. Cota         if (val__ > (to)->field) {                                      \
4021c3fac113SEmilio G. Cota             (to)->field = val__;                                        \
4022c3fac113SEmilio G. Cota         }                                                               \
4023c3fac113SEmilio G. Cota     } while (0)
4024c3fac113SEmilio G. Cota 
4025c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */
4026c3fac113SEmilio G. Cota static inline
4027c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
4028c896fe29Sbellard {
4029d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
4030c3fac113SEmilio G. Cota     unsigned int i;
4031c3fac113SEmilio G. Cota 
40323468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4033d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
40343468b59eSEmilio G. Cota         const TCGProfile *orig = &s->prof;
4035c3fac113SEmilio G. Cota 
4036c3fac113SEmilio G. Cota         if (counters) {
403772fd2efbSEmilio G. Cota             PROF_ADD(prof, orig, cpu_exec_time);
4038c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count1);
4039c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count);
4040c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, op_count);
4041c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, op_count_max);
4042c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, temp_count);
4043c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, temp_count_max);
4044c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, del_op_count);
4045c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_in_len);
4046c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_out_len);
4047c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, search_out_len);
4048c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, interm_time);
4049c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_time);
4050c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, la_time);
4051c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, opt_time);
4052c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_count);
4053c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_time);
4054c3fac113SEmilio G. Cota         }
4055c3fac113SEmilio G. Cota         if (table) {
4056c896fe29Sbellard             int i;
4057d70724ceSzhanghailiang 
405815fc7daaSRichard Henderson             for (i = 0; i < NB_OPS; i++) {
4059c3fac113SEmilio G. Cota                 PROF_ADD(prof, orig, table_op_count[i]);
4060c3fac113SEmilio G. Cota             }
4061c3fac113SEmilio G. Cota         }
4062c3fac113SEmilio G. Cota     }
4063c3fac113SEmilio G. Cota }
4064c3fac113SEmilio G. Cota 
4065c3fac113SEmilio G. Cota #undef PROF_ADD
4066c3fac113SEmilio G. Cota #undef PROF_MAX
4067c3fac113SEmilio G. Cota 
4068c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof)
4069c3fac113SEmilio G. Cota {
4070c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, true, false);
4071c3fac113SEmilio G. Cota }
4072c3fac113SEmilio G. Cota 
4073c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof)
4074c3fac113SEmilio G. Cota {
4075c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, false, true);
4076c3fac113SEmilio G. Cota }
4077c3fac113SEmilio G. Cota 
4078d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
4079c3fac113SEmilio G. Cota {
4080c3fac113SEmilio G. Cota     TCGProfile prof = {};
4081c3fac113SEmilio G. Cota     int i;
4082c3fac113SEmilio G. Cota 
4083c3fac113SEmilio G. Cota     tcg_profile_snapshot_table(&prof);
4084c3fac113SEmilio G. Cota     for (i = 0; i < NB_OPS; i++) {
4085d4c51a0aSMarkus Armbruster         qemu_printf("%s %" PRId64 "\n", tcg_op_defs[i].name,
4086c3fac113SEmilio G. Cota                     prof.table_op_count[i]);
4087c896fe29Sbellard     }
4088c896fe29Sbellard }
408972fd2efbSEmilio G. Cota 
409072fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
409172fd2efbSEmilio G. Cota {
4092d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
409372fd2efbSEmilio G. Cota     unsigned int i;
409472fd2efbSEmilio G. Cota     int64_t ret = 0;
409572fd2efbSEmilio G. Cota 
409672fd2efbSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4097d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
409872fd2efbSEmilio G. Cota         const TCGProfile *prof = &s->prof;
409972fd2efbSEmilio G. Cota 
4100d73415a3SStefan Hajnoczi         ret += qatomic_read(&prof->cpu_exec_time);
410172fd2efbSEmilio G. Cota     }
410272fd2efbSEmilio G. Cota     return ret;
410372fd2efbSEmilio G. Cota }
4104246ae24dSMax Filippov #else
4105d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
4106246ae24dSMax Filippov {
4107d4c51a0aSMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4108246ae24dSMax Filippov }
410972fd2efbSEmilio G. Cota 
411072fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
411172fd2efbSEmilio G. Cota {
411272fd2efbSEmilio G. Cota     error_report("%s: TCG profiler not compiled", __func__);
411372fd2efbSEmilio G. Cota     exit(EXIT_FAILURE);
411472fd2efbSEmilio G. Cota }
4115c896fe29Sbellard #endif
4116c896fe29Sbellard 
4117c896fe29Sbellard 
41185bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
4119c896fe29Sbellard {
4120c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER
4121c3fac113SEmilio G. Cota     TCGProfile *prof = &s->prof;
4122c3fac113SEmilio G. Cota #endif
412315fa08f8SRichard Henderson     int i, num_insns;
412415fa08f8SRichard Henderson     TCGOp *op;
4125c896fe29Sbellard 
412604fe6400SRichard Henderson #ifdef CONFIG_PROFILER
412704fe6400SRichard Henderson     {
4128c1f543b7SEmilio G. Cota         int n = 0;
412904fe6400SRichard Henderson 
413015fa08f8SRichard Henderson         QTAILQ_FOREACH(op, &s->ops, link) {
413115fa08f8SRichard Henderson             n++;
413215fa08f8SRichard Henderson         }
4133d73415a3SStefan Hajnoczi         qatomic_set(&prof->op_count, prof->op_count + n);
4134c3fac113SEmilio G. Cota         if (n > prof->op_count_max) {
4135d73415a3SStefan Hajnoczi             qatomic_set(&prof->op_count_max, n);
413604fe6400SRichard Henderson         }
413704fe6400SRichard Henderson 
413804fe6400SRichard Henderson         n = s->nb_temps;
4139d73415a3SStefan Hajnoczi         qatomic_set(&prof->temp_count, prof->temp_count + n);
4140c3fac113SEmilio G. Cota         if (n > prof->temp_count_max) {
4141d73415a3SStefan Hajnoczi             qatomic_set(&prof->temp_count_max, n);
414204fe6400SRichard Henderson         }
414304fe6400SRichard Henderson     }
414404fe6400SRichard Henderson #endif
414504fe6400SRichard Henderson 
4146c896fe29Sbellard #ifdef DEBUG_DISAS
4147d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
4148d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
4149fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
415093fcfe39Saliguori         qemu_log("OP:\n");
41511894f69aSRichard Henderson         tcg_dump_ops(s, false);
415293fcfe39Saliguori         qemu_log("\n");
4153fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
4154c896fe29Sbellard     }
4155c896fe29Sbellard #endif
4156c896fe29Sbellard 
4157bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
4158bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
4159bef16ab4SRichard Henderson     {
4160bef16ab4SRichard Henderson         TCGLabel *l;
4161bef16ab4SRichard Henderson         bool error = false;
4162bef16ab4SRichard Henderson 
4163bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
4164bef16ab4SRichard Henderson             if (unlikely(!l->present) && l->refs) {
4165bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
4166bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
4167bef16ab4SRichard Henderson                 error = true;
4168bef16ab4SRichard Henderson             }
4169bef16ab4SRichard Henderson         }
4170bef16ab4SRichard Henderson         assert(!error);
4171bef16ab4SRichard Henderson     }
4172bef16ab4SRichard Henderson #endif
4173bef16ab4SRichard Henderson 
4174c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
4175d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
4176c5cc28ffSAurelien Jarno #endif
4177c5cc28ffSAurelien Jarno 
41788f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
4179c45cb8bbSRichard Henderson     tcg_optimize(s);
41808f2e8c07SKirill Batuzov #endif
41818f2e8c07SKirill Batuzov 
4182a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4183d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
4184d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time - profile_getclock());
4185a23a9ec6Sbellard #endif
4186c5cc28ffSAurelien Jarno 
4187b4fc67c7SRichard Henderson     reachable_code_pass(s);
4188b83eabeaSRichard Henderson     liveness_pass_1(s);
41895a18407fSRichard Henderson 
41905a18407fSRichard Henderson     if (s->nb_indirects > 0) {
41915a18407fSRichard Henderson #ifdef DEBUG_DISAS
41925a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
41935a18407fSRichard Henderson                      && qemu_log_in_addr_range(tb->pc))) {
4194fc59d2d8SRobert Foley             FILE *logfile = qemu_log_lock();
41955a18407fSRichard Henderson             qemu_log("OP before indirect lowering:\n");
41961894f69aSRichard Henderson             tcg_dump_ops(s, false);
41975a18407fSRichard Henderson             qemu_log("\n");
4198fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
41995a18407fSRichard Henderson         }
42005a18407fSRichard Henderson #endif
42015a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
4202b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
42035a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
4204b83eabeaSRichard Henderson             liveness_pass_1(s);
42055a18407fSRichard Henderson         }
42065a18407fSRichard Henderson     }
4207c5cc28ffSAurelien Jarno 
4208a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4209d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time + profile_getclock());
4210a23a9ec6Sbellard #endif
4211c896fe29Sbellard 
4212c896fe29Sbellard #ifdef DEBUG_DISAS
4213d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
4214d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
4215fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
4216c5cc28ffSAurelien Jarno         qemu_log("OP after optimization and liveness analysis:\n");
42171894f69aSRichard Henderson         tcg_dump_ops(s, true);
421893fcfe39Saliguori         qemu_log("\n");
4219fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
4220c896fe29Sbellard     }
4221c896fe29Sbellard #endif
4222c896fe29Sbellard 
4223c896fe29Sbellard     tcg_reg_alloc_start(s);
4224c896fe29Sbellard 
4225e7e168f4SEmilio G. Cota     s->code_buf = tb->tc.ptr;
4226e7e168f4SEmilio G. Cota     s->code_ptr = tb->tc.ptr;
4227c896fe29Sbellard 
4228659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
42296001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
4230659ef5cbSRichard Henderson #endif
423157a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
423257a26946SRichard Henderson     s->pool_labels = NULL;
423357a26946SRichard Henderson #endif
42349ecefc84SRichard Henderson 
4235fca8a500SRichard Henderson     num_insns = -1;
423615fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
4237c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
4238b3db8758Sblueswir1 
4239c896fe29Sbellard #ifdef CONFIG_PROFILER
4240d73415a3SStefan Hajnoczi         qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
4241c896fe29Sbellard #endif
4242c45cb8bbSRichard Henderson 
4243c896fe29Sbellard         switch (opc) {
4244c896fe29Sbellard         case INDEX_op_mov_i32:
4245c896fe29Sbellard         case INDEX_op_mov_i64:
4246d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
4247dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
4248c896fe29Sbellard             break;
4249e8996ee0Sbellard         case INDEX_op_movi_i32:
4250e8996ee0Sbellard         case INDEX_op_movi_i64:
4251d2fd745fSRichard Henderson         case INDEX_op_dupi_vec:
4252dd186292SRichard Henderson             tcg_reg_alloc_movi(s, op);
4253e8996ee0Sbellard             break;
4254bab1671fSRichard Henderson         case INDEX_op_dup_vec:
4255bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
4256bab1671fSRichard Henderson             break;
4257765b842aSRichard Henderson         case INDEX_op_insn_start:
4258fca8a500SRichard Henderson             if (num_insns >= 0) {
42599f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
42609f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
42619f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
42629f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
4263fca8a500SRichard Henderson             }
4264fca8a500SRichard Henderson             num_insns++;
4265bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
4266bad729e2SRichard Henderson                 target_ulong a;
4267bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
4268efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
4269bad729e2SRichard Henderson #else
4270efee3746SRichard Henderson                 a = op->args[i];
4271bad729e2SRichard Henderson #endif
4272fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
4273bad729e2SRichard Henderson             }
4274c896fe29Sbellard             break;
42755ff9d6a4Sbellard         case INDEX_op_discard:
427643439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
42775ff9d6a4Sbellard             break;
4278c896fe29Sbellard         case INDEX_op_set_label:
4279e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
4280efee3746SRichard Henderson             tcg_out_label(s, arg_label(op->args[0]), s->code_ptr);
4281c896fe29Sbellard             break;
4282c896fe29Sbellard         case INDEX_op_call:
4283dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
4284c45cb8bbSRichard Henderson             break;
4285c896fe29Sbellard         default:
428625c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
4287be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
4288c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
4289c896fe29Sbellard                faster to have specialized register allocator functions for
4290c896fe29Sbellard                some common argument patterns */
4291dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
4292c896fe29Sbellard             break;
4293c896fe29Sbellard         }
42948d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
4295c896fe29Sbellard         check_regs(s);
4296c896fe29Sbellard #endif
4297b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
4298b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
4299b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
4300b125f9dcSRichard Henderson            generating code without having to check during generation.  */
4301644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
4302b125f9dcSRichard Henderson             return -1;
4303b125f9dcSRichard Henderson         }
43046e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
43056e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
43066e6c4efeSRichard Henderson             return -2;
43076e6c4efeSRichard Henderson         }
4308c896fe29Sbellard     }
4309fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
4310fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
4311c45cb8bbSRichard Henderson 
4312b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
4313659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
4314aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
4315aeee05f5SRichard Henderson     if (i < 0) {
4316aeee05f5SRichard Henderson         return i;
431723dceda6SRichard Henderson     }
4318659ef5cbSRichard Henderson #endif
431957a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
43201768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
43211768987bSRichard Henderson     if (i < 0) {
43221768987bSRichard Henderson         return i;
432357a26946SRichard Henderson     }
432457a26946SRichard Henderson #endif
43257ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
43267ecd02a0SRichard Henderson         return -2;
43277ecd02a0SRichard Henderson     }
4328c896fe29Sbellard 
4329*df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
4330c896fe29Sbellard     /* flush instruction cache */
43311813e175SRichard Henderson     flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr);
4332*df5d2b16SRichard Henderson #endif
43332aeabc08SStefan Weil 
43341813e175SRichard Henderson     return tcg_current_code_size(s);
4335c896fe29Sbellard }
4336c896fe29Sbellard 
4337a23a9ec6Sbellard #ifdef CONFIG_PROFILER
43383de2faa9SMarkus Armbruster void tcg_dump_info(void)
4339a23a9ec6Sbellard {
4340c3fac113SEmilio G. Cota     TCGProfile prof = {};
4341c3fac113SEmilio G. Cota     const TCGProfile *s;
4342c3fac113SEmilio G. Cota     int64_t tb_count;
4343c3fac113SEmilio G. Cota     int64_t tb_div_count;
4344c3fac113SEmilio G. Cota     int64_t tot;
4345c3fac113SEmilio G. Cota 
4346c3fac113SEmilio G. Cota     tcg_profile_snapshot_counters(&prof);
4347c3fac113SEmilio G. Cota     s = &prof;
4348c3fac113SEmilio G. Cota     tb_count = s->tb_count;
4349c3fac113SEmilio G. Cota     tb_div_count = tb_count ? tb_count : 1;
4350c3fac113SEmilio G. Cota     tot = s->interm_time + s->code_time;
4351a23a9ec6Sbellard 
43523de2faa9SMarkus Armbruster     qemu_printf("JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
4353a23a9ec6Sbellard                 tot, tot / 2.4e9);
43543de2faa9SMarkus Armbruster     qemu_printf("translated TBs      %" PRId64 " (aborted=%" PRId64
43553de2faa9SMarkus Armbruster                 " %0.1f%%)\n",
4356fca8a500SRichard Henderson                 tb_count, s->tb_count1 - tb_count,
4357fca8a500SRichard Henderson                 (double)(s->tb_count1 - s->tb_count)
4358fca8a500SRichard Henderson                 / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
43593de2faa9SMarkus Armbruster     qemu_printf("avg ops/TB          %0.1f max=%d\n",
4360fca8a500SRichard Henderson                 (double)s->op_count / tb_div_count, s->op_count_max);
43613de2faa9SMarkus Armbruster     qemu_printf("deleted ops/TB      %0.2f\n",
4362fca8a500SRichard Henderson                 (double)s->del_op_count / tb_div_count);
43633de2faa9SMarkus Armbruster     qemu_printf("avg temps/TB        %0.2f max=%d\n",
4364fca8a500SRichard Henderson                 (double)s->temp_count / tb_div_count, s->temp_count_max);
43653de2faa9SMarkus Armbruster     qemu_printf("avg host code/TB    %0.1f\n",
4366fca8a500SRichard Henderson                 (double)s->code_out_len / tb_div_count);
43673de2faa9SMarkus Armbruster     qemu_printf("avg search data/TB  %0.1f\n",
4368fca8a500SRichard Henderson                 (double)s->search_out_len / tb_div_count);
4369a23a9ec6Sbellard 
43703de2faa9SMarkus Armbruster     qemu_printf("cycles/op           %0.1f\n",
4371a23a9ec6Sbellard                 s->op_count ? (double)tot / s->op_count : 0);
43723de2faa9SMarkus Armbruster     qemu_printf("cycles/in byte      %0.1f\n",
4373a23a9ec6Sbellard                 s->code_in_len ? (double)tot / s->code_in_len : 0);
43743de2faa9SMarkus Armbruster     qemu_printf("cycles/out byte     %0.1f\n",
4375a23a9ec6Sbellard                 s->code_out_len ? (double)tot / s->code_out_len : 0);
43763de2faa9SMarkus Armbruster     qemu_printf("cycles/search byte     %0.1f\n",
4377fca8a500SRichard Henderson                 s->search_out_len ? (double)tot / s->search_out_len : 0);
4378fca8a500SRichard Henderson     if (tot == 0) {
4379a23a9ec6Sbellard         tot = 1;
4380fca8a500SRichard Henderson     }
43813de2faa9SMarkus Armbruster     qemu_printf("  gen_interm time   %0.1f%%\n",
4382a23a9ec6Sbellard                 (double)s->interm_time / tot * 100.0);
43833de2faa9SMarkus Armbruster     qemu_printf("  gen_code time     %0.1f%%\n",
4384a23a9ec6Sbellard                 (double)s->code_time / tot * 100.0);
43853de2faa9SMarkus Armbruster     qemu_printf("optim./code time    %0.1f%%\n",
4386c5cc28ffSAurelien Jarno                 (double)s->opt_time / (s->code_time ? s->code_time : 1)
4387c5cc28ffSAurelien Jarno                 * 100.0);
43883de2faa9SMarkus Armbruster     qemu_printf("liveness/code time  %0.1f%%\n",
4389a23a9ec6Sbellard                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
43903de2faa9SMarkus Armbruster     qemu_printf("cpu_restore count   %" PRId64 "\n",
4391a23a9ec6Sbellard                 s->restore_count);
43923de2faa9SMarkus Armbruster     qemu_printf("  avg cycles        %0.1f\n",
4393a23a9ec6Sbellard                 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
4394a23a9ec6Sbellard }
4395a23a9ec6Sbellard #else
43963de2faa9SMarkus Armbruster void tcg_dump_info(void)
4397a23a9ec6Sbellard {
43983de2faa9SMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4399a23a9ec6Sbellard }
4400a23a9ec6Sbellard #endif
4401813da627SRichard Henderson 
4402813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
44035872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
44045872bbf2SRichard Henderson 
44055872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
44065872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
44075872bbf2SRichard Henderson 
44085872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
44095872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
44105872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
44115872bbf2SRichard Henderson 
44125872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
44135872bbf2SRichard Henderson */
4414813da627SRichard Henderson 
4415813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
4416813da627SRichard Henderson typedef enum {
4417813da627SRichard Henderson     JIT_NOACTION = 0,
4418813da627SRichard Henderson     JIT_REGISTER_FN,
4419813da627SRichard Henderson     JIT_UNREGISTER_FN
4420813da627SRichard Henderson } jit_actions_t;
4421813da627SRichard Henderson 
4422813da627SRichard Henderson struct jit_code_entry {
4423813da627SRichard Henderson     struct jit_code_entry *next_entry;
4424813da627SRichard Henderson     struct jit_code_entry *prev_entry;
4425813da627SRichard Henderson     const void *symfile_addr;
4426813da627SRichard Henderson     uint64_t symfile_size;
4427813da627SRichard Henderson };
4428813da627SRichard Henderson 
4429813da627SRichard Henderson struct jit_descriptor {
4430813da627SRichard Henderson     uint32_t version;
4431813da627SRichard Henderson     uint32_t action_flag;
4432813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
4433813da627SRichard Henderson     struct jit_code_entry *first_entry;
4434813da627SRichard Henderson };
4435813da627SRichard Henderson 
4436813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
4437813da627SRichard Henderson void __jit_debug_register_code(void)
4438813da627SRichard Henderson {
4439813da627SRichard Henderson     asm("");
4440813da627SRichard Henderson }
4441813da627SRichard Henderson 
4442813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
4443813da627SRichard Henderson    the version before we can set it.  */
4444813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
4445813da627SRichard Henderson 
4446813da627SRichard Henderson /* End GDB interface.  */
4447813da627SRichard Henderson 
4448813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
4449813da627SRichard Henderson {
4450813da627SRichard Henderson     const char *p = strtab + 1;
4451813da627SRichard Henderson 
4452813da627SRichard Henderson     while (1) {
4453813da627SRichard Henderson         if (strcmp(p, str) == 0) {
4454813da627SRichard Henderson             return p - strtab;
4455813da627SRichard Henderson         }
4456813da627SRichard Henderson         p += strlen(p) + 1;
4457813da627SRichard Henderson     }
4458813da627SRichard Henderson }
4459813da627SRichard Henderson 
44605872bbf2SRichard Henderson static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
44612c90784aSRichard Henderson                                  const void *debug_frame,
44622c90784aSRichard Henderson                                  size_t debug_frame_size)
4463813da627SRichard Henderson {
44645872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
44655872bbf2SRichard Henderson         uint32_t  len;
44665872bbf2SRichard Henderson         uint16_t  version;
44675872bbf2SRichard Henderson         uint32_t  abbrev;
44685872bbf2SRichard Henderson         uint8_t   ptr_size;
44695872bbf2SRichard Henderson         uint8_t   cu_die;
44705872bbf2SRichard Henderson         uint16_t  cu_lang;
44715872bbf2SRichard Henderson         uintptr_t cu_low_pc;
44725872bbf2SRichard Henderson         uintptr_t cu_high_pc;
44735872bbf2SRichard Henderson         uint8_t   fn_die;
44745872bbf2SRichard Henderson         char      fn_name[16];
44755872bbf2SRichard Henderson         uintptr_t fn_low_pc;
44765872bbf2SRichard Henderson         uintptr_t fn_high_pc;
44775872bbf2SRichard Henderson         uint8_t   cu_eoc;
44785872bbf2SRichard Henderson     };
4479813da627SRichard Henderson 
4480813da627SRichard Henderson     struct ElfImage {
4481813da627SRichard Henderson         ElfW(Ehdr) ehdr;
4482813da627SRichard Henderson         ElfW(Phdr) phdr;
44835872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
44845872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
44855872bbf2SRichard Henderson         struct DebugInfo di;
44865872bbf2SRichard Henderson         uint8_t    da[24];
44875872bbf2SRichard Henderson         char       str[80];
44885872bbf2SRichard Henderson     };
44895872bbf2SRichard Henderson 
44905872bbf2SRichard Henderson     struct ElfImage *img;
44915872bbf2SRichard Henderson 
44925872bbf2SRichard Henderson     static const struct ElfImage img_template = {
44935872bbf2SRichard Henderson         .ehdr = {
44945872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
44955872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
44965872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
44975872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
44985872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
44995872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
45005872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
45015872bbf2SRichard Henderson             .e_type = ET_EXEC,
45025872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
45035872bbf2SRichard Henderson             .e_version = EV_CURRENT,
45045872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
45055872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
45065872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
45075872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
45085872bbf2SRichard Henderson             .e_phnum = 1,
45095872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
45105872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
45115872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
4512abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
4513abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
4514abbb3eaeSRichard Henderson #endif
4515abbb3eaeSRichard Henderson #ifdef ELF_OSABI
4516abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
4517abbb3eaeSRichard Henderson #endif
45185872bbf2SRichard Henderson         },
45195872bbf2SRichard Henderson         .phdr = {
45205872bbf2SRichard Henderson             .p_type = PT_LOAD,
45215872bbf2SRichard Henderson             .p_flags = PF_X,
45225872bbf2SRichard Henderson         },
45235872bbf2SRichard Henderson         .shdr = {
45245872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
45255872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
45265872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
45275872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
45285872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
45295872bbf2SRichard Henderson             [1] = { /* .text */
45305872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
45315872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
45325872bbf2SRichard Henderson             },
45335872bbf2SRichard Henderson             [2] = { /* .debug_info */
45345872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
45355872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
45365872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
45375872bbf2SRichard Henderson             },
45385872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
45395872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
45405872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
45415872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
45425872bbf2SRichard Henderson             },
45435872bbf2SRichard Henderson             [4] = { /* .debug_frame */
45445872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
45455872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
45465872bbf2SRichard Henderson             },
45475872bbf2SRichard Henderson             [5] = { /* .symtab */
45485872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
45495872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
45505872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
45515872bbf2SRichard Henderson                 .sh_info = 1,
45525872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
45535872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
45545872bbf2SRichard Henderson             },
45555872bbf2SRichard Henderson             [6] = { /* .strtab */
45565872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
45575872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
45585872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
45595872bbf2SRichard Henderson             }
45605872bbf2SRichard Henderson         },
45615872bbf2SRichard Henderson         .sym = {
45625872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
45635872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
45645872bbf2SRichard Henderson                 .st_shndx = 1,
45655872bbf2SRichard Henderson             }
45665872bbf2SRichard Henderson         },
45675872bbf2SRichard Henderson         .di = {
45685872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
45695872bbf2SRichard Henderson             .version = 2,
45705872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
45715872bbf2SRichard Henderson             .cu_die = 1,
45725872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
45735872bbf2SRichard Henderson             .fn_die = 2,
45745872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
45755872bbf2SRichard Henderson         },
45765872bbf2SRichard Henderson         .da = {
45775872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
45785872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
45795872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
45805872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
45815872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
45825872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
45835872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
45845872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
45855872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
45865872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
45875872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
45885872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
45895872bbf2SRichard Henderson             0           /* no more abbrev */
45905872bbf2SRichard Henderson         },
45915872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
45925872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
4593813da627SRichard Henderson     };
4594813da627SRichard Henderson 
4595813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
4596813da627SRichard Henderson     static struct jit_code_entry one_entry;
4597813da627SRichard Henderson 
45985872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
4599813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
46002c90784aSRichard Henderson     DebugFrameHeader *dfh;
4601813da627SRichard Henderson 
46025872bbf2SRichard Henderson     img = g_malloc(img_size);
46035872bbf2SRichard Henderson     *img = img_template;
4604813da627SRichard Henderson 
46055872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
46065872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
46075872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
4608813da627SRichard Henderson 
46095872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
46105872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
46115872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
4612813da627SRichard Henderson 
46135872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
46145872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
46155872bbf2SRichard Henderson 
46165872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
46175872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
46185872bbf2SRichard Henderson 
46195872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
46205872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
46215872bbf2SRichard Henderson 
46225872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
46235872bbf2SRichard Henderson     img->sym[1].st_value = buf;
46245872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
46255872bbf2SRichard Henderson 
46265872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
462745aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
46285872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
462945aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
4630813da627SRichard Henderson 
46312c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
46322c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
46332c90784aSRichard Henderson     dfh->fde.func_start = buf;
46342c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
46352c90784aSRichard Henderson 
4636813da627SRichard Henderson #ifdef DEBUG_JIT
4637813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
4638813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
4639813da627SRichard Henderson     {
4640813da627SRichard Henderson         FILE *f = fopen("/tmp/qemu.jit", "w+b");
4641813da627SRichard Henderson         if (f) {
46425872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
4643813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
4644813da627SRichard Henderson             }
4645813da627SRichard Henderson             fclose(f);
4646813da627SRichard Henderson         }
4647813da627SRichard Henderson     }
4648813da627SRichard Henderson #endif
4649813da627SRichard Henderson 
4650813da627SRichard Henderson     one_entry.symfile_addr = img;
4651813da627SRichard Henderson     one_entry.symfile_size = img_size;
4652813da627SRichard Henderson 
4653813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
4654813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
4655813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
4656813da627SRichard Henderson     __jit_debug_register_code();
4657813da627SRichard Henderson }
4658813da627SRichard Henderson #else
46595872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
46605872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
4661813da627SRichard Henderson 
4662813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size,
46632c90784aSRichard Henderson                                  const void *debug_frame,
46642c90784aSRichard Henderson                                  size_t debug_frame_size)
4665813da627SRichard Henderson {
4666813da627SRichard Henderson }
4667813da627SRichard Henderson 
4668813da627SRichard Henderson void tcg_register_jit(void *buf, size_t buf_size)
4669813da627SRichard Henderson {
4670813da627SRichard Henderson }
4671813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
4672db432672SRichard Henderson 
4673db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
4674db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
4675db432672SRichard Henderson {
4676db432672SRichard Henderson     g_assert_not_reached();
4677db432672SRichard Henderson }
4678db432672SRichard Henderson #endif
4679