xref: /qemu/tcg/tcg.c (revision be2cdc5e352eb28b4ff631f053a261d91e6af78e)
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 
33f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
341de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
351de7afc9SPaolo Bonzini #include "qemu/timer.h"
36c896fe29Sbellard 
37c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU
38c896fe29Sbellard    CPU definitions. Currently they are used for qemu_ld/st
39c896fe29Sbellard    instructions */
40c896fe29Sbellard #define NO_CPU_IO_DEFS
41c896fe29Sbellard #include "cpu.h"
42c896fe29Sbellard 
4363c91552SPaolo Bonzini #include "exec/cpu-common.h"
4463c91552SPaolo Bonzini #include "exec/exec-all.h"
4563c91552SPaolo Bonzini 
46c896fe29Sbellard #include "tcg-op.h"
47813da627SRichard Henderson 
48edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX
49813da627SRichard Henderson # define ELF_CLASS  ELFCLASS32
50edee2579SRichard Henderson #else
51edee2579SRichard Henderson # define ELF_CLASS  ELFCLASS64
52813da627SRichard Henderson #endif
53813da627SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
54813da627SRichard Henderson # define ELF_DATA   ELFDATA2MSB
55813da627SRichard Henderson #else
56813da627SRichard Henderson # define ELF_DATA   ELFDATA2LSB
57813da627SRichard Henderson #endif
58813da627SRichard Henderson 
59c896fe29Sbellard #include "elf.h"
60508127e2SPaolo Bonzini #include "exec/log.h"
613468b59eSEmilio G. Cota #include "sysemu/sysemu.h"
62c896fe29Sbellard 
63ce151109SPeter Maydell /* Forward declarations for functions declared in tcg-target.inc.c and
64ce151109SPeter Maydell    used here. */
65e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s);
66f69d277eSRichard Henderson static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode);
67e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
681813e175SRichard Henderson static void patch_reloc(tcg_insn_unit *code_ptr, int type,
692ba7fae2SRichard Henderson                         intptr_t value, intptr_t addend);
70c896fe29Sbellard 
71497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts.  */
72497a22ebSRichard Henderson typedef struct {
73497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
74497a22ebSRichard Henderson     uint32_t id;
75497a22ebSRichard Henderson     uint8_t version;
76497a22ebSRichard Henderson     char augmentation[1];
77497a22ebSRichard Henderson     uint8_t code_align;
78497a22ebSRichard Henderson     uint8_t data_align;
79497a22ebSRichard Henderson     uint8_t return_column;
80497a22ebSRichard Henderson } DebugFrameCIE;
81497a22ebSRichard Henderson 
82497a22ebSRichard Henderson typedef struct QEMU_PACKED {
83497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
84497a22ebSRichard Henderson     uint32_t cie_offset;
85edee2579SRichard Henderson     uintptr_t func_start;
86edee2579SRichard Henderson     uintptr_t func_len;
87497a22ebSRichard Henderson } DebugFrameFDEHeader;
88497a22ebSRichard Henderson 
892c90784aSRichard Henderson typedef struct QEMU_PACKED {
902c90784aSRichard Henderson     DebugFrameCIE cie;
912c90784aSRichard Henderson     DebugFrameFDEHeader fde;
922c90784aSRichard Henderson } DebugFrameHeader;
932c90784aSRichard Henderson 
94813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size,
952c90784aSRichard Henderson                                  const void *debug_frame,
962c90784aSRichard Henderson                                  size_t debug_frame_size)
97813da627SRichard Henderson     __attribute__((unused));
98813da627SRichard Henderson 
99ce151109SPeter Maydell /* Forward declarations for functions declared and used in tcg-target.inc.c. */
100069ea736SRichard Henderson static const char *target_parse_constraint(TCGArgConstraint *ct,
101069ea736SRichard Henderson                                            const char *ct_str, TCGType type);
1022a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
103a05b5b9bSRichard Henderson                        intptr_t arg2);
1042a534affSRichard Henderson static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
105c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1062a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
107c0ad3001SStefan Weil static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
108c0ad3001SStefan Weil                        const int *const_args);
109d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec
110d2fd745fSRichard Henderson static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl,
111d2fd745fSRichard Henderson                            unsigned vece, const TCGArg *args,
112d2fd745fSRichard Henderson                            const int *const_args);
113d2fd745fSRichard Henderson #else
114d2fd745fSRichard Henderson static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl,
115d2fd745fSRichard Henderson                                   unsigned vece, const TCGArg *args,
116d2fd745fSRichard Henderson                                   const int *const_args)
117d2fd745fSRichard Henderson {
118d2fd745fSRichard Henderson     g_assert_not_reached();
119d2fd745fSRichard Henderson }
120d2fd745fSRichard Henderson #endif
1212a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
122a05b5b9bSRichard Henderson                        intptr_t arg2);
12359d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
12459d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
125cf066674SRichard Henderson static void tcg_out_call(TCGContext *s, tcg_insn_unit *target);
126f6c6afc1SRichard Henderson static int tcg_target_const_match(tcg_target_long val, TCGType type,
127c0ad3001SStefan Weil                                   const TCGArgConstraint *arg_ct);
128659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
129659ef5cbSRichard Henderson static bool tcg_out_ldst_finalize(TCGContext *s);
130659ef5cbSRichard Henderson #endif
131c896fe29Sbellard 
132a505785cSEmilio G. Cota #define TCG_HIGHWATER 1024
133a505785cSEmilio G. Cota 
134df2cce29SEmilio G. Cota static TCGContext **tcg_ctxs;
135df2cce29SEmilio G. Cota static unsigned int n_tcg_ctxs;
1361c2adb95SRichard Henderson TCGv_env cpu_env = 0;
137df2cce29SEmilio G. Cota 
138*be2cdc5eSEmilio G. Cota struct tcg_region_tree {
139*be2cdc5eSEmilio G. Cota     QemuMutex lock;
140*be2cdc5eSEmilio G. Cota     GTree *tree;
141*be2cdc5eSEmilio G. Cota     /* padding to avoid false sharing is computed at run-time */
142*be2cdc5eSEmilio G. Cota };
143*be2cdc5eSEmilio G. Cota 
144e8feb96fSEmilio G. Cota /*
145e8feb96fSEmilio G. Cota  * We divide code_gen_buffer into equally-sized "regions" that TCG threads
146e8feb96fSEmilio G. Cota  * dynamically allocate from as demand dictates. Given appropriate region
147e8feb96fSEmilio G. Cota  * sizing, this minimizes flushes even when some TCG threads generate a lot
148e8feb96fSEmilio G. Cota  * more code than others.
149e8feb96fSEmilio G. Cota  */
150e8feb96fSEmilio G. Cota struct tcg_region_state {
151e8feb96fSEmilio G. Cota     QemuMutex lock;
152e8feb96fSEmilio G. Cota 
153e8feb96fSEmilio G. Cota     /* fields set at init time */
154e8feb96fSEmilio G. Cota     void *start;
155e8feb96fSEmilio G. Cota     void *start_aligned;
156e8feb96fSEmilio G. Cota     void *end;
157e8feb96fSEmilio G. Cota     size_t n;
158e8feb96fSEmilio G. Cota     size_t size; /* size of one region */
159e8feb96fSEmilio G. Cota     size_t stride; /* .size + guard size */
160e8feb96fSEmilio G. Cota 
161e8feb96fSEmilio G. Cota     /* fields protected by the lock */
162e8feb96fSEmilio G. Cota     size_t current; /* current region index */
163e8feb96fSEmilio G. Cota     size_t agg_size_full; /* aggregate size of full regions */
164e8feb96fSEmilio G. Cota };
165e8feb96fSEmilio G. Cota 
166e8feb96fSEmilio G. Cota static struct tcg_region_state region;
167*be2cdc5eSEmilio G. Cota /*
168*be2cdc5eSEmilio G. Cota  * This is an array of struct tcg_region_tree's, with padding.
169*be2cdc5eSEmilio G. Cota  * We use void * to simplify the computation of region_trees[i]; each
170*be2cdc5eSEmilio G. Cota  * struct is found every tree_size bytes.
171*be2cdc5eSEmilio G. Cota  */
172*be2cdc5eSEmilio G. Cota static void *region_trees;
173*be2cdc5eSEmilio G. Cota static size_t tree_size;
174d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
175b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
176c896fe29Sbellard 
1771813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
1784196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
179c896fe29Sbellard {
180c896fe29Sbellard     *s->code_ptr++ = v;
181c896fe29Sbellard }
182c896fe29Sbellard 
1834196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
1844196dca6SPeter Maydell                                                       uint8_t v)
1855c53bb81SPeter Maydell {
1861813e175SRichard Henderson     *p = v;
1875c53bb81SPeter Maydell }
1881813e175SRichard Henderson #endif
1895c53bb81SPeter Maydell 
1901813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
1914196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
192c896fe29Sbellard {
1931813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
1941813e175SRichard Henderson         *s->code_ptr++ = v;
1951813e175SRichard Henderson     } else {
1961813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
1974387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
1981813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
1991813e175SRichard Henderson     }
200c896fe29Sbellard }
201c896fe29Sbellard 
2024196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2034196dca6SPeter Maydell                                                        uint16_t v)
2045c53bb81SPeter Maydell {
2051813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2061813e175SRichard Henderson         *p = v;
2071813e175SRichard Henderson     } else {
2085c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2095c53bb81SPeter Maydell     }
2101813e175SRichard Henderson }
2111813e175SRichard Henderson #endif
2125c53bb81SPeter Maydell 
2131813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
2144196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
215c896fe29Sbellard {
2161813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2171813e175SRichard Henderson         *s->code_ptr++ = v;
2181813e175SRichard Henderson     } else {
2191813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2204387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2211813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
2221813e175SRichard Henderson     }
223c896fe29Sbellard }
224c896fe29Sbellard 
2254196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
2264196dca6SPeter Maydell                                                        uint32_t v)
2275c53bb81SPeter Maydell {
2281813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2291813e175SRichard Henderson         *p = v;
2301813e175SRichard Henderson     } else {
2315c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2325c53bb81SPeter Maydell     }
2331813e175SRichard Henderson }
2341813e175SRichard Henderson #endif
2355c53bb81SPeter Maydell 
2361813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
2374196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
238ac26eb69SRichard Henderson {
2391813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2401813e175SRichard Henderson         *s->code_ptr++ = v;
2411813e175SRichard Henderson     } else {
2421813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2434387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2441813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
2451813e175SRichard Henderson     }
246ac26eb69SRichard Henderson }
247ac26eb69SRichard Henderson 
2484196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
2494196dca6SPeter Maydell                                                        uint64_t v)
2505c53bb81SPeter Maydell {
2511813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2521813e175SRichard Henderson         *p = v;
2531813e175SRichard Henderson     } else {
2545c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2555c53bb81SPeter Maydell     }
2561813e175SRichard Henderson }
2571813e175SRichard Henderson #endif
2585c53bb81SPeter Maydell 
259c896fe29Sbellard /* label relocation processing */
260c896fe29Sbellard 
2611813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
262bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
263c896fe29Sbellard {
264c896fe29Sbellard     TCGRelocation *r;
265c896fe29Sbellard 
266c896fe29Sbellard     if (l->has_value) {
267623e265cSpbrook         /* FIXME: This may break relocations on RISC targets that
268623e265cSpbrook            modify instruction fields in place.  The caller may not have
269623e265cSpbrook            written the initial value.  */
270f54b3f92Saurel32         patch_reloc(code_ptr, type, l->u.value, addend);
271c896fe29Sbellard     } else {
272c896fe29Sbellard         /* add a new relocation entry */
273c896fe29Sbellard         r = tcg_malloc(sizeof(TCGRelocation));
274c896fe29Sbellard         r->type = type;
275c896fe29Sbellard         r->ptr = code_ptr;
276c896fe29Sbellard         r->addend = addend;
277c896fe29Sbellard         r->next = l->u.first_reloc;
278c896fe29Sbellard         l->u.first_reloc = r;
279c896fe29Sbellard     }
280c896fe29Sbellard }
281c896fe29Sbellard 
282bec16311SRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr)
283c896fe29Sbellard {
2842ba7fae2SRichard Henderson     intptr_t value = (intptr_t)ptr;
2851813e175SRichard Henderson     TCGRelocation *r;
286c896fe29Sbellard 
287eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
2881813e175SRichard Henderson 
2891813e175SRichard Henderson     for (r = l->u.first_reloc; r != NULL; r = r->next) {
290f54b3f92Saurel32         patch_reloc(r->ptr, r->type, value, r->addend);
291c896fe29Sbellard     }
2921813e175SRichard Henderson 
293c896fe29Sbellard     l->has_value = 1;
2941813e175SRichard Henderson     l->u.value_ptr = ptr;
295c896fe29Sbellard }
296c896fe29Sbellard 
29742a268c2SRichard Henderson TCGLabel *gen_new_label(void)
298c896fe29Sbellard {
299b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
30051e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
301c896fe29Sbellard 
30251e3972cSRichard Henderson     *l = (TCGLabel){
30351e3972cSRichard Henderson         .id = s->nb_labels++
30451e3972cSRichard Henderson     };
30542a268c2SRichard Henderson 
30642a268c2SRichard Henderson     return l;
307c896fe29Sbellard }
308c896fe29Sbellard 
309ce151109SPeter Maydell #include "tcg-target.inc.c"
310c896fe29Sbellard 
311*be2cdc5eSEmilio G. Cota /* compare a pointer @ptr and a tb_tc @s */
312*be2cdc5eSEmilio G. Cota static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s)
313*be2cdc5eSEmilio G. Cota {
314*be2cdc5eSEmilio G. Cota     if (ptr >= s->ptr + s->size) {
315*be2cdc5eSEmilio G. Cota         return 1;
316*be2cdc5eSEmilio G. Cota     } else if (ptr < s->ptr) {
317*be2cdc5eSEmilio G. Cota         return -1;
318*be2cdc5eSEmilio G. Cota     }
319*be2cdc5eSEmilio G. Cota     return 0;
320*be2cdc5eSEmilio G. Cota }
321*be2cdc5eSEmilio G. Cota 
322*be2cdc5eSEmilio G. Cota static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp)
323*be2cdc5eSEmilio G. Cota {
324*be2cdc5eSEmilio G. Cota     const struct tb_tc *a = ap;
325*be2cdc5eSEmilio G. Cota     const struct tb_tc *b = bp;
326*be2cdc5eSEmilio G. Cota 
327*be2cdc5eSEmilio G. Cota     /*
328*be2cdc5eSEmilio G. Cota      * When both sizes are set, we know this isn't a lookup.
329*be2cdc5eSEmilio G. Cota      * This is the most likely case: every TB must be inserted; lookups
330*be2cdc5eSEmilio G. Cota      * are a lot less frequent.
331*be2cdc5eSEmilio G. Cota      */
332*be2cdc5eSEmilio G. Cota     if (likely(a->size && b->size)) {
333*be2cdc5eSEmilio G. Cota         if (a->ptr > b->ptr) {
334*be2cdc5eSEmilio G. Cota             return 1;
335*be2cdc5eSEmilio G. Cota         } else if (a->ptr < b->ptr) {
336*be2cdc5eSEmilio G. Cota             return -1;
337*be2cdc5eSEmilio G. Cota         }
338*be2cdc5eSEmilio G. Cota         /* a->ptr == b->ptr should happen only on deletions */
339*be2cdc5eSEmilio G. Cota         g_assert(a->size == b->size);
340*be2cdc5eSEmilio G. Cota         return 0;
341*be2cdc5eSEmilio G. Cota     }
342*be2cdc5eSEmilio G. Cota     /*
343*be2cdc5eSEmilio G. Cota      * All lookups have either .size field set to 0.
344*be2cdc5eSEmilio G. Cota      * From the glib sources we see that @ap is always the lookup key. However
345*be2cdc5eSEmilio G. Cota      * the docs provide no guarantee, so we just mark this case as likely.
346*be2cdc5eSEmilio G. Cota      */
347*be2cdc5eSEmilio G. Cota     if (likely(a->size == 0)) {
348*be2cdc5eSEmilio G. Cota         return ptr_cmp_tb_tc(a->ptr, b);
349*be2cdc5eSEmilio G. Cota     }
350*be2cdc5eSEmilio G. Cota     return ptr_cmp_tb_tc(b->ptr, a);
351*be2cdc5eSEmilio G. Cota }
352*be2cdc5eSEmilio G. Cota 
353*be2cdc5eSEmilio G. Cota static void tcg_region_trees_init(void)
354*be2cdc5eSEmilio G. Cota {
355*be2cdc5eSEmilio G. Cota     size_t i;
356*be2cdc5eSEmilio G. Cota 
357*be2cdc5eSEmilio G. Cota     tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize);
358*be2cdc5eSEmilio G. Cota     region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size);
359*be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
360*be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
361*be2cdc5eSEmilio G. Cota 
362*be2cdc5eSEmilio G. Cota         qemu_mutex_init(&rt->lock);
363*be2cdc5eSEmilio G. Cota         rt->tree = g_tree_new(tb_tc_cmp);
364*be2cdc5eSEmilio G. Cota     }
365*be2cdc5eSEmilio G. Cota }
366*be2cdc5eSEmilio G. Cota 
367*be2cdc5eSEmilio G. Cota static struct tcg_region_tree *tc_ptr_to_region_tree(void *p)
368*be2cdc5eSEmilio G. Cota {
369*be2cdc5eSEmilio G. Cota     size_t region_idx;
370*be2cdc5eSEmilio G. Cota 
371*be2cdc5eSEmilio G. Cota     if (p < region.start_aligned) {
372*be2cdc5eSEmilio G. Cota         region_idx = 0;
373*be2cdc5eSEmilio G. Cota     } else {
374*be2cdc5eSEmilio G. Cota         ptrdiff_t offset = p - region.start_aligned;
375*be2cdc5eSEmilio G. Cota 
376*be2cdc5eSEmilio G. Cota         if (offset > region.stride * (region.n - 1)) {
377*be2cdc5eSEmilio G. Cota             region_idx = region.n - 1;
378*be2cdc5eSEmilio G. Cota         } else {
379*be2cdc5eSEmilio G. Cota             region_idx = offset / region.stride;
380*be2cdc5eSEmilio G. Cota         }
381*be2cdc5eSEmilio G. Cota     }
382*be2cdc5eSEmilio G. Cota     return region_trees + region_idx * tree_size;
383*be2cdc5eSEmilio G. Cota }
384*be2cdc5eSEmilio G. Cota 
385*be2cdc5eSEmilio G. Cota void tcg_tb_insert(TranslationBlock *tb)
386*be2cdc5eSEmilio G. Cota {
387*be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
388*be2cdc5eSEmilio G. Cota 
389*be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
390*be2cdc5eSEmilio G. Cota     g_tree_insert(rt->tree, &tb->tc, tb);
391*be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
392*be2cdc5eSEmilio G. Cota }
393*be2cdc5eSEmilio G. Cota 
394*be2cdc5eSEmilio G. Cota void tcg_tb_remove(TranslationBlock *tb)
395*be2cdc5eSEmilio G. Cota {
396*be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
397*be2cdc5eSEmilio G. Cota 
398*be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
399*be2cdc5eSEmilio G. Cota     g_tree_remove(rt->tree, &tb->tc);
400*be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
401*be2cdc5eSEmilio G. Cota }
402*be2cdc5eSEmilio G. Cota 
403*be2cdc5eSEmilio G. Cota /*
404*be2cdc5eSEmilio G. Cota  * Find the TB 'tb' such that
405*be2cdc5eSEmilio G. Cota  * tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size
406*be2cdc5eSEmilio G. Cota  * Return NULL if not found.
407*be2cdc5eSEmilio G. Cota  */
408*be2cdc5eSEmilio G. Cota TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr)
409*be2cdc5eSEmilio G. Cota {
410*be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr);
411*be2cdc5eSEmilio G. Cota     TranslationBlock *tb;
412*be2cdc5eSEmilio G. Cota     struct tb_tc s = { .ptr = (void *)tc_ptr };
413*be2cdc5eSEmilio G. Cota 
414*be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
415*be2cdc5eSEmilio G. Cota     tb = g_tree_lookup(rt->tree, &s);
416*be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
417*be2cdc5eSEmilio G. Cota     return tb;
418*be2cdc5eSEmilio G. Cota }
419*be2cdc5eSEmilio G. Cota 
420*be2cdc5eSEmilio G. Cota static void tcg_region_tree_lock_all(void)
421*be2cdc5eSEmilio G. Cota {
422*be2cdc5eSEmilio G. Cota     size_t i;
423*be2cdc5eSEmilio G. Cota 
424*be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
425*be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
426*be2cdc5eSEmilio G. Cota 
427*be2cdc5eSEmilio G. Cota         qemu_mutex_lock(&rt->lock);
428*be2cdc5eSEmilio G. Cota     }
429*be2cdc5eSEmilio G. Cota }
430*be2cdc5eSEmilio G. Cota 
431*be2cdc5eSEmilio G. Cota static void tcg_region_tree_unlock_all(void)
432*be2cdc5eSEmilio G. Cota {
433*be2cdc5eSEmilio G. Cota     size_t i;
434*be2cdc5eSEmilio G. Cota 
435*be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
436*be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
437*be2cdc5eSEmilio G. Cota 
438*be2cdc5eSEmilio G. Cota         qemu_mutex_unlock(&rt->lock);
439*be2cdc5eSEmilio G. Cota     }
440*be2cdc5eSEmilio G. Cota }
441*be2cdc5eSEmilio G. Cota 
442*be2cdc5eSEmilio G. Cota void tcg_tb_foreach(GTraverseFunc func, gpointer user_data)
443*be2cdc5eSEmilio G. Cota {
444*be2cdc5eSEmilio G. Cota     size_t i;
445*be2cdc5eSEmilio G. Cota 
446*be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
447*be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
448*be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
449*be2cdc5eSEmilio G. Cota 
450*be2cdc5eSEmilio G. Cota         g_tree_foreach(rt->tree, func, user_data);
451*be2cdc5eSEmilio G. Cota     }
452*be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
453*be2cdc5eSEmilio G. Cota }
454*be2cdc5eSEmilio G. Cota 
455*be2cdc5eSEmilio G. Cota size_t tcg_nb_tbs(void)
456*be2cdc5eSEmilio G. Cota {
457*be2cdc5eSEmilio G. Cota     size_t nb_tbs = 0;
458*be2cdc5eSEmilio G. Cota     size_t i;
459*be2cdc5eSEmilio G. Cota 
460*be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
461*be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
462*be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
463*be2cdc5eSEmilio G. Cota 
464*be2cdc5eSEmilio G. Cota         nb_tbs += g_tree_nnodes(rt->tree);
465*be2cdc5eSEmilio G. Cota     }
466*be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
467*be2cdc5eSEmilio G. Cota     return nb_tbs;
468*be2cdc5eSEmilio G. Cota }
469*be2cdc5eSEmilio G. Cota 
470*be2cdc5eSEmilio G. Cota static void tcg_region_tree_reset_all(void)
471*be2cdc5eSEmilio G. Cota {
472*be2cdc5eSEmilio G. Cota     size_t i;
473*be2cdc5eSEmilio G. Cota 
474*be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
475*be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
476*be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
477*be2cdc5eSEmilio G. Cota 
478*be2cdc5eSEmilio G. Cota         /* Increment the refcount first so that destroy acts as a reset */
479*be2cdc5eSEmilio G. Cota         g_tree_ref(rt->tree);
480*be2cdc5eSEmilio G. Cota         g_tree_destroy(rt->tree);
481*be2cdc5eSEmilio G. Cota     }
482*be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
483*be2cdc5eSEmilio G. Cota }
484*be2cdc5eSEmilio G. Cota 
485e8feb96fSEmilio G. Cota static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend)
486e8feb96fSEmilio G. Cota {
487e8feb96fSEmilio G. Cota     void *start, *end;
488e8feb96fSEmilio G. Cota 
489e8feb96fSEmilio G. Cota     start = region.start_aligned + curr_region * region.stride;
490e8feb96fSEmilio G. Cota     end = start + region.size;
491e8feb96fSEmilio G. Cota 
492e8feb96fSEmilio G. Cota     if (curr_region == 0) {
493e8feb96fSEmilio G. Cota         start = region.start;
494e8feb96fSEmilio G. Cota     }
495e8feb96fSEmilio G. Cota     if (curr_region == region.n - 1) {
496e8feb96fSEmilio G. Cota         end = region.end;
497e8feb96fSEmilio G. Cota     }
498e8feb96fSEmilio G. Cota 
499e8feb96fSEmilio G. Cota     *pstart = start;
500e8feb96fSEmilio G. Cota     *pend = end;
501e8feb96fSEmilio G. Cota }
502e8feb96fSEmilio G. Cota 
503e8feb96fSEmilio G. Cota static void tcg_region_assign(TCGContext *s, size_t curr_region)
504e8feb96fSEmilio G. Cota {
505e8feb96fSEmilio G. Cota     void *start, *end;
506e8feb96fSEmilio G. Cota 
507e8feb96fSEmilio G. Cota     tcg_region_bounds(curr_region, &start, &end);
508e8feb96fSEmilio G. Cota 
509e8feb96fSEmilio G. Cota     s->code_gen_buffer = start;
510e8feb96fSEmilio G. Cota     s->code_gen_ptr = start;
511e8feb96fSEmilio G. Cota     s->code_gen_buffer_size = end - start;
512e8feb96fSEmilio G. Cota     s->code_gen_highwater = end - TCG_HIGHWATER;
513e8feb96fSEmilio G. Cota }
514e8feb96fSEmilio G. Cota 
515e8feb96fSEmilio G. Cota static bool tcg_region_alloc__locked(TCGContext *s)
516e8feb96fSEmilio G. Cota {
517e8feb96fSEmilio G. Cota     if (region.current == region.n) {
518e8feb96fSEmilio G. Cota         return true;
519e8feb96fSEmilio G. Cota     }
520e8feb96fSEmilio G. Cota     tcg_region_assign(s, region.current);
521e8feb96fSEmilio G. Cota     region.current++;
522e8feb96fSEmilio G. Cota     return false;
523e8feb96fSEmilio G. Cota }
524e8feb96fSEmilio G. Cota 
525e8feb96fSEmilio G. Cota /*
526e8feb96fSEmilio G. Cota  * Request a new region once the one in use has filled up.
527e8feb96fSEmilio G. Cota  * Returns true on error.
528e8feb96fSEmilio G. Cota  */
529e8feb96fSEmilio G. Cota static bool tcg_region_alloc(TCGContext *s)
530e8feb96fSEmilio G. Cota {
531e8feb96fSEmilio G. Cota     bool err;
532e8feb96fSEmilio G. Cota     /* read the region size now; alloc__locked will overwrite it on success */
533e8feb96fSEmilio G. Cota     size_t size_full = s->code_gen_buffer_size;
534e8feb96fSEmilio G. Cota 
535e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
536e8feb96fSEmilio G. Cota     err = tcg_region_alloc__locked(s);
537e8feb96fSEmilio G. Cota     if (!err) {
538e8feb96fSEmilio G. Cota         region.agg_size_full += size_full - TCG_HIGHWATER;
539e8feb96fSEmilio G. Cota     }
540e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
541e8feb96fSEmilio G. Cota     return err;
542e8feb96fSEmilio G. Cota }
543e8feb96fSEmilio G. Cota 
544e8feb96fSEmilio G. Cota /*
545e8feb96fSEmilio G. Cota  * Perform a context's first region allocation.
546e8feb96fSEmilio G. Cota  * This function does _not_ increment region.agg_size_full.
547e8feb96fSEmilio G. Cota  */
548e8feb96fSEmilio G. Cota static inline bool tcg_region_initial_alloc__locked(TCGContext *s)
549e8feb96fSEmilio G. Cota {
550e8feb96fSEmilio G. Cota     return tcg_region_alloc__locked(s);
551e8feb96fSEmilio G. Cota }
552e8feb96fSEmilio G. Cota 
553e8feb96fSEmilio G. Cota /* Call from a safe-work context */
554e8feb96fSEmilio G. Cota void tcg_region_reset_all(void)
555e8feb96fSEmilio G. Cota {
5563468b59eSEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
557e8feb96fSEmilio G. Cota     unsigned int i;
558e8feb96fSEmilio G. Cota 
559e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
560e8feb96fSEmilio G. Cota     region.current = 0;
561e8feb96fSEmilio G. Cota     region.agg_size_full = 0;
562e8feb96fSEmilio G. Cota 
5633468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
5643468b59eSEmilio G. Cota         TCGContext *s = atomic_read(&tcg_ctxs[i]);
5653468b59eSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(s);
566e8feb96fSEmilio G. Cota 
567e8feb96fSEmilio G. Cota         g_assert(!err);
568e8feb96fSEmilio G. Cota     }
569e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
570*be2cdc5eSEmilio G. Cota 
571*be2cdc5eSEmilio G. Cota     tcg_region_tree_reset_all();
572e8feb96fSEmilio G. Cota }
573e8feb96fSEmilio G. Cota 
5743468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
5753468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
5763468b59eSEmilio G. Cota {
5773468b59eSEmilio G. Cota     return 1;
5783468b59eSEmilio G. Cota }
5793468b59eSEmilio G. Cota #else
5803468b59eSEmilio G. Cota /*
5813468b59eSEmilio G. Cota  * It is likely that some vCPUs will translate more code than others, so we
5823468b59eSEmilio G. Cota  * first try to set more regions than max_cpus, with those regions being of
5833468b59eSEmilio G. Cota  * reasonable size. If that's not possible we make do by evenly dividing
5843468b59eSEmilio G. Cota  * the code_gen_buffer among the vCPUs.
5853468b59eSEmilio G. Cota  */
5863468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
5873468b59eSEmilio G. Cota {
5883468b59eSEmilio G. Cota     size_t i;
5893468b59eSEmilio G. Cota 
5903468b59eSEmilio G. Cota     /* Use a single region if all we have is one vCPU thread */
5913468b59eSEmilio G. Cota     if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) {
5923468b59eSEmilio G. Cota         return 1;
5933468b59eSEmilio G. Cota     }
5943468b59eSEmilio G. Cota 
5953468b59eSEmilio G. Cota     /* Try to have more regions than max_cpus, with each region being >= 2 MB */
5963468b59eSEmilio G. Cota     for (i = 8; i > 0; i--) {
5973468b59eSEmilio G. Cota         size_t regions_per_thread = i;
5983468b59eSEmilio G. Cota         size_t region_size;
5993468b59eSEmilio G. Cota 
6003468b59eSEmilio G. Cota         region_size = tcg_init_ctx.code_gen_buffer_size;
6013468b59eSEmilio G. Cota         region_size /= max_cpus * regions_per_thread;
6023468b59eSEmilio G. Cota 
6033468b59eSEmilio G. Cota         if (region_size >= 2 * 1024u * 1024) {
6043468b59eSEmilio G. Cota             return max_cpus * regions_per_thread;
6053468b59eSEmilio G. Cota         }
6063468b59eSEmilio G. Cota     }
6073468b59eSEmilio G. Cota     /* If we can't, then just allocate one region per vCPU thread */
6083468b59eSEmilio G. Cota     return max_cpus;
6093468b59eSEmilio G. Cota }
6103468b59eSEmilio G. Cota #endif
6113468b59eSEmilio G. Cota 
612e8feb96fSEmilio G. Cota /*
613e8feb96fSEmilio G. Cota  * Initializes region partitioning.
614e8feb96fSEmilio G. Cota  *
615e8feb96fSEmilio G. Cota  * Called at init time from the parent thread (i.e. the one calling
616e8feb96fSEmilio G. Cota  * tcg_context_init), after the target's TCG globals have been set.
6173468b59eSEmilio G. Cota  *
6183468b59eSEmilio G. Cota  * Region partitioning works by splitting code_gen_buffer into separate regions,
6193468b59eSEmilio G. Cota  * and then assigning regions to TCG threads so that the threads can translate
6203468b59eSEmilio G. Cota  * code in parallel without synchronization.
6213468b59eSEmilio G. Cota  *
6223468b59eSEmilio G. Cota  * In softmmu the number of TCG threads is bounded by max_cpus, so we use at
6233468b59eSEmilio G. Cota  * least max_cpus regions in MTTCG. In !MTTCG we use a single region.
6243468b59eSEmilio G. Cota  * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...])
6253468b59eSEmilio G. Cota  * must have been parsed before calling this function, since it calls
6263468b59eSEmilio G. Cota  * qemu_tcg_mttcg_enabled().
6273468b59eSEmilio G. Cota  *
6283468b59eSEmilio G. Cota  * In user-mode we use a single region.  Having multiple regions in user-mode
6293468b59eSEmilio G. Cota  * is not supported, because the number of vCPU threads (recall that each thread
6303468b59eSEmilio G. Cota  * spawned by the guest corresponds to a vCPU thread) is only bounded by the
6313468b59eSEmilio G. Cota  * OS, and usually this number is huge (tens of thousands is not uncommon).
6323468b59eSEmilio G. Cota  * Thus, given this large bound on the number of vCPU threads and the fact
6333468b59eSEmilio G. Cota  * that code_gen_buffer is allocated at compile-time, we cannot guarantee
6343468b59eSEmilio G. Cota  * that the availability of at least one region per vCPU thread.
6353468b59eSEmilio G. Cota  *
6363468b59eSEmilio G. Cota  * However, this user-mode limitation is unlikely to be a significant problem
6373468b59eSEmilio G. Cota  * in practice. Multi-threaded guests share most if not all of their translated
6383468b59eSEmilio G. Cota  * code, which makes parallel code generation less appealing than in softmmu.
639e8feb96fSEmilio G. Cota  */
640e8feb96fSEmilio G. Cota void tcg_region_init(void)
641e8feb96fSEmilio G. Cota {
642e8feb96fSEmilio G. Cota     void *buf = tcg_init_ctx.code_gen_buffer;
643e8feb96fSEmilio G. Cota     void *aligned;
644e8feb96fSEmilio G. Cota     size_t size = tcg_init_ctx.code_gen_buffer_size;
645e8feb96fSEmilio G. Cota     size_t page_size = qemu_real_host_page_size;
646e8feb96fSEmilio G. Cota     size_t region_size;
647e8feb96fSEmilio G. Cota     size_t n_regions;
648e8feb96fSEmilio G. Cota     size_t i;
649e8feb96fSEmilio G. Cota 
6503468b59eSEmilio G. Cota     n_regions = tcg_n_regions();
651e8feb96fSEmilio G. Cota 
652e8feb96fSEmilio G. Cota     /* The first region will be 'aligned - buf' bytes larger than the others */
653e8feb96fSEmilio G. Cota     aligned = QEMU_ALIGN_PTR_UP(buf, page_size);
654e8feb96fSEmilio G. Cota     g_assert(aligned < tcg_init_ctx.code_gen_buffer + size);
655e8feb96fSEmilio G. Cota     /*
656e8feb96fSEmilio G. Cota      * Make region_size a multiple of page_size, using aligned as the start.
657e8feb96fSEmilio G. Cota      * As a result of this we might end up with a few extra pages at the end of
658e8feb96fSEmilio G. Cota      * the buffer; we will assign those to the last region.
659e8feb96fSEmilio G. Cota      */
660e8feb96fSEmilio G. Cota     region_size = (size - (aligned - buf)) / n_regions;
661e8feb96fSEmilio G. Cota     region_size = QEMU_ALIGN_DOWN(region_size, page_size);
662e8feb96fSEmilio G. Cota 
663e8feb96fSEmilio G. Cota     /* A region must have at least 2 pages; one code, one guard */
664e8feb96fSEmilio G. Cota     g_assert(region_size >= 2 * page_size);
665e8feb96fSEmilio G. Cota 
666e8feb96fSEmilio G. Cota     /* init the region struct */
667e8feb96fSEmilio G. Cota     qemu_mutex_init(&region.lock);
668e8feb96fSEmilio G. Cota     region.n = n_regions;
669e8feb96fSEmilio G. Cota     region.size = region_size - page_size;
670e8feb96fSEmilio G. Cota     region.stride = region_size;
671e8feb96fSEmilio G. Cota     region.start = buf;
672e8feb96fSEmilio G. Cota     region.start_aligned = aligned;
673e8feb96fSEmilio G. Cota     /* page-align the end, since its last page will be a guard page */
674e8feb96fSEmilio G. Cota     region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size);
675e8feb96fSEmilio G. Cota     /* account for that last guard page */
676e8feb96fSEmilio G. Cota     region.end -= page_size;
677e8feb96fSEmilio G. Cota 
678e8feb96fSEmilio G. Cota     /* set guard pages */
679e8feb96fSEmilio G. Cota     for (i = 0; i < region.n; i++) {
680e8feb96fSEmilio G. Cota         void *start, *end;
681e8feb96fSEmilio G. Cota         int rc;
682e8feb96fSEmilio G. Cota 
683e8feb96fSEmilio G. Cota         tcg_region_bounds(i, &start, &end);
684e8feb96fSEmilio G. Cota         rc = qemu_mprotect_none(end, page_size);
685e8feb96fSEmilio G. Cota         g_assert(!rc);
686e8feb96fSEmilio G. Cota     }
687e8feb96fSEmilio G. Cota 
688*be2cdc5eSEmilio G. Cota     tcg_region_trees_init();
689*be2cdc5eSEmilio G. Cota 
6903468b59eSEmilio G. Cota     /* In user-mode we support only one ctx, so do the initial allocation now */
6913468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
692e8feb96fSEmilio G. Cota     {
693e8feb96fSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(tcg_ctx);
694e8feb96fSEmilio G. Cota 
695e8feb96fSEmilio G. Cota         g_assert(!err);
696e8feb96fSEmilio G. Cota     }
6973468b59eSEmilio G. Cota #endif
698e8feb96fSEmilio G. Cota }
699e8feb96fSEmilio G. Cota 
700e8feb96fSEmilio G. Cota /*
7013468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
7023468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
7033468b59eSEmilio G. Cota  * before initiating translation.
7043468b59eSEmilio G. Cota  *
7053468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
7063468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
7073468b59eSEmilio G. Cota  *
7083468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
7093468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
7103468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
7113468b59eSEmilio G. Cota  *
7123468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
7133468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
7143468b59eSEmilio G. Cota  */
7153468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
7163468b59eSEmilio G. Cota void tcg_register_thread(void)
7173468b59eSEmilio G. Cota {
7183468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
7193468b59eSEmilio G. Cota }
7203468b59eSEmilio G. Cota #else
7213468b59eSEmilio G. Cota void tcg_register_thread(void)
7223468b59eSEmilio G. Cota {
7233468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
7243468b59eSEmilio G. Cota     unsigned int i, n;
7253468b59eSEmilio G. Cota     bool err;
7263468b59eSEmilio G. Cota 
7273468b59eSEmilio G. Cota     *s = tcg_init_ctx;
7283468b59eSEmilio G. Cota 
7293468b59eSEmilio G. Cota     /* Relink mem_base.  */
7303468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
7313468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
7323468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
7333468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
7343468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
7353468b59eSEmilio G. Cota         }
7363468b59eSEmilio G. Cota     }
7373468b59eSEmilio G. Cota 
7383468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
7393468b59eSEmilio G. Cota     n = atomic_fetch_inc(&n_tcg_ctxs);
7403468b59eSEmilio G. Cota     g_assert(n < max_cpus);
7413468b59eSEmilio G. Cota     atomic_set(&tcg_ctxs[n], s);
7423468b59eSEmilio G. Cota 
7433468b59eSEmilio G. Cota     tcg_ctx = s;
7443468b59eSEmilio G. Cota     qemu_mutex_lock(&region.lock);
7453468b59eSEmilio G. Cota     err = tcg_region_initial_alloc__locked(tcg_ctx);
7463468b59eSEmilio G. Cota     g_assert(!err);
7473468b59eSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
7483468b59eSEmilio G. Cota }
7493468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
7503468b59eSEmilio G. Cota 
7513468b59eSEmilio G. Cota /*
752e8feb96fSEmilio G. Cota  * Returns the size (in bytes) of all translated code (i.e. from all regions)
753e8feb96fSEmilio G. Cota  * currently in the cache.
754e8feb96fSEmilio G. Cota  * See also: tcg_code_capacity()
755e8feb96fSEmilio G. Cota  * Do not confuse with tcg_current_code_size(); that one applies to a single
756e8feb96fSEmilio G. Cota  * TCG context.
757e8feb96fSEmilio G. Cota  */
758e8feb96fSEmilio G. Cota size_t tcg_code_size(void)
759e8feb96fSEmilio G. Cota {
7603468b59eSEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
761e8feb96fSEmilio G. Cota     unsigned int i;
762e8feb96fSEmilio G. Cota     size_t total;
763e8feb96fSEmilio G. Cota 
764e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
765e8feb96fSEmilio G. Cota     total = region.agg_size_full;
7663468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
7673468b59eSEmilio G. Cota         const TCGContext *s = atomic_read(&tcg_ctxs[i]);
768e8feb96fSEmilio G. Cota         size_t size;
769e8feb96fSEmilio G. Cota 
770e8feb96fSEmilio G. Cota         size = atomic_read(&s->code_gen_ptr) - s->code_gen_buffer;
771e8feb96fSEmilio G. Cota         g_assert(size <= s->code_gen_buffer_size);
772e8feb96fSEmilio G. Cota         total += size;
773e8feb96fSEmilio G. Cota     }
774e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
775e8feb96fSEmilio G. Cota     return total;
776e8feb96fSEmilio G. Cota }
777e8feb96fSEmilio G. Cota 
778e8feb96fSEmilio G. Cota /*
779e8feb96fSEmilio G. Cota  * Returns the code capacity (in bytes) of the entire cache, i.e. including all
780e8feb96fSEmilio G. Cota  * regions.
781e8feb96fSEmilio G. Cota  * See also: tcg_code_size()
782e8feb96fSEmilio G. Cota  */
783e8feb96fSEmilio G. Cota size_t tcg_code_capacity(void)
784e8feb96fSEmilio G. Cota {
785e8feb96fSEmilio G. Cota     size_t guard_size, capacity;
786e8feb96fSEmilio G. Cota 
787e8feb96fSEmilio G. Cota     /* no need for synchronization; these variables are set at init time */
788e8feb96fSEmilio G. Cota     guard_size = region.stride - region.size;
789e8feb96fSEmilio G. Cota     capacity = region.end + guard_size - region.start;
790e8feb96fSEmilio G. Cota     capacity -= region.n * (guard_size + TCG_HIGHWATER);
791e8feb96fSEmilio G. Cota     return capacity;
792e8feb96fSEmilio G. Cota }
793e8feb96fSEmilio G. Cota 
794c896fe29Sbellard /* pool based memory allocation */
795c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
796c896fe29Sbellard {
797c896fe29Sbellard     TCGPool *p;
798c896fe29Sbellard     int pool_size;
799c896fe29Sbellard 
800c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
801c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
8027267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
803c896fe29Sbellard         p->size = size;
8044055299eSKirill Batuzov         p->next = s->pool_first_large;
8054055299eSKirill Batuzov         s->pool_first_large = p;
8064055299eSKirill Batuzov         return p->data;
807c896fe29Sbellard     } else {
808c896fe29Sbellard         p = s->pool_current;
809c896fe29Sbellard         if (!p) {
810c896fe29Sbellard             p = s->pool_first;
811c896fe29Sbellard             if (!p)
812c896fe29Sbellard                 goto new_pool;
813c896fe29Sbellard         } else {
814c896fe29Sbellard             if (!p->next) {
815c896fe29Sbellard             new_pool:
816c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
8177267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
818c896fe29Sbellard                 p->size = pool_size;
819c896fe29Sbellard                 p->next = NULL;
820c896fe29Sbellard                 if (s->pool_current)
821c896fe29Sbellard                     s->pool_current->next = p;
822c896fe29Sbellard                 else
823c896fe29Sbellard                     s->pool_first = p;
824c896fe29Sbellard             } else {
825c896fe29Sbellard                 p = p->next;
826c896fe29Sbellard             }
827c896fe29Sbellard         }
828c896fe29Sbellard     }
829c896fe29Sbellard     s->pool_current = p;
830c896fe29Sbellard     s->pool_cur = p->data + size;
831c896fe29Sbellard     s->pool_end = p->data + p->size;
832c896fe29Sbellard     return p->data;
833c896fe29Sbellard }
834c896fe29Sbellard 
835c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
836c896fe29Sbellard {
8374055299eSKirill Batuzov     TCGPool *p, *t;
8384055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
8394055299eSKirill Batuzov         t = p->next;
8404055299eSKirill Batuzov         g_free(p);
8414055299eSKirill Batuzov     }
8424055299eSKirill Batuzov     s->pool_first_large = NULL;
843c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
844c896fe29Sbellard     s->pool_current = NULL;
845c896fe29Sbellard }
846c896fe29Sbellard 
847100b5e01SRichard Henderson typedef struct TCGHelperInfo {
848100b5e01SRichard Henderson     void *func;
849100b5e01SRichard Henderson     const char *name;
850afb49896SRichard Henderson     unsigned flags;
851afb49896SRichard Henderson     unsigned sizemask;
852100b5e01SRichard Henderson } TCGHelperInfo;
853100b5e01SRichard Henderson 
8542ef6175aSRichard Henderson #include "exec/helper-proto.h"
8552ef6175aSRichard Henderson 
856100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = {
8572ef6175aSRichard Henderson #include "exec/helper-tcg.h"
858100b5e01SRichard Henderson };
859619205fdSEmilio G. Cota static GHashTable *helper_table;
860100b5e01SRichard Henderson 
86191478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
862f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
8631c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
8641c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
86591478cefSRichard Henderson 
866c896fe29Sbellard void tcg_context_init(TCGContext *s)
867c896fe29Sbellard {
868100b5e01SRichard Henderson     int op, total_args, n, i;
869c896fe29Sbellard     TCGOpDef *def;
870c896fe29Sbellard     TCGArgConstraint *args_ct;
871c896fe29Sbellard     int *sorted_args;
8721c2adb95SRichard Henderson     TCGTemp *ts;
873c896fe29Sbellard 
874c896fe29Sbellard     memset(s, 0, sizeof(*s));
875c896fe29Sbellard     s->nb_globals = 0;
876c896fe29Sbellard 
877c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
878c896fe29Sbellard        space */
879c896fe29Sbellard     total_args = 0;
880c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
881c896fe29Sbellard         def = &tcg_op_defs[op];
882c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
883c896fe29Sbellard         total_args += n;
884c896fe29Sbellard     }
885c896fe29Sbellard 
8867267c094SAnthony Liguori     args_ct = g_malloc(sizeof(TCGArgConstraint) * total_args);
8877267c094SAnthony Liguori     sorted_args = g_malloc(sizeof(int) * total_args);
888c896fe29Sbellard 
889c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
890c896fe29Sbellard         def = &tcg_op_defs[op];
891c896fe29Sbellard         def->args_ct = args_ct;
892c896fe29Sbellard         def->sorted_args = sorted_args;
893c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
894c896fe29Sbellard         sorted_args += n;
895c896fe29Sbellard         args_ct += n;
896c896fe29Sbellard     }
897c896fe29Sbellard 
8985cd8f621SRichard Henderson     /* Register helpers.  */
89984fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
900619205fdSEmilio G. Cota     helper_table = g_hash_table_new(NULL, NULL);
90184fd9dd3SRichard Henderson 
902100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
90384fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
90472866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
905100b5e01SRichard Henderson     }
9065cd8f621SRichard Henderson 
907c896fe29Sbellard     tcg_target_init(s);
908f69d277eSRichard Henderson     process_op_defs(s);
90991478cefSRichard Henderson 
91091478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
91191478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
91291478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
91391478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
91491478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
91591478cefSRichard Henderson             break;
91691478cefSRichard Henderson         }
91791478cefSRichard Henderson     }
91891478cefSRichard Henderson     for (i = 0; i < n; ++i) {
91991478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
92091478cefSRichard Henderson     }
92191478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
92291478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
92391478cefSRichard Henderson     }
924b1311c4aSEmilio G. Cota 
925b1311c4aSEmilio G. Cota     tcg_ctx = s;
9263468b59eSEmilio G. Cota     /*
9273468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
9283468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
9293468b59eSEmilio G. Cota      * reasoning behind this.
9303468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
9313468b59eSEmilio G. Cota      */
9323468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
933df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
934df2cce29SEmilio G. Cota     n_tcg_ctxs = 1;
9353468b59eSEmilio G. Cota #else
9363468b59eSEmilio G. Cota     tcg_ctxs = g_new(TCGContext *, max_cpus);
9373468b59eSEmilio G. Cota #endif
9381c2adb95SRichard Henderson 
9391c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
9401c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
9411c2adb95SRichard Henderson     cpu_env = temp_tcgv_ptr(ts);
9429002ec79SRichard Henderson }
943b03cce8eSbellard 
9446e3b2bfdSEmilio G. Cota /*
9456e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
9466e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
9476e3b2bfdSEmilio G. Cota  */
9486e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
9496e3b2bfdSEmilio G. Cota {
9506e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
9516e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
9526e3b2bfdSEmilio G. Cota     void *next;
9536e3b2bfdSEmilio G. Cota 
954e8feb96fSEmilio G. Cota  retry:
9556e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
9566e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
9576e3b2bfdSEmilio G. Cota 
9586e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
959e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
9606e3b2bfdSEmilio G. Cota             return NULL;
9616e3b2bfdSEmilio G. Cota         }
962e8feb96fSEmilio G. Cota         goto retry;
963e8feb96fSEmilio G. Cota     }
964e8feb96fSEmilio G. Cota     atomic_set(&s->code_gen_ptr, next);
96557a26946SRichard Henderson     s->data_gen_ptr = NULL;
9666e3b2bfdSEmilio G. Cota     return tb;
9676e3b2bfdSEmilio G. Cota }
9686e3b2bfdSEmilio G. Cota 
9699002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
9709002ec79SRichard Henderson {
9718163b749SRichard Henderson     size_t prologue_size, total_size;
9728163b749SRichard Henderson     void *buf0, *buf1;
9738163b749SRichard Henderson 
9748163b749SRichard Henderson     /* Put the prologue at the beginning of code_gen_buffer.  */
9758163b749SRichard Henderson     buf0 = s->code_gen_buffer;
9765b38ee31SRichard Henderson     total_size = s->code_gen_buffer_size;
9778163b749SRichard Henderson     s->code_ptr = buf0;
9788163b749SRichard Henderson     s->code_buf = buf0;
9795b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
9808163b749SRichard Henderson     s->code_gen_prologue = buf0;
9818163b749SRichard Henderson 
9825b38ee31SRichard Henderson     /* Compute a high-water mark, at which we voluntarily flush the buffer
9835b38ee31SRichard Henderson        and start over.  The size here is arbitrary, significantly larger
9845b38ee31SRichard Henderson        than we expect the code generation for any one opcode to require.  */
9855b38ee31SRichard Henderson     s->code_gen_highwater = s->code_gen_buffer + (total_size - TCG_HIGHWATER);
9865b38ee31SRichard Henderson 
9875b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
9885b38ee31SRichard Henderson     s->pool_labels = NULL;
9895b38ee31SRichard Henderson #endif
9905b38ee31SRichard Henderson 
9918163b749SRichard Henderson     /* Generate the prologue.  */
992b03cce8eSbellard     tcg_target_qemu_prologue(s);
9935b38ee31SRichard Henderson 
9945b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
9955b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
9965b38ee31SRichard Henderson     {
9975b38ee31SRichard Henderson         bool ok = tcg_out_pool_finalize(s);
9985b38ee31SRichard Henderson         tcg_debug_assert(ok);
9995b38ee31SRichard Henderson     }
10005b38ee31SRichard Henderson #endif
10015b38ee31SRichard Henderson 
10028163b749SRichard Henderson     buf1 = s->code_ptr;
10038163b749SRichard Henderson     flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1);
10048163b749SRichard Henderson 
10058163b749SRichard Henderson     /* Deduct the prologue from the buffer.  */
10068163b749SRichard Henderson     prologue_size = tcg_current_code_size(s);
10078163b749SRichard Henderson     s->code_gen_ptr = buf1;
10088163b749SRichard Henderson     s->code_gen_buffer = buf1;
10098163b749SRichard Henderson     s->code_buf = buf1;
10105b38ee31SRichard Henderson     total_size -= prologue_size;
10118163b749SRichard Henderson     s->code_gen_buffer_size = total_size;
10128163b749SRichard Henderson 
10138163b749SRichard Henderson     tcg_register_jit(s->code_gen_buffer, total_size);
1014d6b64b2bSRichard Henderson 
1015d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
1016d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
10171ee73216SRichard Henderson         qemu_log_lock();
10188163b749SRichard Henderson         qemu_log("PROLOGUE: [size=%zu]\n", prologue_size);
10195b38ee31SRichard Henderson         if (s->data_gen_ptr) {
10205b38ee31SRichard Henderson             size_t code_size = s->data_gen_ptr - buf0;
10215b38ee31SRichard Henderson             size_t data_size = prologue_size - code_size;
10225b38ee31SRichard Henderson             size_t i;
10235b38ee31SRichard Henderson 
10245b38ee31SRichard Henderson             log_disas(buf0, code_size);
10255b38ee31SRichard Henderson 
10265b38ee31SRichard Henderson             for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
10275b38ee31SRichard Henderson                 if (sizeof(tcg_target_ulong) == 8) {
10285b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
10295b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
10305b38ee31SRichard Henderson                              *(uint64_t *)(s->data_gen_ptr + i));
10315b38ee31SRichard Henderson                 } else {
10325b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .long  0x%08x\n",
10335b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
10345b38ee31SRichard Henderson                              *(uint32_t *)(s->data_gen_ptr + i));
10355b38ee31SRichard Henderson                 }
10365b38ee31SRichard Henderson             }
10375b38ee31SRichard Henderson         } else {
10388163b749SRichard Henderson             log_disas(buf0, prologue_size);
10395b38ee31SRichard Henderson         }
1040d6b64b2bSRichard Henderson         qemu_log("\n");
1041d6b64b2bSRichard Henderson         qemu_log_flush();
10421ee73216SRichard Henderson         qemu_log_unlock();
1043d6b64b2bSRichard Henderson     }
1044d6b64b2bSRichard Henderson #endif
1045cedbcb01SEmilio G. Cota 
1046cedbcb01SEmilio G. Cota     /* Assert that goto_ptr is implemented completely.  */
1047cedbcb01SEmilio G. Cota     if (TCG_TARGET_HAS_goto_ptr) {
1048cedbcb01SEmilio G. Cota         tcg_debug_assert(s->code_gen_epilogue != NULL);
1049cedbcb01SEmilio G. Cota     }
1050c896fe29Sbellard }
1051c896fe29Sbellard 
1052c896fe29Sbellard void tcg_func_start(TCGContext *s)
1053c896fe29Sbellard {
1054c896fe29Sbellard     tcg_pool_reset(s);
1055c896fe29Sbellard     s->nb_temps = s->nb_globals;
10560ec9eabcSRichard Henderson 
10570ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
10580ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
10590ec9eabcSRichard Henderson 
1060abebf925SRichard Henderson     s->nb_ops = 0;
1061c896fe29Sbellard     s->nb_labels = 0;
1062c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1063c896fe29Sbellard 
10640a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
10650a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
10660a209d4bSRichard Henderson #endif
10670a209d4bSRichard Henderson 
106815fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
106915fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
1070c896fe29Sbellard }
1071c896fe29Sbellard 
10727ca4b752SRichard Henderson static inline TCGTemp *tcg_temp_alloc(TCGContext *s)
10737ca4b752SRichard Henderson {
10747ca4b752SRichard Henderson     int n = s->nb_temps++;
10757ca4b752SRichard Henderson     tcg_debug_assert(n < TCG_MAX_TEMPS);
10767ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
10777ca4b752SRichard Henderson }
10787ca4b752SRichard Henderson 
10797ca4b752SRichard Henderson static inline TCGTemp *tcg_global_alloc(TCGContext *s)
10807ca4b752SRichard Henderson {
1081fa477d25SRichard Henderson     TCGTemp *ts;
1082fa477d25SRichard Henderson 
10837ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
10847ca4b752SRichard Henderson     s->nb_globals++;
1085fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1086fa477d25SRichard Henderson     ts->temp_global = 1;
1087fa477d25SRichard Henderson 
1088fa477d25SRichard Henderson     return ts;
1089c896fe29Sbellard }
1090c896fe29Sbellard 
1091085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1092b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1093c896fe29Sbellard {
1094c896fe29Sbellard     TCGTemp *ts;
1095c896fe29Sbellard 
1096b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
1097c896fe29Sbellard         tcg_abort();
1098b3a62939SRichard Henderson     }
10997ca4b752SRichard Henderson 
11007ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1101c896fe29Sbellard     ts->base_type = type;
1102c896fe29Sbellard     ts->type = type;
1103c896fe29Sbellard     ts->fixed_reg = 1;
1104c896fe29Sbellard     ts->reg = reg;
1105c896fe29Sbellard     ts->name = name;
1106c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
11077ca4b752SRichard Henderson 
1108085272b3SRichard Henderson     return ts;
1109a7812ae4Spbrook }
1110a7812ae4Spbrook 
1111b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1112a7812ae4Spbrook {
1113b3a62939SRichard Henderson     s->frame_start = start;
1114b3a62939SRichard Henderson     s->frame_end = start + size;
1115085272b3SRichard Henderson     s->frame_temp
1116085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1117b3a62939SRichard Henderson }
1118a7812ae4Spbrook 
1119085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
1120e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
1121c896fe29Sbellard {
1122b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1123dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
11247ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1125b3915dbbSRichard Henderson     int indirect_reg = 0, bigendian = 0;
11267ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
11277ca4b752SRichard Henderson     bigendian = 1;
11287ca4b752SRichard Henderson #endif
1129c896fe29Sbellard 
1130b3915dbbSRichard Henderson     if (!base_ts->fixed_reg) {
11315a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
11325a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1133b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
11345a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
11355a18407fSRichard Henderson                             ? 2 : 1);
11365a18407fSRichard Henderson         indirect_reg = 1;
1137b3915dbbSRichard Henderson     }
1138b3915dbbSRichard Henderson 
11397ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
11407ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1141c896fe29Sbellard         char buf[64];
11427ca4b752SRichard Henderson 
11437ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1144c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1145b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1146c896fe29Sbellard         ts->mem_allocated = 1;
1147b3a62939SRichard Henderson         ts->mem_base = base_ts;
11487ca4b752SRichard Henderson         ts->mem_offset = offset + bigendian * 4;
1149c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1150c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1151c896fe29Sbellard         ts->name = strdup(buf);
1152c896fe29Sbellard 
11537ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
11547ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
11557ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1156b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
11577ca4b752SRichard Henderson         ts2->mem_allocated = 1;
11587ca4b752SRichard Henderson         ts2->mem_base = base_ts;
11597ca4b752SRichard Henderson         ts2->mem_offset = offset + (1 - bigendian) * 4;
1160c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1161c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1162120c1084SRichard Henderson         ts2->name = strdup(buf);
11637ca4b752SRichard Henderson     } else {
1164c896fe29Sbellard         ts->base_type = type;
1165c896fe29Sbellard         ts->type = type;
1166b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1167c896fe29Sbellard         ts->mem_allocated = 1;
1168b3a62939SRichard Henderson         ts->mem_base = base_ts;
1169c896fe29Sbellard         ts->mem_offset = offset;
1170c896fe29Sbellard         ts->name = name;
1171c896fe29Sbellard     }
1172085272b3SRichard Henderson     return ts;
1173c896fe29Sbellard }
1174c896fe29Sbellard 
11755bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local)
1176c896fe29Sbellard {
1177b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1178c896fe29Sbellard     TCGTemp *ts;
1179641d5fbeSbellard     int idx, k;
1180c896fe29Sbellard 
11810ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
11820ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
11830ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
11840ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
11850ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
11860ec9eabcSRichard Henderson 
1187e8996ee0Sbellard         ts = &s->temps[idx];
1188e8996ee0Sbellard         ts->temp_allocated = 1;
11897ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
11907ca4b752SRichard Henderson         tcg_debug_assert(ts->temp_local == temp_local);
1191e8996ee0Sbellard     } else {
11927ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
11937ca4b752SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
11947ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
11957ca4b752SRichard Henderson 
1196c896fe29Sbellard             ts->base_type = type;
1197c896fe29Sbellard             ts->type = TCG_TYPE_I32;
1198e8996ee0Sbellard             ts->temp_allocated = 1;
1199641d5fbeSbellard             ts->temp_local = temp_local;
12007ca4b752SRichard Henderson 
12017ca4b752SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
12027ca4b752SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
12037ca4b752SRichard Henderson             ts2->type = TCG_TYPE_I32;
12047ca4b752SRichard Henderson             ts2->temp_allocated = 1;
12057ca4b752SRichard Henderson             ts2->temp_local = temp_local;
12067ca4b752SRichard Henderson         } else {
1207c896fe29Sbellard             ts->base_type = type;
1208c896fe29Sbellard             ts->type = type;
1209e8996ee0Sbellard             ts->temp_allocated = 1;
1210641d5fbeSbellard             ts->temp_local = temp_local;
1211c896fe29Sbellard         }
1212e8996ee0Sbellard     }
121327bfd83cSPeter Maydell 
121427bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
121527bfd83cSPeter Maydell     s->temps_in_use++;
121627bfd83cSPeter Maydell #endif
1217085272b3SRichard Henderson     return ts;
1218c896fe29Sbellard }
1219c896fe29Sbellard 
1220d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1221d2fd745fSRichard Henderson {
1222d2fd745fSRichard Henderson     TCGTemp *t;
1223d2fd745fSRichard Henderson 
1224d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1225d2fd745fSRichard Henderson     switch (type) {
1226d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1227d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1228d2fd745fSRichard Henderson         break;
1229d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1230d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1231d2fd745fSRichard Henderson         break;
1232d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1233d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1234d2fd745fSRichard Henderson         break;
1235d2fd745fSRichard Henderson     default:
1236d2fd745fSRichard Henderson         g_assert_not_reached();
1237d2fd745fSRichard Henderson     }
1238d2fd745fSRichard Henderson #endif
1239d2fd745fSRichard Henderson 
1240d2fd745fSRichard Henderson     t = tcg_temp_new_internal(type, 0);
1241d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1242d2fd745fSRichard Henderson }
1243d2fd745fSRichard Henderson 
1244d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1245d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1246d2fd745fSRichard Henderson {
1247d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1248d2fd745fSRichard Henderson 
1249d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1250d2fd745fSRichard Henderson 
1251d2fd745fSRichard Henderson     t = tcg_temp_new_internal(t->base_type, 0);
1252d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1253d2fd745fSRichard Henderson }
1254d2fd745fSRichard Henderson 
12555bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1256c896fe29Sbellard {
1257b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1258085272b3SRichard Henderson     int k, idx;
1259c896fe29Sbellard 
126027bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
126127bfd83cSPeter Maydell     s->temps_in_use--;
126227bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
126327bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
126427bfd83cSPeter Maydell     }
126527bfd83cSPeter Maydell #endif
126627bfd83cSPeter Maydell 
1267085272b3SRichard Henderson     tcg_debug_assert(ts->temp_global == 0);
1268eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
1269e8996ee0Sbellard     ts->temp_allocated = 0;
12700ec9eabcSRichard Henderson 
1271085272b3SRichard Henderson     idx = temp_idx(ts);
127218d13fa2SAlexander Graf     k = ts->base_type + (ts->temp_local ? TCG_TYPE_COUNT : 0);
12730ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
1274e8996ee0Sbellard }
1275e8996ee0Sbellard 
1276a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
1277a7812ae4Spbrook {
1278a7812ae4Spbrook     TCGv_i32 t0;
1279a7812ae4Spbrook     t0 = tcg_temp_new_i32();
1280e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
1281e8996ee0Sbellard     return t0;
1282c896fe29Sbellard }
1283c896fe29Sbellard 
1284a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
1285c896fe29Sbellard {
1286a7812ae4Spbrook     TCGv_i64 t0;
1287a7812ae4Spbrook     t0 = tcg_temp_new_i64();
1288e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
1289e8996ee0Sbellard     return t0;
1290c896fe29Sbellard }
1291c896fe29Sbellard 
1292a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
1293bdffd4a9Saurel32 {
1294a7812ae4Spbrook     TCGv_i32 t0;
1295a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
1296bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
1297bdffd4a9Saurel32     return t0;
1298bdffd4a9Saurel32 }
1299bdffd4a9Saurel32 
1300a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
1301bdffd4a9Saurel32 {
1302a7812ae4Spbrook     TCGv_i64 t0;
1303a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
1304bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
1305bdffd4a9Saurel32     return t0;
1306bdffd4a9Saurel32 }
1307bdffd4a9Saurel32 
130827bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
130927bfd83cSPeter Maydell void tcg_clear_temp_count(void)
131027bfd83cSPeter Maydell {
1311b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
131227bfd83cSPeter Maydell     s->temps_in_use = 0;
131327bfd83cSPeter Maydell }
131427bfd83cSPeter Maydell 
131527bfd83cSPeter Maydell int tcg_check_temp_count(void)
131627bfd83cSPeter Maydell {
1317b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
131827bfd83cSPeter Maydell     if (s->temps_in_use) {
131927bfd83cSPeter Maydell         /* Clear the count so that we don't give another
132027bfd83cSPeter Maydell          * warning immediately next time around.
132127bfd83cSPeter Maydell          */
132227bfd83cSPeter Maydell         s->temps_in_use = 0;
132327bfd83cSPeter Maydell         return 1;
132427bfd83cSPeter Maydell     }
132527bfd83cSPeter Maydell     return 0;
132627bfd83cSPeter Maydell }
132727bfd83cSPeter Maydell #endif
132827bfd83cSPeter Maydell 
1329be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1330be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1331be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1332be0f34b5SRichard Henderson {
1333d2fd745fSRichard Henderson     const bool have_vec
1334d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1335d2fd745fSRichard Henderson 
1336be0f34b5SRichard Henderson     switch (op) {
1337be0f34b5SRichard Henderson     case INDEX_op_discard:
1338be0f34b5SRichard Henderson     case INDEX_op_set_label:
1339be0f34b5SRichard Henderson     case INDEX_op_call:
1340be0f34b5SRichard Henderson     case INDEX_op_br:
1341be0f34b5SRichard Henderson     case INDEX_op_mb:
1342be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1343be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1344be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1345be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i32:
1346be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i32:
1347be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i64:
1348be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i64:
1349be0f34b5SRichard Henderson         return true;
1350be0f34b5SRichard Henderson 
1351be0f34b5SRichard Henderson     case INDEX_op_goto_ptr:
1352be0f34b5SRichard Henderson         return TCG_TARGET_HAS_goto_ptr;
1353be0f34b5SRichard Henderson 
1354be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1355be0f34b5SRichard Henderson     case INDEX_op_movi_i32:
1356be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1357be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1358be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1359be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1360be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1361be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1362be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1363be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1364be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1365be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1366be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1367be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1368be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1369be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1370be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1371be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1372be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1373be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1374be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1375be0f34b5SRichard Henderson         return true;
1376be0f34b5SRichard Henderson 
1377be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1378be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1379be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1380be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1381be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1382be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1383be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1384be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1385be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1386be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1387be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1388be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1389be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1390be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1391be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1392be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1393be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1394be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1395be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1396be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1397be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1398be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1399be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1400be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1401be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1402be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1403be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1404be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1405be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1406be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1407be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1408be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1409be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1410be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1411be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1412be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1413be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1414be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1415be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1416be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1417be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1418be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1419be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1420be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1421be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1422be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1423be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1424be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1425be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1426be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1427be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1428be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1429be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1430be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1431be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1432be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1433be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1434be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1435be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1436be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1437be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1438be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1439be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1440be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1441be0f34b5SRichard Henderson 
1442be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1443be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1444be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1445be0f34b5SRichard Henderson 
1446be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1447be0f34b5SRichard Henderson     case INDEX_op_movi_i64:
1448be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1449be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1450be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1451be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1452be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1453be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1454be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1455be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1456be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1457be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1458be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1459be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1460be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1461be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1462be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1463be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1464be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1465be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1466be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1467be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1468be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1469be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1470be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1471be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1472be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1473be0f34b5SRichard Henderson 
1474be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1475be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1476be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1477be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1478be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1479be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1480be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1481be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1482be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1483be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
1484be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
1485be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
1486be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
1487be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
1488be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
1489be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
1490be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
1491be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
1492be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
1493be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
1494be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
1495be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrl_i64_i32;
1496be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
1497be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrh_i64_i32;
1498be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
1499be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
1500be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
1501be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
1502be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
1503be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
1504be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
1505be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
1506be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
1507be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
1508be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
1509be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
1510be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
1511be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
1512be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
1513be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
1514be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
1515be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
1516be0f34b5SRichard Henderson     case INDEX_op_not_i64:
1517be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
1518be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
1519be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
1520be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
1521be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
1522be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
1523be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
1524be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
1525be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
1526be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
1527be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
1528be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
1529be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
1530be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
1531be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
1532be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
1533be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
1534be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
1535be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
1536be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
1537be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
1538be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
1539be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
1540be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
1541be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
1542be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
1543be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
1544be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
1545be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
1546be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
1547be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
1548be0f34b5SRichard Henderson 
1549d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
1550d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
1551d2fd745fSRichard Henderson     case INDEX_op_dupi_vec:
1552d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
1553d2fd745fSRichard Henderson     case INDEX_op_st_vec:
1554d2fd745fSRichard Henderson     case INDEX_op_add_vec:
1555d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
1556d2fd745fSRichard Henderson     case INDEX_op_and_vec:
1557d2fd745fSRichard Henderson     case INDEX_op_or_vec:
1558d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
1559212be173SRichard Henderson     case INDEX_op_cmp_vec:
1560d2fd745fSRichard Henderson         return have_vec;
1561d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
1562d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
1563d2fd745fSRichard Henderson     case INDEX_op_not_vec:
1564d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
1565d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
1566d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
1567d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
1568d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
1569d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
1570d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
15713774030aSRichard Henderson     case INDEX_op_mul_vec:
15723774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
1573d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
1574d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
1575d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
1576d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
1577d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
1578d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
1579d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
1580d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
1581d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
1582d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
1583d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
1584d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
1585d2fd745fSRichard Henderson 
1586db432672SRichard Henderson     default:
1587db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
1588db432672SRichard Henderson         return true;
1589be0f34b5SRichard Henderson     }
1590be0f34b5SRichard Henderson }
1591be0f34b5SRichard Henderson 
159239cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment
159339cf05d3Sbellard    and endian swap. Maybe it would be better to do the alignment
159439cf05d3Sbellard    and endian swap in tcg_reg_alloc_call(). */
1595ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
1596c896fe29Sbellard {
159775e8b9b7SRichard Henderson     int i, real_args, nb_rets, pi;
1598bbb8a1b4SRichard Henderson     unsigned sizemask, flags;
1599afb49896SRichard Henderson     TCGHelperInfo *info;
160075e8b9b7SRichard Henderson     TCGOp *op;
1601afb49896SRichard Henderson 
1602619205fdSEmilio G. Cota     info = g_hash_table_lookup(helper_table, (gpointer)func);
1603bbb8a1b4SRichard Henderson     flags = info->flags;
1604bbb8a1b4SRichard Henderson     sizemask = info->sizemask;
16052bece2c8SRichard Henderson 
160634b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
160734b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
160834b1a49cSRichard Henderson     /* We have 64-bit values in one register, but need to pass as two
160934b1a49cSRichard Henderson        separate parameters.  Split them.  */
161034b1a49cSRichard Henderson     int orig_sizemask = sizemask;
161134b1a49cSRichard Henderson     int orig_nargs = nargs;
161234b1a49cSRichard Henderson     TCGv_i64 retl, reth;
1613ae8b75dcSRichard Henderson     TCGTemp *split_args[MAX_OPC_PARAM];
161434b1a49cSRichard Henderson 
1615f764718dSRichard Henderson     retl = NULL;
1616f764718dSRichard Henderson     reth = NULL;
161734b1a49cSRichard Henderson     if (sizemask != 0) {
161834b1a49cSRichard Henderson         for (i = real_args = 0; i < nargs; ++i) {
161934b1a49cSRichard Henderson             int is_64bit = sizemask & (1 << (i+1)*2);
162034b1a49cSRichard Henderson             if (is_64bit) {
1621085272b3SRichard Henderson                 TCGv_i64 orig = temp_tcgv_i64(args[i]);
162234b1a49cSRichard Henderson                 TCGv_i32 h = tcg_temp_new_i32();
162334b1a49cSRichard Henderson                 TCGv_i32 l = tcg_temp_new_i32();
162434b1a49cSRichard Henderson                 tcg_gen_extr_i64_i32(l, h, orig);
1625ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(h);
1626ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(l);
162734b1a49cSRichard Henderson             } else {
162834b1a49cSRichard Henderson                 split_args[real_args++] = args[i];
162934b1a49cSRichard Henderson             }
163034b1a49cSRichard Henderson         }
163134b1a49cSRichard Henderson         nargs = real_args;
163234b1a49cSRichard Henderson         args = split_args;
163334b1a49cSRichard Henderson         sizemask = 0;
163434b1a49cSRichard Henderson     }
163534b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
16362bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
16372bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
16382bece2c8SRichard Henderson         int is_signed = sizemask & (2 << (i+1)*2);
16392bece2c8SRichard Henderson         if (!is_64bit) {
16402bece2c8SRichard Henderson             TCGv_i64 temp = tcg_temp_new_i64();
1641085272b3SRichard Henderson             TCGv_i64 orig = temp_tcgv_i64(args[i]);
16422bece2c8SRichard Henderson             if (is_signed) {
16432bece2c8SRichard Henderson                 tcg_gen_ext32s_i64(temp, orig);
16442bece2c8SRichard Henderson             } else {
16452bece2c8SRichard Henderson                 tcg_gen_ext32u_i64(temp, orig);
16462bece2c8SRichard Henderson             }
1647ae8b75dcSRichard Henderson             args[i] = tcgv_i64_temp(temp);
16482bece2c8SRichard Henderson         }
16492bece2c8SRichard Henderson     }
16502bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
16512bece2c8SRichard Henderson 
165215fa08f8SRichard Henderson     op = tcg_emit_op(INDEX_op_call);
165375e8b9b7SRichard Henderson 
165475e8b9b7SRichard Henderson     pi = 0;
1655ae8b75dcSRichard Henderson     if (ret != NULL) {
165634b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
165734b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
165834b1a49cSRichard Henderson         if (orig_sizemask & 1) {
165934b1a49cSRichard Henderson             /* The 32-bit ABI is going to return the 64-bit value in
166034b1a49cSRichard Henderson                the %o0/%o1 register pair.  Prepare for this by using
166134b1a49cSRichard Henderson                two return temporaries, and reassemble below.  */
166234b1a49cSRichard Henderson             retl = tcg_temp_new_i64();
166334b1a49cSRichard Henderson             reth = tcg_temp_new_i64();
1664ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(reth);
1665ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(retl);
166634b1a49cSRichard Henderson             nb_rets = 2;
166734b1a49cSRichard Henderson         } else {
1668ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
166934b1a49cSRichard Henderson             nb_rets = 1;
167034b1a49cSRichard Henderson         }
167134b1a49cSRichard Henderson #else
167234b1a49cSRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) {
167302eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
1674ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1675ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1676a7812ae4Spbrook #else
1677ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1678ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1679a7812ae4Spbrook #endif
1680a7812ae4Spbrook             nb_rets = 2;
168134b1a49cSRichard Henderson         } else {
1682ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1683a7812ae4Spbrook             nb_rets = 1;
1684a7812ae4Spbrook         }
168534b1a49cSRichard Henderson #endif
1686a7812ae4Spbrook     } else {
1687a7812ae4Spbrook         nb_rets = 0;
1688a7812ae4Spbrook     }
1689cd9090aaSRichard Henderson     TCGOP_CALLO(op) = nb_rets;
169075e8b9b7SRichard Henderson 
1691a7812ae4Spbrook     real_args = 0;
1692a7812ae4Spbrook     for (i = 0; i < nargs; i++) {
16932bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
1694bbb8a1b4SRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
169539cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS
169639cf05d3Sbellard             /* some targets want aligned 64 bit args */
1697ebd486d5Smalc             if (real_args & 1) {
169875e8b9b7SRichard Henderson                 op->args[pi++] = TCG_CALL_DUMMY_ARG;
1699ebd486d5Smalc                 real_args++;
170039cf05d3Sbellard             }
170139cf05d3Sbellard #endif
17023f90f252SRichard Henderson            /* If stack grows up, then we will be placing successive
17033f90f252SRichard Henderson               arguments at lower addresses, which means we need to
17043f90f252SRichard Henderson               reverse the order compared to how we would normally
17053f90f252SRichard Henderson               treat either big or little-endian.  For those arguments
17063f90f252SRichard Henderson               that will wind up in registers, this still works for
17073f90f252SRichard Henderson               HPPA (the only current STACK_GROWSUP target) since the
17083f90f252SRichard Henderson               argument registers are *also* allocated in decreasing
17093f90f252SRichard Henderson               order.  If another such target is added, this logic may
17103f90f252SRichard Henderson               have to get more complicated to differentiate between
17113f90f252SRichard Henderson               stack arguments and register arguments.  */
171202eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
1713ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1714ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1715c896fe29Sbellard #else
1716ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1717ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1718c896fe29Sbellard #endif
1719a7812ae4Spbrook             real_args += 2;
17202bece2c8SRichard Henderson             continue;
17212bece2c8SRichard Henderson         }
17222bece2c8SRichard Henderson 
1723ae8b75dcSRichard Henderson         op->args[pi++] = temp_arg(args[i]);
1724a7812ae4Spbrook         real_args++;
1725c896fe29Sbellard     }
172675e8b9b7SRichard Henderson     op->args[pi++] = (uintptr_t)func;
172775e8b9b7SRichard Henderson     op->args[pi++] = flags;
1728cd9090aaSRichard Henderson     TCGOP_CALLI(op) = real_args;
1729a7812ae4Spbrook 
173075e8b9b7SRichard Henderson     /* Make sure the fields didn't overflow.  */
1731cd9090aaSRichard Henderson     tcg_debug_assert(TCGOP_CALLI(op) == real_args);
173275e8b9b7SRichard Henderson     tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
17332bece2c8SRichard Henderson 
173434b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
173534b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
173634b1a49cSRichard Henderson     /* Free all of the parts we allocated above.  */
173734b1a49cSRichard Henderson     for (i = real_args = 0; i < orig_nargs; ++i) {
173834b1a49cSRichard Henderson         int is_64bit = orig_sizemask & (1 << (i+1)*2);
173934b1a49cSRichard Henderson         if (is_64bit) {
1740085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
1741085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
174234b1a49cSRichard Henderson         } else {
174334b1a49cSRichard Henderson             real_args++;
174434b1a49cSRichard Henderson         }
174534b1a49cSRichard Henderson     }
174634b1a49cSRichard Henderson     if (orig_sizemask & 1) {
174734b1a49cSRichard Henderson         /* The 32-bit ABI returned two 32-bit pieces.  Re-assemble them.
174834b1a49cSRichard Henderson            Note that describing these as TCGv_i64 eliminates an unnecessary
174934b1a49cSRichard Henderson            zero-extension that tcg_gen_concat_i32_i64 would create.  */
1750085272b3SRichard Henderson         tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth);
175134b1a49cSRichard Henderson         tcg_temp_free_i64(retl);
175234b1a49cSRichard Henderson         tcg_temp_free_i64(reth);
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         if (!is_64bit) {
1758085272b3SRichard Henderson             tcg_temp_free_internal(args[i]);
17592bece2c8SRichard Henderson         }
17602bece2c8SRichard Henderson     }
17612bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
1762a7812ae4Spbrook }
1763c896fe29Sbellard 
17648fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
1765c896fe29Sbellard {
1766ac3b8891SRichard Henderson     int i, n;
1767c896fe29Sbellard     TCGTemp *ts;
1768ac3b8891SRichard Henderson 
1769ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
1770c896fe29Sbellard         ts = &s->temps[i];
1771ac3b8891SRichard Henderson         ts->val_type = (ts->fixed_reg ? TEMP_VAL_REG : TEMP_VAL_MEM);
1772c896fe29Sbellard     }
1773ac3b8891SRichard Henderson     for (n = s->nb_temps; i < n; i++) {
1774e8996ee0Sbellard         ts = &s->temps[i];
1775ac3b8891SRichard Henderson         ts->val_type = (ts->temp_local ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
1776e8996ee0Sbellard         ts->mem_allocated = 0;
1777e8996ee0Sbellard         ts->fixed_reg = 0;
1778e8996ee0Sbellard     }
1779f8b2f202SRichard Henderson 
1780f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
1781c896fe29Sbellard }
1782c896fe29Sbellard 
1783f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
1784f8b2f202SRichard Henderson                                  TCGTemp *ts)
1785c896fe29Sbellard {
17861807f4c4SRichard Henderson     int idx = temp_idx(ts);
1787ac56dd48Spbrook 
1788fa477d25SRichard Henderson     if (ts->temp_global) {
1789ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
1790f8b2f202SRichard Henderson     } else if (ts->temp_local) {
1791641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
1792f8b2f202SRichard Henderson     } else {
1793ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
1794c896fe29Sbellard     }
1795c896fe29Sbellard     return buf;
1796c896fe29Sbellard }
1797c896fe29Sbellard 
179843439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
179943439139SRichard Henderson                              int buf_size, TCGArg arg)
1800f8b2f202SRichard Henderson {
180143439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
1802f8b2f202SRichard Henderson }
1803f8b2f202SRichard Henderson 
18046e085f72SRichard Henderson /* Find helper name.  */
18056e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val)
1806e8996ee0Sbellard {
18076e085f72SRichard Henderson     const char *ret = NULL;
1808619205fdSEmilio G. Cota     if (helper_table) {
1809619205fdSEmilio G. Cota         TCGHelperInfo *info = g_hash_table_lookup(helper_table, (gpointer)val);
181072866e82SRichard Henderson         if (info) {
181172866e82SRichard Henderson             ret = info->name;
181272866e82SRichard Henderson         }
1813e8996ee0Sbellard     }
18146e085f72SRichard Henderson     return ret;
18154dc81f28Sbellard }
18164dc81f28Sbellard 
1817f48f3edeSblueswir1 static const char * const cond_name[] =
1818f48f3edeSblueswir1 {
18190aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
18200aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
1821f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
1822f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
1823f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
1824f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
1825f48f3edeSblueswir1     [TCG_COND_LE] = "le",
1826f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
1827f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
1828f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
1829f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
1830f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
1831f48f3edeSblueswir1 };
1832f48f3edeSblueswir1 
1833f713d6adSRichard Henderson static const char * const ldst_name[] =
1834f713d6adSRichard Henderson {
1835f713d6adSRichard Henderson     [MO_UB]   = "ub",
1836f713d6adSRichard Henderson     [MO_SB]   = "sb",
1837f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
1838f713d6adSRichard Henderson     [MO_LESW] = "lesw",
1839f713d6adSRichard Henderson     [MO_LEUL] = "leul",
1840f713d6adSRichard Henderson     [MO_LESL] = "lesl",
1841f713d6adSRichard Henderson     [MO_LEQ]  = "leq",
1842f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
1843f713d6adSRichard Henderson     [MO_BESW] = "besw",
1844f713d6adSRichard Henderson     [MO_BEUL] = "beul",
1845f713d6adSRichard Henderson     [MO_BESL] = "besl",
1846f713d6adSRichard Henderson     [MO_BEQ]  = "beq",
1847f713d6adSRichard Henderson };
1848f713d6adSRichard Henderson 
18491f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
18501f00b27fSSergey Sorokin #ifdef ALIGNED_ONLY
18511f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
18521f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
18531f00b27fSSergey Sorokin #else
18541f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
18551f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
18561f00b27fSSergey Sorokin #endif
18571f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
18581f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
18591f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
18601f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
18611f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
18621f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
18631f00b27fSSergey Sorokin };
18641f00b27fSSergey Sorokin 
1865eeacee4dSBlue Swirl void tcg_dump_ops(TCGContext *s)
1866c896fe29Sbellard {
1867c896fe29Sbellard     char buf[128];
1868c45cb8bbSRichard Henderson     TCGOp *op;
1869c896fe29Sbellard 
187015fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
1871c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
1872c45cb8bbSRichard Henderson         const TCGOpDef *def;
1873c45cb8bbSRichard Henderson         TCGOpcode c;
1874bdfb460eSRichard Henderson         int col = 0;
1875c45cb8bbSRichard Henderson 
1876c45cb8bbSRichard Henderson         c = op->opc;
1877c896fe29Sbellard         def = &tcg_op_defs[c];
1878c45cb8bbSRichard Henderson 
1879765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
188015fa08f8SRichard Henderson             col += qemu_log("\n ----");
18819aef40edSRichard Henderson 
18829aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
18839aef40edSRichard Henderson                 target_ulong a;
18847e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
1885efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
18867e4597d7Sbellard #else
1887efee3746SRichard Henderson                 a = op->args[i];
18887e4597d7Sbellard #endif
1889bdfb460eSRichard Henderson                 col += qemu_log(" " TARGET_FMT_lx, a);
1890eeacee4dSBlue Swirl             }
18917e4597d7Sbellard         } else if (c == INDEX_op_call) {
1892c896fe29Sbellard             /* variable number of arguments */
1893cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
1894cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
1895c896fe29Sbellard             nb_cargs = def->nb_cargs;
1896b03cce8eSbellard 
1897cf066674SRichard Henderson             /* function name, flags, out args */
1898bdfb460eSRichard Henderson             col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name,
1899efee3746SRichard Henderson                             tcg_find_helper(s, op->args[nb_oargs + nb_iargs]),
1900efee3746SRichard Henderson                             op->args[nb_oargs + nb_iargs + 1], nb_oargs);
1901b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
190243439139SRichard Henderson                 col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf),
1903efee3746SRichard Henderson                                                        op->args[i]));
1904b03cce8eSbellard             }
1905cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
1906efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
1907cf066674SRichard Henderson                 const char *t = "<dummy>";
1908cf066674SRichard Henderson                 if (arg != TCG_CALL_DUMMY_ARG) {
190943439139SRichard Henderson                     t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
1910b03cce8eSbellard                 }
1911bdfb460eSRichard Henderson                 col += qemu_log(",%s", t);
1912e8996ee0Sbellard             }
1913b03cce8eSbellard         } else {
1914bdfb460eSRichard Henderson             col += qemu_log(" %s ", def->name);
1915c45cb8bbSRichard Henderson 
1916c896fe29Sbellard             nb_oargs = def->nb_oargs;
1917c896fe29Sbellard             nb_iargs = def->nb_iargs;
1918c896fe29Sbellard             nb_cargs = def->nb_cargs;
1919c896fe29Sbellard 
1920d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
1921d2fd745fSRichard Henderson                 col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op),
1922d2fd745fSRichard Henderson                                 8 << TCGOP_VECE(op));
1923d2fd745fSRichard Henderson             }
1924d2fd745fSRichard Henderson 
1925c896fe29Sbellard             k = 0;
1926c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
1927eeacee4dSBlue Swirl                 if (k != 0) {
1928bdfb460eSRichard Henderson                     col += qemu_log(",");
1929eeacee4dSBlue Swirl                 }
193043439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
1931efee3746SRichard Henderson                                                       op->args[k++]));
1932c896fe29Sbellard             }
1933c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
1934eeacee4dSBlue Swirl                 if (k != 0) {
1935bdfb460eSRichard Henderson                     col += qemu_log(",");
1936eeacee4dSBlue Swirl                 }
193743439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
1938efee3746SRichard Henderson                                                       op->args[k++]));
1939c896fe29Sbellard             }
1940be210acbSRichard Henderson             switch (c) {
1941be210acbSRichard Henderson             case INDEX_op_brcond_i32:
1942ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
1943ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
1944be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
1945be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
1946ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
1947be210acbSRichard Henderson             case INDEX_op_setcond_i64:
1948ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
1949212be173SRichard Henderson             case INDEX_op_cmp_vec:
1950efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
1951efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
1952efee3746SRichard Henderson                     col += qemu_log(",%s", cond_name[op->args[k++]]);
1953eeacee4dSBlue Swirl                 } else {
1954efee3746SRichard Henderson                     col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]);
1955eeacee4dSBlue Swirl                 }
1956f48f3edeSblueswir1                 i = 1;
1957be210acbSRichard Henderson                 break;
1958f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
1959f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
1960f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
1961f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
196259227d5dSRichard Henderson                 {
1963efee3746SRichard Henderson                     TCGMemOpIdx oi = op->args[k++];
196459227d5dSRichard Henderson                     TCGMemOp op = get_memop(oi);
196559227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
196659227d5dSRichard Henderson 
196759c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
1968bdfb460eSRichard Henderson                         col += qemu_log(",$0x%x,%u", op, ix);
196959c4b7e8SRichard Henderson                     } else {
19701f00b27fSSergey Sorokin                         const char *s_al, *s_op;
19711f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
197259c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
1973bdfb460eSRichard Henderson                         col += qemu_log(",%s%s,%u", s_al, s_op, ix);
1974f713d6adSRichard Henderson                     }
1975f713d6adSRichard Henderson                     i = 1;
197659227d5dSRichard Henderson                 }
1977f713d6adSRichard Henderson                 break;
1978be210acbSRichard Henderson             default:
1979f48f3edeSblueswir1                 i = 0;
1980be210acbSRichard Henderson                 break;
1981be210acbSRichard Henderson             }
198251e3972cSRichard Henderson             switch (c) {
198351e3972cSRichard Henderson             case INDEX_op_set_label:
198451e3972cSRichard Henderson             case INDEX_op_br:
198551e3972cSRichard Henderson             case INDEX_op_brcond_i32:
198651e3972cSRichard Henderson             case INDEX_op_brcond_i64:
198751e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
1988efee3746SRichard Henderson                 col += qemu_log("%s$L%d", k ? "," : "",
1989efee3746SRichard Henderson                                 arg_label(op->args[k])->id);
199051e3972cSRichard Henderson                 i++, k++;
199151e3972cSRichard Henderson                 break;
199251e3972cSRichard Henderson             default:
199351e3972cSRichard Henderson                 break;
1994eeacee4dSBlue Swirl             }
199551e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
1996efee3746SRichard Henderson                 col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]);
1997bdfb460eSRichard Henderson             }
1998bdfb460eSRichard Henderson         }
1999bdfb460eSRichard Henderson         if (op->life) {
2000bdfb460eSRichard Henderson             unsigned life = op->life;
2001bdfb460eSRichard Henderson 
2002bdfb460eSRichard Henderson             for (; col < 48; ++col) {
2003bdfb460eSRichard Henderson                 putc(' ', qemu_logfile);
2004bdfb460eSRichard Henderson             }
2005bdfb460eSRichard Henderson 
2006bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
2007bdfb460eSRichard Henderson                 qemu_log("  sync:");
2008bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
2009bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
2010bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2011bdfb460eSRichard Henderson                     }
2012bdfb460eSRichard Henderson                 }
2013bdfb460eSRichard Henderson             }
2014bdfb460eSRichard Henderson             life /= DEAD_ARG;
2015bdfb460eSRichard Henderson             if (life) {
2016bdfb460eSRichard Henderson                 qemu_log("  dead:");
2017bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
2018bdfb460eSRichard Henderson                     if (life & 1) {
2019bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2020bdfb460eSRichard Henderson                     }
2021bdfb460eSRichard Henderson                 }
2022c896fe29Sbellard             }
2023b03cce8eSbellard         }
2024eeacee4dSBlue Swirl         qemu_log("\n");
2025c896fe29Sbellard     }
2026c896fe29Sbellard }
2027c896fe29Sbellard 
2028c896fe29Sbellard /* we give more priority to constraints with less registers */
2029c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2030c896fe29Sbellard {
2031c896fe29Sbellard     const TCGArgConstraint *arg_ct;
2032c896fe29Sbellard 
2033c896fe29Sbellard     int i, n;
2034c896fe29Sbellard     arg_ct = &def->args_ct[k];
2035c896fe29Sbellard     if (arg_ct->ct & TCG_CT_ALIAS) {
2036c896fe29Sbellard         /* an alias is equivalent to a single register */
2037c896fe29Sbellard         n = 1;
2038c896fe29Sbellard     } else {
2039c896fe29Sbellard         if (!(arg_ct->ct & TCG_CT_REG))
2040c896fe29Sbellard             return 0;
2041c896fe29Sbellard         n = 0;
2042c896fe29Sbellard         for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
2043c896fe29Sbellard             if (tcg_regset_test_reg(arg_ct->u.regs, i))
2044c896fe29Sbellard                 n++;
2045c896fe29Sbellard         }
2046c896fe29Sbellard     }
2047c896fe29Sbellard     return TCG_TARGET_NB_REGS - n + 1;
2048c896fe29Sbellard }
2049c896fe29Sbellard 
2050c896fe29Sbellard /* sort from highest priority to lowest */
2051c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2052c896fe29Sbellard {
2053c896fe29Sbellard     int i, j, p1, p2, tmp;
2054c896fe29Sbellard 
2055c896fe29Sbellard     for(i = 0; i < n; i++)
2056c896fe29Sbellard         def->sorted_args[start + i] = start + i;
2057c896fe29Sbellard     if (n <= 1)
2058c896fe29Sbellard         return;
2059c896fe29Sbellard     for(i = 0; i < n - 1; i++) {
2060c896fe29Sbellard         for(j = i + 1; j < n; j++) {
2061c896fe29Sbellard             p1 = get_constraint_priority(def, def->sorted_args[start + i]);
2062c896fe29Sbellard             p2 = get_constraint_priority(def, def->sorted_args[start + j]);
2063c896fe29Sbellard             if (p1 < p2) {
2064c896fe29Sbellard                 tmp = def->sorted_args[start + i];
2065c896fe29Sbellard                 def->sorted_args[start + i] = def->sorted_args[start + j];
2066c896fe29Sbellard                 def->sorted_args[start + j] = tmp;
2067c896fe29Sbellard             }
2068c896fe29Sbellard         }
2069c896fe29Sbellard     }
2070c896fe29Sbellard }
2071c896fe29Sbellard 
2072f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2073c896fe29Sbellard {
2074a9751609SRichard Henderson     TCGOpcode op;
2075c896fe29Sbellard 
2076f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
2077f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
2078f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
2079069ea736SRichard Henderson         TCGType type;
2080069ea736SRichard Henderson         int i, nb_args;
2081f69d277eSRichard Henderson 
2082f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
2083f69d277eSRichard Henderson             continue;
2084f69d277eSRichard Henderson         }
2085f69d277eSRichard Henderson 
2086c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
2087f69d277eSRichard Henderson         if (nb_args == 0) {
2088f69d277eSRichard Henderson             continue;
2089f69d277eSRichard Henderson         }
2090f69d277eSRichard Henderson 
2091f69d277eSRichard Henderson         tdefs = tcg_target_op_def(op);
2092f69d277eSRichard Henderson         /* Missing TCGTargetOpDef entry. */
2093f69d277eSRichard Henderson         tcg_debug_assert(tdefs != NULL);
2094f69d277eSRichard Henderson 
2095069ea736SRichard Henderson         type = (def->flags & TCG_OPF_64BIT ? TCG_TYPE_I64 : TCG_TYPE_I32);
2096c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2097f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
2098f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2099eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2100f69d277eSRichard Henderson 
2101ccb1bb66SRichard Henderson             def->args_ct[i].u.regs = 0;
2102c896fe29Sbellard             def->args_ct[i].ct = 0;
210317280ff4SRichard Henderson             while (*ct_str != '\0') {
210417280ff4SRichard Henderson                 switch(*ct_str) {
210517280ff4SRichard Henderson                 case '0' ... '9':
210617280ff4SRichard Henderson                     {
210717280ff4SRichard Henderson                         int oarg = *ct_str - '0';
210817280ff4SRichard Henderson                         tcg_debug_assert(ct_str == tdefs->args_ct_str[i]);
2109eabb7b91SAurelien Jarno                         tcg_debug_assert(oarg < def->nb_oargs);
2110eabb7b91SAurelien Jarno                         tcg_debug_assert(def->args_ct[oarg].ct & TCG_CT_REG);
211117280ff4SRichard Henderson                         /* TCG_CT_ALIAS is for the output arguments.
211217280ff4SRichard Henderson                            The input is tagged with TCG_CT_IALIAS. */
2113c896fe29Sbellard                         def->args_ct[i] = def->args_ct[oarg];
211417280ff4SRichard Henderson                         def->args_ct[oarg].ct |= TCG_CT_ALIAS;
21155ff9d6a4Sbellard                         def->args_ct[oarg].alias_index = i;
2116c896fe29Sbellard                         def->args_ct[i].ct |= TCG_CT_IALIAS;
21175ff9d6a4Sbellard                         def->args_ct[i].alias_index = oarg;
211817280ff4SRichard Henderson                     }
211917280ff4SRichard Henderson                     ct_str++;
2120c896fe29Sbellard                     break;
212182790a87SRichard Henderson                 case '&':
212282790a87SRichard Henderson                     def->args_ct[i].ct |= TCG_CT_NEWREG;
212382790a87SRichard Henderson                     ct_str++;
212482790a87SRichard Henderson                     break;
2125c896fe29Sbellard                 case 'i':
2126c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2127c896fe29Sbellard                     ct_str++;
2128c896fe29Sbellard                     break;
2129c896fe29Sbellard                 default:
2130069ea736SRichard Henderson                     ct_str = target_parse_constraint(&def->args_ct[i],
2131069ea736SRichard Henderson                                                      ct_str, type);
2132f69d277eSRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2133069ea736SRichard Henderson                     tcg_debug_assert(ct_str != NULL);
2134c896fe29Sbellard                 }
2135c896fe29Sbellard             }
2136c896fe29Sbellard         }
2137c896fe29Sbellard 
2138c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2139eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2140c68aaa18SStefan Weil 
2141c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
2142c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
2143c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
2144c896fe29Sbellard     }
2145c896fe29Sbellard }
2146c896fe29Sbellard 
21470c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
21480c627cdcSRichard Henderson {
214915fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
215015fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
2151abebf925SRichard Henderson     s->nb_ops--;
21520c627cdcSRichard Henderson 
21530c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
2154c3fac113SEmilio G. Cota     atomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
21550c627cdcSRichard Henderson #endif
21560c627cdcSRichard Henderson }
21570c627cdcSRichard Henderson 
215815fa08f8SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc)
215915fa08f8SRichard Henderson {
216015fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
216115fa08f8SRichard Henderson     TCGOp *op;
216215fa08f8SRichard Henderson 
216315fa08f8SRichard Henderson     if (likely(QTAILQ_EMPTY(&s->free_ops))) {
216415fa08f8SRichard Henderson         op = tcg_malloc(sizeof(TCGOp));
216515fa08f8SRichard Henderson     } else {
216615fa08f8SRichard Henderson         op = QTAILQ_FIRST(&s->free_ops);
216715fa08f8SRichard Henderson         QTAILQ_REMOVE(&s->free_ops, op, link);
216815fa08f8SRichard Henderson     }
216915fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
217015fa08f8SRichard Henderson     op->opc = opc;
2171abebf925SRichard Henderson     s->nb_ops++;
217215fa08f8SRichard Henderson 
217315fa08f8SRichard Henderson     return op;
217415fa08f8SRichard Henderson }
217515fa08f8SRichard Henderson 
217615fa08f8SRichard Henderson TCGOp *tcg_emit_op(TCGOpcode opc)
217715fa08f8SRichard Henderson {
217815fa08f8SRichard Henderson     TCGOp *op = tcg_op_alloc(opc);
217915fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
218015fa08f8SRichard Henderson     return op;
218115fa08f8SRichard Henderson }
218215fa08f8SRichard Henderson 
21835a18407fSRichard Henderson TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op,
21845a18407fSRichard Henderson                             TCGOpcode opc, int nargs)
21855a18407fSRichard Henderson {
218615fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
218715fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
21885a18407fSRichard Henderson     return new_op;
21895a18407fSRichard Henderson }
21905a18407fSRichard Henderson 
21915a18407fSRichard Henderson TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op,
21925a18407fSRichard Henderson                            TCGOpcode opc, int nargs)
21935a18407fSRichard Henderson {
219415fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
219515fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
21965a18407fSRichard Henderson     return new_op;
21975a18407fSRichard Henderson }
21985a18407fSRichard Henderson 
2199c70fbf0aSRichard Henderson #define TS_DEAD  1
2200c70fbf0aSRichard Henderson #define TS_MEM   2
2201c70fbf0aSRichard Henderson 
22025a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
22035a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
22045a18407fSRichard Henderson 
22059c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
22069c43b68dSAurelien Jarno    should be in memory. */
2207b83eabeaSRichard Henderson static void tcg_la_func_end(TCGContext *s)
2208c896fe29Sbellard {
2209b83eabeaSRichard Henderson     int ng = s->nb_globals;
2210b83eabeaSRichard Henderson     int nt = s->nb_temps;
2211b83eabeaSRichard Henderson     int i;
2212b83eabeaSRichard Henderson 
2213b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2214b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
2215b83eabeaSRichard Henderson     }
2216b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2217b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
2218b83eabeaSRichard Henderson     }
2219c896fe29Sbellard }
2220c896fe29Sbellard 
22219c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
22229c43b68dSAurelien Jarno    and local temps should be in memory. */
2223b83eabeaSRichard Henderson static void tcg_la_bb_end(TCGContext *s)
2224641d5fbeSbellard {
2225b83eabeaSRichard Henderson     int ng = s->nb_globals;
2226b83eabeaSRichard Henderson     int nt = s->nb_temps;
2227b83eabeaSRichard Henderson     int i;
2228641d5fbeSbellard 
2229b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2230b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
2231c70fbf0aSRichard Henderson     }
2232b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2233b83eabeaSRichard Henderson         s->temps[i].state = (s->temps[i].temp_local
2234b83eabeaSRichard Henderson                              ? TS_DEAD | TS_MEM
2235b83eabeaSRichard Henderson                              : TS_DEAD);
2236641d5fbeSbellard     }
2237641d5fbeSbellard }
2238641d5fbeSbellard 
2239a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
2240c896fe29Sbellard    given input arguments is dead. Instructions updating dead
2241c896fe29Sbellard    temporaries are removed. */
2242b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s)
2243c896fe29Sbellard {
2244c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
224515fa08f8SRichard Henderson     TCGOp *op, *op_prev;
2246c896fe29Sbellard 
2247b83eabeaSRichard Henderson     tcg_la_func_end(s);
2248c896fe29Sbellard 
224915fa08f8SRichard Henderson     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, TCGOpHead, link, op_prev) {
2250c45cb8bbSRichard Henderson         int i, nb_iargs, nb_oargs;
2251c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
2252c45cb8bbSRichard Henderson         bool have_opc_new2;
2253a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
2254b83eabeaSRichard Henderson         TCGTemp *arg_ts;
2255c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2256c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2257c45cb8bbSRichard Henderson 
2258c45cb8bbSRichard Henderson         switch (opc) {
2259c896fe29Sbellard         case INDEX_op_call:
2260c6e113f5Sbellard             {
2261c6e113f5Sbellard                 int call_flags;
2262c6e113f5Sbellard 
2263cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
2264cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
2265efee3746SRichard Henderson                 call_flags = op->args[nb_oargs + nb_iargs + 1];
2266c6e113f5Sbellard 
2267c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
226878505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
2269c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
2270b83eabeaSRichard Henderson                         arg_ts = arg_temp(op->args[i]);
2271b83eabeaSRichard Henderson                         if (arg_ts->state != TS_DEAD) {
2272c6e113f5Sbellard                             goto do_not_remove_call;
2273c6e113f5Sbellard                         }
22749c43b68dSAurelien Jarno                     }
2275c45cb8bbSRichard Henderson                     goto do_remove;
2276c6e113f5Sbellard                 } else {
2277c6e113f5Sbellard                 do_not_remove_call:
2278c896fe29Sbellard 
2279c896fe29Sbellard                     /* output args are dead */
2280c896fe29Sbellard                     for (i = 0; i < nb_oargs; i++) {
2281b83eabeaSRichard Henderson                         arg_ts = arg_temp(op->args[i]);
2282b83eabeaSRichard Henderson                         if (arg_ts->state & TS_DEAD) {
2283a1b3c48dSRichard Henderson                             arg_life |= DEAD_ARG << i;
22846b64b624SAurelien Jarno                         }
2285b83eabeaSRichard Henderson                         if (arg_ts->state & TS_MEM) {
2286a1b3c48dSRichard Henderson                             arg_life |= SYNC_ARG << i;
22879c43b68dSAurelien Jarno                         }
2288b83eabeaSRichard Henderson                         arg_ts->state = TS_DEAD;
2289c896fe29Sbellard                     }
2290c896fe29Sbellard 
229178505279SAurelien Jarno                     if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
229278505279SAurelien Jarno                                         TCG_CALL_NO_READ_GLOBALS))) {
22939c43b68dSAurelien Jarno                         /* globals should go back to memory */
2294b83eabeaSRichard Henderson                         for (i = 0; i < nb_globals; i++) {
2295b83eabeaSRichard Henderson                             s->temps[i].state = TS_DEAD | TS_MEM;
2296b83eabeaSRichard Henderson                         }
2297c70fbf0aSRichard Henderson                     } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
2298c70fbf0aSRichard Henderson                         /* globals should be synced to memory */
2299c70fbf0aSRichard Henderson                         for (i = 0; i < nb_globals; i++) {
2300b83eabeaSRichard Henderson                             s->temps[i].state |= TS_MEM;
2301c70fbf0aSRichard Henderson                         }
2302b9c18f56Saurel32                     }
2303c896fe29Sbellard 
2304c19f47bfSAurelien Jarno                     /* record arguments that die in this helper */
2305866cb6cbSAurelien Jarno                     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2306b83eabeaSRichard Henderson                         arg_ts = arg_temp(op->args[i]);
2307b83eabeaSRichard Henderson                         if (arg_ts && arg_ts->state & TS_DEAD) {
2308a1b3c48dSRichard Henderson                             arg_life |= DEAD_ARG << i;
2309c896fe29Sbellard                         }
2310c896fe29Sbellard                     }
231167cc32ebSVeres Lajos                     /* input arguments are live for preceding opcodes */
2312c70fbf0aSRichard Henderson                     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2313b83eabeaSRichard Henderson                         arg_ts = arg_temp(op->args[i]);
2314b83eabeaSRichard Henderson                         if (arg_ts) {
2315b83eabeaSRichard Henderson                             arg_ts->state &= ~TS_DEAD;
2316c70fbf0aSRichard Henderson                         }
2317c19f47bfSAurelien Jarno                     }
2318c6e113f5Sbellard                 }
2319c6e113f5Sbellard             }
2320c896fe29Sbellard             break;
2321765b842aSRichard Henderson         case INDEX_op_insn_start:
2322c896fe29Sbellard             break;
23235ff9d6a4Sbellard         case INDEX_op_discard:
23245ff9d6a4Sbellard             /* mark the temporary as dead */
2325b83eabeaSRichard Henderson             arg_temp(op->args[0])->state = TS_DEAD;
23265ff9d6a4Sbellard             break;
23271305c451SRichard Henderson 
23281305c451SRichard Henderson         case INDEX_op_add2_i32:
2329c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
2330f1fae40cSRichard Henderson             goto do_addsub2;
23311305c451SRichard Henderson         case INDEX_op_sub2_i32:
2332c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
2333f1fae40cSRichard Henderson             goto do_addsub2;
2334f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
2335c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
2336f1fae40cSRichard Henderson             goto do_addsub2;
2337f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
2338c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
2339f1fae40cSRichard Henderson         do_addsub2:
23401305c451SRichard Henderson             nb_iargs = 4;
23411305c451SRichard Henderson             nb_oargs = 2;
23421305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
23431305c451SRichard Henderson                the low part.  The result can be optimized to a simple
23441305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
23451305c451SRichard Henderson                cpu mode is set to 32 bit.  */
2346b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2347b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
23481305c451SRichard Henderson                     goto do_remove;
23491305c451SRichard Henderson                 }
2350c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
2351c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
2352c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2353efee3746SRichard Henderson                 op->args[1] = op->args[2];
2354efee3746SRichard Henderson                 op->args[2] = op->args[4];
23551305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
23561305c451SRichard Henderson                 nb_iargs = 2;
23571305c451SRichard Henderson                 nb_oargs = 1;
23581305c451SRichard Henderson             }
23591305c451SRichard Henderson             goto do_not_remove;
23601305c451SRichard Henderson 
23611414968aSRichard Henderson         case INDEX_op_mulu2_i32:
2362c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2363c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
2364c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
236503271524SRichard Henderson             goto do_mul2;
2366f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
2367c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2368c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
2369c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
2370f1fae40cSRichard Henderson             goto do_mul2;
2371f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
2372c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2373c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
2374c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
237503271524SRichard Henderson             goto do_mul2;
2376f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
2377c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2378c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
2379c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
238003271524SRichard Henderson             goto do_mul2;
2381f1fae40cSRichard Henderson         do_mul2:
23821414968aSRichard Henderson             nb_iargs = 2;
23831414968aSRichard Henderson             nb_oargs = 2;
2384b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2385b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
238603271524SRichard Henderson                     /* Both parts of the operation are dead.  */
23871414968aSRichard Henderson                     goto do_remove;
23881414968aSRichard Henderson                 }
238903271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
2390c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2391efee3746SRichard Henderson                 op->args[1] = op->args[2];
2392efee3746SRichard Henderson                 op->args[2] = op->args[3];
2393b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
239403271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
2395c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
2396efee3746SRichard Henderson                 op->args[0] = op->args[1];
2397efee3746SRichard Henderson                 op->args[1] = op->args[2];
2398efee3746SRichard Henderson                 op->args[2] = op->args[3];
239903271524SRichard Henderson             } else {
240003271524SRichard Henderson                 goto do_not_remove;
240103271524SRichard Henderson             }
240203271524SRichard Henderson             /* Mark the single-word operation live.  */
24031414968aSRichard Henderson             nb_oargs = 1;
24041414968aSRichard Henderson             goto do_not_remove;
24051414968aSRichard Henderson 
2406c896fe29Sbellard         default:
24071305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
2408c896fe29Sbellard             nb_iargs = def->nb_iargs;
2409c896fe29Sbellard             nb_oargs = def->nb_oargs;
2410c896fe29Sbellard 
2411c896fe29Sbellard             /* Test if the operation can be removed because all
24125ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
24135ff9d6a4Sbellard                implies side effects */
24145ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
2415c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
2416b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
2417c896fe29Sbellard                         goto do_not_remove;
2418c896fe29Sbellard                     }
24199c43b68dSAurelien Jarno                 }
24201305c451SRichard Henderson             do_remove:
24210c627cdcSRichard Henderson                 tcg_op_remove(s, op);
2422c896fe29Sbellard             } else {
2423c896fe29Sbellard             do_not_remove:
2424c896fe29Sbellard                 /* output args are dead */
2425c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
2426b83eabeaSRichard Henderson                     arg_ts = arg_temp(op->args[i]);
2427b83eabeaSRichard Henderson                     if (arg_ts->state & TS_DEAD) {
2428a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
24296b64b624SAurelien Jarno                     }
2430b83eabeaSRichard Henderson                     if (arg_ts->state & TS_MEM) {
2431a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
24329c43b68dSAurelien Jarno                     }
2433b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
2434c896fe29Sbellard                 }
2435c896fe29Sbellard 
2436c896fe29Sbellard                 /* if end of basic block, update */
2437c896fe29Sbellard                 if (def->flags & TCG_OPF_BB_END) {
2438b83eabeaSRichard Henderson                     tcg_la_bb_end(s);
24393d5c5f87SAurelien Jarno                 } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
24403d5c5f87SAurelien Jarno                     /* globals should be synced to memory */
2441c70fbf0aSRichard Henderson                     for (i = 0; i < nb_globals; i++) {
2442b83eabeaSRichard Henderson                         s->temps[i].state |= TS_MEM;
2443c70fbf0aSRichard Henderson                     }
2444c896fe29Sbellard                 }
2445c896fe29Sbellard 
2446c19f47bfSAurelien Jarno                 /* record arguments that die in this opcode */
2447866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
2448b83eabeaSRichard Henderson                     arg_ts = arg_temp(op->args[i]);
2449b83eabeaSRichard Henderson                     if (arg_ts->state & TS_DEAD) {
2450a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
2451c896fe29Sbellard                     }
2452c19f47bfSAurelien Jarno                 }
245367cc32ebSVeres Lajos                 /* input arguments are live for preceding opcodes */
2454c19f47bfSAurelien Jarno                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
2455b83eabeaSRichard Henderson                     arg_temp(op->args[i])->state &= ~TS_DEAD;
2456c896fe29Sbellard                 }
2457c896fe29Sbellard             }
2458c896fe29Sbellard             break;
2459c896fe29Sbellard         }
2460bee158cbSRichard Henderson         op->life = arg_life;
2461c896fe29Sbellard     }
24621ff0a2c5SEvgeny Voevodin }
2463c896fe29Sbellard 
24645a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
2465b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s)
24665a18407fSRichard Henderson {
24675a18407fSRichard Henderson     int nb_globals = s->nb_globals;
246815fa08f8SRichard Henderson     int nb_temps, i;
24695a18407fSRichard Henderson     bool changes = false;
247015fa08f8SRichard Henderson     TCGOp *op, *op_next;
24715a18407fSRichard Henderson 
24725a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
24735a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
24745a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
24755a18407fSRichard Henderson         if (its->indirect_reg) {
24765a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
24775a18407fSRichard Henderson             dts->type = its->type;
24785a18407fSRichard Henderson             dts->base_type = its->base_type;
2479b83eabeaSRichard Henderson             its->state_ptr = dts;
2480b83eabeaSRichard Henderson         } else {
2481b83eabeaSRichard Henderson             its->state_ptr = NULL;
24825a18407fSRichard Henderson         }
2483b83eabeaSRichard Henderson         /* All globals begin dead.  */
2484b83eabeaSRichard Henderson         its->state = TS_DEAD;
24855a18407fSRichard Henderson     }
2486b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
2487b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
2488b83eabeaSRichard Henderson         its->state_ptr = NULL;
2489b83eabeaSRichard Henderson         its->state = TS_DEAD;
2490b83eabeaSRichard Henderson     }
24915a18407fSRichard Henderson 
249215fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
24935a18407fSRichard Henderson         TCGOpcode opc = op->opc;
24945a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
24955a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
24965a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
2497b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
24985a18407fSRichard Henderson 
24995a18407fSRichard Henderson         if (opc == INDEX_op_call) {
2500cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2501cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2502efee3746SRichard Henderson             call_flags = op->args[nb_oargs + nb_iargs + 1];
25035a18407fSRichard Henderson         } else {
25045a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
25055a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
25065a18407fSRichard Henderson 
25075a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
25085a18407fSRichard Henderson             if (def->flags & TCG_OPF_BB_END) {
25095a18407fSRichard Henderson                 /* Like writing globals: save_globals */
25105a18407fSRichard Henderson                 call_flags = 0;
25115a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
25125a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
25135a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
25145a18407fSRichard Henderson             } else {
25155a18407fSRichard Henderson                 /* No effect on globals.  */
25165a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
25175a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
25185a18407fSRichard Henderson             }
25195a18407fSRichard Henderson         }
25205a18407fSRichard Henderson 
25215a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
25225a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2523b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2524b83eabeaSRichard Henderson             if (arg_ts) {
2525b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
2526b83eabeaSRichard Henderson                 if (dir_ts && arg_ts->state == TS_DEAD) {
2527b83eabeaSRichard Henderson                     TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
25285a18407fSRichard Henderson                                       ? INDEX_op_ld_i32
25295a18407fSRichard Henderson                                       : INDEX_op_ld_i64);
25305a18407fSRichard Henderson                     TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3);
25315a18407fSRichard Henderson 
2532b83eabeaSRichard Henderson                     lop->args[0] = temp_arg(dir_ts);
2533b83eabeaSRichard Henderson                     lop->args[1] = temp_arg(arg_ts->mem_base);
2534b83eabeaSRichard Henderson                     lop->args[2] = arg_ts->mem_offset;
25355a18407fSRichard Henderson 
25365a18407fSRichard Henderson                     /* Loaded, but synced with memory.  */
2537b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
25385a18407fSRichard Henderson                 }
25395a18407fSRichard Henderson             }
25405a18407fSRichard Henderson         }
25415a18407fSRichard Henderson 
25425a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
25435a18407fSRichard Henderson            No action is required except keeping temp_state up to date
25445a18407fSRichard Henderson            so that we reload when needed.  */
25455a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2546b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2547b83eabeaSRichard Henderson             if (arg_ts) {
2548b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
2549b83eabeaSRichard Henderson                 if (dir_ts) {
2550b83eabeaSRichard Henderson                     op->args[i] = temp_arg(dir_ts);
25515a18407fSRichard Henderson                     changes = true;
25525a18407fSRichard Henderson                     if (IS_DEAD_ARG(i)) {
2553b83eabeaSRichard Henderson                         arg_ts->state = TS_DEAD;
25545a18407fSRichard Henderson                     }
25555a18407fSRichard Henderson                 }
25565a18407fSRichard Henderson             }
25575a18407fSRichard Henderson         }
25585a18407fSRichard Henderson 
25595a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
25605a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
25615a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
25625a18407fSRichard Henderson             /* Nothing to do */
25635a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
25645a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
25655a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
25665a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
2567b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
2568b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
2569b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
25705a18407fSRichard Henderson             }
25715a18407fSRichard Henderson         } else {
25725a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
25735a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
25745a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
2575b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
2576b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
2577b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
25785a18407fSRichard Henderson             }
25795a18407fSRichard Henderson         }
25805a18407fSRichard Henderson 
25815a18407fSRichard Henderson         /* Outputs become available.  */
25825a18407fSRichard Henderson         for (i = 0; i < nb_oargs; i++) {
2583b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2584b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
2585b83eabeaSRichard Henderson             if (!dir_ts) {
25865a18407fSRichard Henderson                 continue;
25875a18407fSRichard Henderson             }
2588b83eabeaSRichard Henderson             op->args[i] = temp_arg(dir_ts);
25895a18407fSRichard Henderson             changes = true;
25905a18407fSRichard Henderson 
25915a18407fSRichard Henderson             /* The output is now live and modified.  */
2592b83eabeaSRichard Henderson             arg_ts->state = 0;
25935a18407fSRichard Henderson 
25945a18407fSRichard Henderson             /* Sync outputs upon their last write.  */
25955a18407fSRichard Henderson             if (NEED_SYNC_ARG(i)) {
2596b83eabeaSRichard Henderson                 TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
25975a18407fSRichard Henderson                                   ? INDEX_op_st_i32
25985a18407fSRichard Henderson                                   : INDEX_op_st_i64);
25995a18407fSRichard Henderson                 TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
26005a18407fSRichard Henderson 
2601b83eabeaSRichard Henderson                 sop->args[0] = temp_arg(dir_ts);
2602b83eabeaSRichard Henderson                 sop->args[1] = temp_arg(arg_ts->mem_base);
2603b83eabeaSRichard Henderson                 sop->args[2] = arg_ts->mem_offset;
26045a18407fSRichard Henderson 
2605b83eabeaSRichard Henderson                 arg_ts->state = TS_MEM;
26065a18407fSRichard Henderson             }
26075a18407fSRichard Henderson             /* Drop outputs that are dead.  */
26085a18407fSRichard Henderson             if (IS_DEAD_ARG(i)) {
2609b83eabeaSRichard Henderson                 arg_ts->state = TS_DEAD;
26105a18407fSRichard Henderson             }
26115a18407fSRichard Henderson         }
26125a18407fSRichard Henderson     }
26135a18407fSRichard Henderson 
26145a18407fSRichard Henderson     return changes;
26155a18407fSRichard Henderson }
26165a18407fSRichard Henderson 
26178d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
2618c896fe29Sbellard static void dump_regs(TCGContext *s)
2619c896fe29Sbellard {
2620c896fe29Sbellard     TCGTemp *ts;
2621c896fe29Sbellard     int i;
2622c896fe29Sbellard     char buf[64];
2623c896fe29Sbellard 
2624c896fe29Sbellard     for(i = 0; i < s->nb_temps; i++) {
2625c896fe29Sbellard         ts = &s->temps[i];
262643439139SRichard Henderson         printf("  %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
2627c896fe29Sbellard         switch(ts->val_type) {
2628c896fe29Sbellard         case TEMP_VAL_REG:
2629c896fe29Sbellard             printf("%s", tcg_target_reg_names[ts->reg]);
2630c896fe29Sbellard             break;
2631c896fe29Sbellard         case TEMP_VAL_MEM:
2632b3a62939SRichard Henderson             printf("%d(%s)", (int)ts->mem_offset,
2633b3a62939SRichard Henderson                    tcg_target_reg_names[ts->mem_base->reg]);
2634c896fe29Sbellard             break;
2635c896fe29Sbellard         case TEMP_VAL_CONST:
2636c896fe29Sbellard             printf("$0x%" TCG_PRIlx, ts->val);
2637c896fe29Sbellard             break;
2638c896fe29Sbellard         case TEMP_VAL_DEAD:
2639c896fe29Sbellard             printf("D");
2640c896fe29Sbellard             break;
2641c896fe29Sbellard         default:
2642c896fe29Sbellard             printf("???");
2643c896fe29Sbellard             break;
2644c896fe29Sbellard         }
2645c896fe29Sbellard         printf("\n");
2646c896fe29Sbellard     }
2647c896fe29Sbellard 
2648c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
2649f8b2f202SRichard Henderson         if (s->reg_to_temp[i] != NULL) {
2650c896fe29Sbellard             printf("%s: %s\n",
2651c896fe29Sbellard                    tcg_target_reg_names[i],
2652f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i]));
2653c896fe29Sbellard         }
2654c896fe29Sbellard     }
2655c896fe29Sbellard }
2656c896fe29Sbellard 
2657c896fe29Sbellard static void check_regs(TCGContext *s)
2658c896fe29Sbellard {
2659869938aeSRichard Henderson     int reg;
2660b6638662SRichard Henderson     int k;
2661c896fe29Sbellard     TCGTemp *ts;
2662c896fe29Sbellard     char buf[64];
2663c896fe29Sbellard 
2664c896fe29Sbellard     for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
2665f8b2f202SRichard Henderson         ts = s->reg_to_temp[reg];
2666f8b2f202SRichard Henderson         if (ts != NULL) {
2667f8b2f202SRichard Henderson             if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) {
2668c896fe29Sbellard                 printf("Inconsistency for register %s:\n",
2669c896fe29Sbellard                        tcg_target_reg_names[reg]);
2670b03cce8eSbellard                 goto fail;
2671c896fe29Sbellard             }
2672c896fe29Sbellard         }
2673c896fe29Sbellard     }
2674c896fe29Sbellard     for (k = 0; k < s->nb_temps; k++) {
2675c896fe29Sbellard         ts = &s->temps[k];
2676f8b2f202SRichard Henderson         if (ts->val_type == TEMP_VAL_REG && !ts->fixed_reg
2677f8b2f202SRichard Henderson             && s->reg_to_temp[ts->reg] != ts) {
2678c896fe29Sbellard             printf("Inconsistency for temp %s:\n",
2679f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
2680b03cce8eSbellard         fail:
2681c896fe29Sbellard             printf("reg state:\n");
2682c896fe29Sbellard             dump_regs(s);
2683c896fe29Sbellard             tcg_abort();
2684c896fe29Sbellard         }
2685c896fe29Sbellard     }
2686c896fe29Sbellard }
2687c896fe29Sbellard #endif
2688c896fe29Sbellard 
26892272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
2690c896fe29Sbellard {
26919b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64)
26929b9c37c3SRichard Henderson     /* Sparc64 stack is accessed with offset of 2047 */
2693b591dc59SBlue Swirl     s->current_frame_offset = (s->current_frame_offset +
2694b591dc59SBlue Swirl                                (tcg_target_long)sizeof(tcg_target_long) - 1) &
2695b591dc59SBlue Swirl         ~(sizeof(tcg_target_long) - 1);
2696f44c9960SBlue Swirl #endif
2697b591dc59SBlue Swirl     if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
2698b591dc59SBlue Swirl         s->frame_end) {
26995ff9d6a4Sbellard         tcg_abort();
2700b591dc59SBlue Swirl     }
2701c896fe29Sbellard     ts->mem_offset = s->current_frame_offset;
2702b3a62939SRichard Henderson     ts->mem_base = s->frame_temp;
2703c896fe29Sbellard     ts->mem_allocated = 1;
2704e2c6d1b4SRichard Henderson     s->current_frame_offset += sizeof(tcg_target_long);
2705c896fe29Sbellard }
2706c896fe29Sbellard 
2707b3915dbbSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet);
2708b3915dbbSRichard Henderson 
270959d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
271059d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
271159d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
2712c896fe29Sbellard {
271359d7c14eSRichard Henderson     if (ts->fixed_reg) {
271459d7c14eSRichard Henderson         return;
271559d7c14eSRichard Henderson     }
271659d7c14eSRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
271759d7c14eSRichard Henderson         s->reg_to_temp[ts->reg] = NULL;
271859d7c14eSRichard Henderson     }
271959d7c14eSRichard Henderson     ts->val_type = (free_or_dead < 0
272059d7c14eSRichard Henderson                     || ts->temp_local
2721fa477d25SRichard Henderson                     || ts->temp_global
272259d7c14eSRichard Henderson                     ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
272359d7c14eSRichard Henderson }
2724c896fe29Sbellard 
272559d7c14eSRichard Henderson /* Mark a temporary as dead.  */
272659d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
272759d7c14eSRichard Henderson {
272859d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
272959d7c14eSRichard Henderson }
273059d7c14eSRichard Henderson 
273159d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
273259d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
273359d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
273459d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
273559d7c14eSRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts,
273659d7c14eSRichard Henderson                       TCGRegSet allocated_regs, int free_or_dead)
273759d7c14eSRichard Henderson {
273859d7c14eSRichard Henderson     if (ts->fixed_reg) {
273959d7c14eSRichard Henderson         return;
274059d7c14eSRichard Henderson     }
274159d7c14eSRichard Henderson     if (!ts->mem_coherent) {
27427f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
27432272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
274459d7c14eSRichard Henderson         }
274559d7c14eSRichard Henderson         switch (ts->val_type) {
274659d7c14eSRichard Henderson         case TEMP_VAL_CONST:
274759d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
274859d7c14eSRichard Henderson                require it later in a register, so attempt to store the
274959d7c14eSRichard Henderson                constant to memory directly.  */
275059d7c14eSRichard Henderson             if (free_or_dead
275159d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
275259d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
275359d7c14eSRichard Henderson                 break;
275459d7c14eSRichard Henderson             }
275559d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
275659d7c14eSRichard Henderson                       allocated_regs);
275759d7c14eSRichard Henderson             /* fallthrough */
275859d7c14eSRichard Henderson 
275959d7c14eSRichard Henderson         case TEMP_VAL_REG:
276059d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
276159d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
276259d7c14eSRichard Henderson             break;
276359d7c14eSRichard Henderson 
276459d7c14eSRichard Henderson         case TEMP_VAL_MEM:
276559d7c14eSRichard Henderson             break;
276659d7c14eSRichard Henderson 
276759d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
276859d7c14eSRichard Henderson         default:
276959d7c14eSRichard Henderson             tcg_abort();
2770c896fe29Sbellard         }
27717f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
27727f6ceedfSAurelien Jarno     }
277359d7c14eSRichard Henderson     if (free_or_dead) {
277459d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
277559d7c14eSRichard Henderson     }
277659d7c14eSRichard Henderson }
27777f6ceedfSAurelien Jarno 
27787f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
2779b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
27807f6ceedfSAurelien Jarno {
2781f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
2782f8b2f202SRichard Henderson     if (ts != NULL) {
278359d7c14eSRichard Henderson         temp_sync(s, ts, allocated_regs, -1);
2784c896fe29Sbellard     }
2785c896fe29Sbellard }
2786c896fe29Sbellard 
2787c896fe29Sbellard /* Allocate a register belonging to reg1 & ~reg2 */
2788b3915dbbSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet desired_regs,
278991478cefSRichard Henderson                             TCGRegSet allocated_regs, bool rev)
2790c896fe29Sbellard {
279191478cefSRichard Henderson     int i, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
279291478cefSRichard Henderson     const int *order;
2793b6638662SRichard Henderson     TCGReg reg;
2794c896fe29Sbellard     TCGRegSet reg_ct;
2795c896fe29Sbellard 
279607ddf036SRichard Henderson     reg_ct = desired_regs & ~allocated_regs;
279791478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
2798c896fe29Sbellard 
2799c896fe29Sbellard     /* first try free registers */
280091478cefSRichard Henderson     for(i = 0; i < n; i++) {
280191478cefSRichard Henderson         reg = order[i];
2802f8b2f202SRichard Henderson         if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == NULL)
2803c896fe29Sbellard             return reg;
2804c896fe29Sbellard     }
2805c896fe29Sbellard 
2806c896fe29Sbellard     /* XXX: do better spill choice */
280791478cefSRichard Henderson     for(i = 0; i < n; i++) {
280891478cefSRichard Henderson         reg = order[i];
2809c896fe29Sbellard         if (tcg_regset_test_reg(reg_ct, reg)) {
2810b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
2811c896fe29Sbellard             return reg;
2812c896fe29Sbellard         }
2813c896fe29Sbellard     }
2814c896fe29Sbellard 
2815c896fe29Sbellard     tcg_abort();
2816c896fe29Sbellard }
2817c896fe29Sbellard 
281840ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
281940ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
282040ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
282140ae5c62SRichard Henderson                       TCGRegSet allocated_regs)
282240ae5c62SRichard Henderson {
282340ae5c62SRichard Henderson     TCGReg reg;
282440ae5c62SRichard Henderson 
282540ae5c62SRichard Henderson     switch (ts->val_type) {
282640ae5c62SRichard Henderson     case TEMP_VAL_REG:
282740ae5c62SRichard Henderson         return;
282840ae5c62SRichard Henderson     case TEMP_VAL_CONST:
282991478cefSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs, ts->indirect_base);
283040ae5c62SRichard Henderson         tcg_out_movi(s, ts->type, reg, ts->val);
283140ae5c62SRichard Henderson         ts->mem_coherent = 0;
283240ae5c62SRichard Henderson         break;
283340ae5c62SRichard Henderson     case TEMP_VAL_MEM:
283491478cefSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs, ts->indirect_base);
283540ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
283640ae5c62SRichard Henderson         ts->mem_coherent = 1;
283740ae5c62SRichard Henderson         break;
283840ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
283940ae5c62SRichard Henderson     default:
284040ae5c62SRichard Henderson         tcg_abort();
284140ae5c62SRichard Henderson     }
284240ae5c62SRichard Henderson     ts->reg = reg;
284340ae5c62SRichard Henderson     ts->val_type = TEMP_VAL_REG;
284440ae5c62SRichard Henderson     s->reg_to_temp[reg] = ts;
284540ae5c62SRichard Henderson }
284640ae5c62SRichard Henderson 
284759d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
2848e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
284959d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
28501ad80729SAurelien Jarno {
28512c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
2852eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
2853f8bf00f1SRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg);
28541ad80729SAurelien Jarno }
28551ad80729SAurelien Jarno 
28569814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
2857641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
2858641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
2859641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
2860641d5fbeSbellard {
2861ac3b8891SRichard Henderson     int i, n;
2862641d5fbeSbellard 
2863ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
2864b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
2865641d5fbeSbellard     }
2866e5097dc8Sbellard }
2867e5097dc8Sbellard 
28683d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
28693d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
28703d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
28713d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
28723d5c5f87SAurelien Jarno {
2873ac3b8891SRichard Henderson     int i, n;
28743d5c5f87SAurelien Jarno 
2875ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
287612b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
287712b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
287812b9b11aSRichard Henderson                          || ts->fixed_reg
287912b9b11aSRichard Henderson                          || ts->mem_coherent);
28803d5c5f87SAurelien Jarno     }
28813d5c5f87SAurelien Jarno }
28823d5c5f87SAurelien Jarno 
2883e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
2884e8996ee0Sbellard    all globals are stored at their canonical location. */
2885e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
2886e5097dc8Sbellard {
2887e5097dc8Sbellard     int i;
2888e5097dc8Sbellard 
2889c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
2890b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
2891641d5fbeSbellard         if (ts->temp_local) {
2892b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
2893641d5fbeSbellard         } else {
28942c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
2895eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
2896eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
2897c896fe29Sbellard         }
2898641d5fbeSbellard     }
2899e8996ee0Sbellard 
2900e8996ee0Sbellard     save_globals(s, allocated_regs);
2901c896fe29Sbellard }
2902c896fe29Sbellard 
29030fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
29040fe4fca4SPaolo Bonzini                                   tcg_target_ulong val, TCGLifeData arg_life)
2905e8996ee0Sbellard {
2906e8996ee0Sbellard     if (ots->fixed_reg) {
290759d7c14eSRichard Henderson         /* For fixed registers, we do not do any constant propagation.  */
2908e8996ee0Sbellard         tcg_out_movi(s, ots->type, ots->reg, val);
290959d7c14eSRichard Henderson         return;
291059d7c14eSRichard Henderson     }
291159d7c14eSRichard Henderson 
291259d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
2913f8b2f202SRichard Henderson     if (ots->val_type == TEMP_VAL_REG) {
2914f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = NULL;
2915f8b2f202SRichard Henderson     }
2916e8996ee0Sbellard     ots->val_type = TEMP_VAL_CONST;
2917e8996ee0Sbellard     ots->val = val;
291859d7c14eSRichard Henderson     ots->mem_coherent = 0;
2919ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
292059d7c14eSRichard Henderson         temp_sync(s, ots, s->reserved_regs, IS_DEAD_ARG(0));
292159d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
2922f8bf00f1SRichard Henderson         temp_dead(s, ots);
29234c4e1ab2SAurelien Jarno     }
2924e8996ee0Sbellard }
2925e8996ee0Sbellard 
2926dd186292SRichard Henderson static void tcg_reg_alloc_movi(TCGContext *s, const TCGOp *op)
29270fe4fca4SPaolo Bonzini {
292843439139SRichard Henderson     TCGTemp *ots = arg_temp(op->args[0]);
2929dd186292SRichard Henderson     tcg_target_ulong val = op->args[1];
29300fe4fca4SPaolo Bonzini 
2931dd186292SRichard Henderson     tcg_reg_alloc_do_movi(s, ots, val, op->life);
29320fe4fca4SPaolo Bonzini }
29330fe4fca4SPaolo Bonzini 
2934dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
2935c896fe29Sbellard {
2936dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
2937c29c1d7eSAurelien Jarno     TCGRegSet allocated_regs;
2938c896fe29Sbellard     TCGTemp *ts, *ots;
2939450445d5SRichard Henderson     TCGType otype, itype;
2940c896fe29Sbellard 
2941d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
294243439139SRichard Henderson     ots = arg_temp(op->args[0]);
294343439139SRichard Henderson     ts = arg_temp(op->args[1]);
2944450445d5SRichard Henderson 
2945450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
2946450445d5SRichard Henderson     otype = ots->type;
2947450445d5SRichard Henderson     itype = ts->type;
2948c896fe29Sbellard 
29490fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
29500fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
29510fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
29520fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
29530fe4fca4SPaolo Bonzini             temp_dead(s, ts);
29540fe4fca4SPaolo Bonzini         }
29550fe4fca4SPaolo Bonzini         tcg_reg_alloc_do_movi(s, ots, val, arg_life);
29560fe4fca4SPaolo Bonzini         return;
29570fe4fca4SPaolo Bonzini     }
29580fe4fca4SPaolo Bonzini 
29590fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
29600fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
29610fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
29620fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
29630fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
296440ae5c62SRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype], allocated_regs);
2965c29c1d7eSAurelien Jarno     }
2966c29c1d7eSAurelien Jarno 
29670fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
2968c29c1d7eSAurelien Jarno     if (IS_DEAD_ARG(0) && !ots->fixed_reg) {
2969c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
2970c29c1d7eSAurelien Jarno            liveness analysis disabled). */
2971eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
2972c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
29732272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
2974c29c1d7eSAurelien Jarno         }
2975b3a62939SRichard Henderson         tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset);
2976c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
2977f8bf00f1SRichard Henderson             temp_dead(s, ts);
2978c29c1d7eSAurelien Jarno         }
2979f8bf00f1SRichard Henderson         temp_dead(s, ots);
2980e8996ee0Sbellard     } else {
2981c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1) && !ts->fixed_reg && !ots->fixed_reg) {
2982c29c1d7eSAurelien Jarno             /* the mov can be suppressed */
2983c29c1d7eSAurelien Jarno             if (ots->val_type == TEMP_VAL_REG) {
2984f8b2f202SRichard Henderson                 s->reg_to_temp[ots->reg] = NULL;
2985c896fe29Sbellard             }
2986c29c1d7eSAurelien Jarno             ots->reg = ts->reg;
2987f8bf00f1SRichard Henderson             temp_dead(s, ts);
2988c29c1d7eSAurelien Jarno         } else {
2989c29c1d7eSAurelien Jarno             if (ots->val_type != TEMP_VAL_REG) {
2990c29c1d7eSAurelien Jarno                 /* When allocating a new register, make sure to not spill the
2991c29c1d7eSAurelien Jarno                    input one. */
2992c29c1d7eSAurelien Jarno                 tcg_regset_set_reg(allocated_regs, ts->reg);
2993450445d5SRichard Henderson                 ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
299491478cefSRichard Henderson                                          allocated_regs, ots->indirect_base);
2995c29c1d7eSAurelien Jarno             }
2996450445d5SRichard Henderson             tcg_out_mov(s, otype, ots->reg, ts->reg);
2997c29c1d7eSAurelien Jarno         }
2998c896fe29Sbellard         ots->val_type = TEMP_VAL_REG;
2999c896fe29Sbellard         ots->mem_coherent = 0;
3000f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3001ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(0)) {
300259d7c14eSRichard Henderson             temp_sync(s, ots, allocated_regs, 0);
3003c29c1d7eSAurelien Jarno         }
3004ec7a869dSAurelien Jarno     }
3005c896fe29Sbellard }
3006c896fe29Sbellard 
3007dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
3008c896fe29Sbellard {
3009dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3010dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
301182790a87SRichard Henderson     TCGRegSet i_allocated_regs;
301282790a87SRichard Henderson     TCGRegSet o_allocated_regs;
3013b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
3014b6638662SRichard Henderson     TCGReg reg;
3015c896fe29Sbellard     TCGArg arg;
3016c896fe29Sbellard     const TCGArgConstraint *arg_ct;
3017c896fe29Sbellard     TCGTemp *ts;
3018c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
3019c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
3020c896fe29Sbellard 
3021c896fe29Sbellard     nb_oargs = def->nb_oargs;
3022c896fe29Sbellard     nb_iargs = def->nb_iargs;
3023c896fe29Sbellard 
3024c896fe29Sbellard     /* copy constants */
3025c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
3026dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
3027c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
3028c896fe29Sbellard 
3029d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
3030d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
303182790a87SRichard Henderson 
3032c896fe29Sbellard     /* satisfy input constraints */
3033c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
3034c896fe29Sbellard         i = def->sorted_args[nb_oargs + k];
3035dd186292SRichard Henderson         arg = op->args[i];
3036c896fe29Sbellard         arg_ct = &def->args_ct[i];
303743439139SRichard Henderson         ts = arg_temp(arg);
303840ae5c62SRichard Henderson 
303940ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
304040ae5c62SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct)) {
3041c896fe29Sbellard             /* constant is OK for instruction */
3042c896fe29Sbellard             const_args[i] = 1;
3043c896fe29Sbellard             new_args[i] = ts->val;
3044c896fe29Sbellard             goto iarg_end;
3045c896fe29Sbellard         }
304640ae5c62SRichard Henderson 
304782790a87SRichard Henderson         temp_load(s, ts, arg_ct->u.regs, i_allocated_regs);
304840ae5c62SRichard Henderson 
30495ff9d6a4Sbellard         if (arg_ct->ct & TCG_CT_IALIAS) {
30505ff9d6a4Sbellard             if (ts->fixed_reg) {
30515ff9d6a4Sbellard                 /* if fixed register, we must allocate a new register
30525ff9d6a4Sbellard                    if the alias is not the same register */
3053dd186292SRichard Henderson                 if (arg != op->args[arg_ct->alias_index])
30545ff9d6a4Sbellard                     goto allocate_in_reg;
30555ff9d6a4Sbellard             } else {
3056c896fe29Sbellard                 /* if the input is aliased to an output and if it is
3057c896fe29Sbellard                    not dead after the instruction, we must allocate
3058c896fe29Sbellard                    a new register and move it */
3059866cb6cbSAurelien Jarno                 if (!IS_DEAD_ARG(i)) {
3060c896fe29Sbellard                     goto allocate_in_reg;
3061c896fe29Sbellard                 }
30627e1df267SAurelien Jarno                 /* check if the current register has already been allocated
30637e1df267SAurelien Jarno                    for another input aliased to an output */
30647e1df267SAurelien Jarno                 int k2, i2;
30657e1df267SAurelien Jarno                 for (k2 = 0 ; k2 < k ; k2++) {
30667e1df267SAurelien Jarno                     i2 = def->sorted_args[nb_oargs + k2];
30677e1df267SAurelien Jarno                     if ((def->args_ct[i2].ct & TCG_CT_IALIAS) &&
30687e1df267SAurelien Jarno                         (new_args[i2] == ts->reg)) {
30697e1df267SAurelien Jarno                         goto allocate_in_reg;
30707e1df267SAurelien Jarno                     }
30717e1df267SAurelien Jarno                 }
30725ff9d6a4Sbellard             }
3073866cb6cbSAurelien Jarno         }
3074c896fe29Sbellard         reg = ts->reg;
3075c896fe29Sbellard         if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
3076c896fe29Sbellard             /* nothing to do : the constraint is satisfied */
3077c896fe29Sbellard         } else {
3078c896fe29Sbellard         allocate_in_reg:
3079c896fe29Sbellard             /* allocate a new register matching the constraint
3080c896fe29Sbellard                and move the temporary register into it */
308182790a87SRichard Henderson             reg = tcg_reg_alloc(s, arg_ct->u.regs, i_allocated_regs,
308291478cefSRichard Henderson                                 ts->indirect_base);
30833b6dac34SRichard Henderson             tcg_out_mov(s, ts->type, reg, ts->reg);
3084c896fe29Sbellard         }
3085c896fe29Sbellard         new_args[i] = reg;
3086c896fe29Sbellard         const_args[i] = 0;
308782790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
3088c896fe29Sbellard     iarg_end: ;
3089c896fe29Sbellard     }
3090c896fe29Sbellard 
3091c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
3092866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
3093866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
309443439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
3095c896fe29Sbellard         }
3096c896fe29Sbellard     }
3097c896fe29Sbellard 
3098a52ad07eSAurelien Jarno     if (def->flags & TCG_OPF_BB_END) {
309982790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
3100a52ad07eSAurelien Jarno     } else {
3101c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
3102b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
3103c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
3104c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
310582790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
3106c896fe29Sbellard                 }
3107c896fe29Sbellard             }
31083d5c5f87SAurelien Jarno         }
31093d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
31103d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
31113d5c5f87SAurelien Jarno                an exception. */
311282790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
3113c896fe29Sbellard         }
3114c896fe29Sbellard 
3115c896fe29Sbellard         /* satisfy the output constraints */
3116c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
3117c896fe29Sbellard             i = def->sorted_args[k];
3118dd186292SRichard Henderson             arg = op->args[i];
3119c896fe29Sbellard             arg_ct = &def->args_ct[i];
312043439139SRichard Henderson             ts = arg_temp(arg);
312117280ff4SRichard Henderson             if ((arg_ct->ct & TCG_CT_ALIAS)
312217280ff4SRichard Henderson                 && !const_args[arg_ct->alias_index]) {
31235ff9d6a4Sbellard                 reg = new_args[arg_ct->alias_index];
312482790a87SRichard Henderson             } else if (arg_ct->ct & TCG_CT_NEWREG) {
312582790a87SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->u.regs,
312682790a87SRichard Henderson                                     i_allocated_regs | o_allocated_regs,
312782790a87SRichard Henderson                                     ts->indirect_base);
3128c896fe29Sbellard             } else {
3129c896fe29Sbellard                 /* if fixed register, we try to use it */
3130c896fe29Sbellard                 reg = ts->reg;
3131c896fe29Sbellard                 if (ts->fixed_reg &&
3132c896fe29Sbellard                     tcg_regset_test_reg(arg_ct->u.regs, reg)) {
3133c896fe29Sbellard                     goto oarg_end;
3134c896fe29Sbellard                 }
313582790a87SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->u.regs, o_allocated_regs,
313691478cefSRichard Henderson                                     ts->indirect_base);
3137c896fe29Sbellard             }
313882790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
3139c896fe29Sbellard             /* if a fixed register is used, then a move will be done afterwards */
3140c896fe29Sbellard             if (!ts->fixed_reg) {
3141639368ddSAurelien Jarno                 if (ts->val_type == TEMP_VAL_REG) {
3142f8b2f202SRichard Henderson                     s->reg_to_temp[ts->reg] = NULL;
3143639368ddSAurelien Jarno                 }
3144c896fe29Sbellard                 ts->val_type = TEMP_VAL_REG;
3145c896fe29Sbellard                 ts->reg = reg;
3146c896fe29Sbellard                 /* temp value is modified, so the value kept in memory is
3147c896fe29Sbellard                    potentially not the same */
3148c896fe29Sbellard                 ts->mem_coherent = 0;
3149f8b2f202SRichard Henderson                 s->reg_to_temp[reg] = ts;
3150c896fe29Sbellard             }
3151c896fe29Sbellard         oarg_end:
3152c896fe29Sbellard             new_args[i] = reg;
3153c896fe29Sbellard         }
3154e8996ee0Sbellard     }
3155c896fe29Sbellard 
3156c896fe29Sbellard     /* emit instruction */
3157d2fd745fSRichard Henderson     if (def->flags & TCG_OPF_VECTOR) {
3158d2fd745fSRichard Henderson         tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
3159d2fd745fSRichard Henderson                        new_args, const_args);
3160d2fd745fSRichard Henderson     } else {
3161dd186292SRichard Henderson         tcg_out_op(s, op->opc, new_args, const_args);
3162d2fd745fSRichard Henderson     }
3163c896fe29Sbellard 
3164c896fe29Sbellard     /* move the outputs in the correct register if needed */
3165c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
316643439139SRichard Henderson         ts = arg_temp(op->args[i]);
3167c896fe29Sbellard         reg = new_args[i];
3168c896fe29Sbellard         if (ts->fixed_reg && ts->reg != reg) {
31693b6dac34SRichard Henderson             tcg_out_mov(s, ts->type, ts->reg, reg);
3170c896fe29Sbellard         }
3171ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
317282790a87SRichard Henderson             temp_sync(s, ts, o_allocated_regs, IS_DEAD_ARG(i));
317359d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
3174f8bf00f1SRichard Henderson             temp_dead(s, ts);
3175ec7a869dSAurelien Jarno         }
3176c896fe29Sbellard     }
3177c896fe29Sbellard }
3178c896fe29Sbellard 
3179b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP
3180b03cce8eSbellard #define STACK_DIR(x) (-(x))
3181b03cce8eSbellard #else
3182b03cce8eSbellard #define STACK_DIR(x) (x)
3183b03cce8eSbellard #endif
3184b03cce8eSbellard 
3185dd186292SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
3186c896fe29Sbellard {
3187cd9090aaSRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
3188cd9090aaSRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
3189dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3190b6638662SRichard Henderson     int flags, nb_regs, i;
3191b6638662SRichard Henderson     TCGReg reg;
3192cf066674SRichard Henderson     TCGArg arg;
3193c896fe29Sbellard     TCGTemp *ts;
3194d3452f1fSRichard Henderson     intptr_t stack_offset;
3195d3452f1fSRichard Henderson     size_t call_stack_size;
3196cf066674SRichard Henderson     tcg_insn_unit *func_addr;
3197cf066674SRichard Henderson     int allocate_args;
3198c896fe29Sbellard     TCGRegSet allocated_regs;
3199c896fe29Sbellard 
3200dd186292SRichard Henderson     func_addr = (tcg_insn_unit *)(intptr_t)op->args[nb_oargs + nb_iargs];
3201dd186292SRichard Henderson     flags = op->args[nb_oargs + nb_iargs + 1];
3202c896fe29Sbellard 
32036e17d0c5SStefan Weil     nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
3204c45cb8bbSRichard Henderson     if (nb_regs > nb_iargs) {
3205c45cb8bbSRichard Henderson         nb_regs = nb_iargs;
3206cf066674SRichard Henderson     }
3207c896fe29Sbellard 
3208c896fe29Sbellard     /* assign stack slots first */
3209c45cb8bbSRichard Henderson     call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long);
3210c896fe29Sbellard     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
3211c896fe29Sbellard         ~(TCG_TARGET_STACK_ALIGN - 1);
3212b03cce8eSbellard     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
3213b03cce8eSbellard     if (allocate_args) {
3214345649c0SBlue Swirl         /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
3215345649c0SBlue Swirl            preallocate call stack */
3216345649c0SBlue Swirl         tcg_abort();
3217b03cce8eSbellard     }
321839cf05d3Sbellard 
321939cf05d3Sbellard     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
3220c45cb8bbSRichard Henderson     for (i = nb_regs; i < nb_iargs; i++) {
3221dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
322239cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP
322339cf05d3Sbellard         stack_offset -= sizeof(tcg_target_long);
322439cf05d3Sbellard #endif
322539cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
322643439139SRichard Henderson             ts = arg_temp(arg);
322740ae5c62SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
322840ae5c62SRichard Henderson                       s->reserved_regs);
3229e4d5434cSblueswir1             tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
323039cf05d3Sbellard         }
323139cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP
323239cf05d3Sbellard         stack_offset += sizeof(tcg_target_long);
323339cf05d3Sbellard #endif
3234c896fe29Sbellard     }
3235c896fe29Sbellard 
3236c896fe29Sbellard     /* assign input registers */
3237d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
3238c896fe29Sbellard     for (i = 0; i < nb_regs; i++) {
3239dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
324039cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
324143439139SRichard Henderson             ts = arg_temp(arg);
3242c896fe29Sbellard             reg = tcg_target_call_iarg_regs[i];
3243b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
324440ae5c62SRichard Henderson 
3245c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
3246c896fe29Sbellard                 if (ts->reg != reg) {
32473b6dac34SRichard Henderson                     tcg_out_mov(s, ts->type, reg, ts->reg);
3248c896fe29Sbellard                 }
3249c896fe29Sbellard             } else {
3250ccb1bb66SRichard Henderson                 TCGRegSet arg_set = 0;
325140ae5c62SRichard Henderson 
325240ae5c62SRichard Henderson                 tcg_regset_set_reg(arg_set, reg);
325340ae5c62SRichard Henderson                 temp_load(s, ts, arg_set, allocated_regs);
3254c896fe29Sbellard             }
325540ae5c62SRichard Henderson 
3256c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
3257c896fe29Sbellard         }
325839cf05d3Sbellard     }
3259c896fe29Sbellard 
3260c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
3261866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3262866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
326343439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
3264c896fe29Sbellard         }
3265c896fe29Sbellard     }
3266c896fe29Sbellard 
3267c896fe29Sbellard     /* clobber call registers */
3268c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
3269c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
3270b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
3271c896fe29Sbellard         }
3272c896fe29Sbellard     }
3273c896fe29Sbellard 
327478505279SAurelien Jarno     /* Save globals if they might be written by the helper, sync them if
327578505279SAurelien Jarno        they might be read. */
327678505279SAurelien Jarno     if (flags & TCG_CALL_NO_READ_GLOBALS) {
327778505279SAurelien Jarno         /* Nothing to do */
327878505279SAurelien Jarno     } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) {
327978505279SAurelien Jarno         sync_globals(s, allocated_regs);
328078505279SAurelien Jarno     } else {
3281e8996ee0Sbellard         save_globals(s, allocated_regs);
3282b9c18f56Saurel32     }
3283c896fe29Sbellard 
3284cf066674SRichard Henderson     tcg_out_call(s, func_addr);
3285c896fe29Sbellard 
3286c896fe29Sbellard     /* assign output registers and emit moves if needed */
3287c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
3288dd186292SRichard Henderson         arg = op->args[i];
328943439139SRichard Henderson         ts = arg_temp(arg);
3290c896fe29Sbellard         reg = tcg_target_call_oarg_regs[i];
3291eabb7b91SAurelien Jarno         tcg_debug_assert(s->reg_to_temp[reg] == NULL);
329234b1a49cSRichard Henderson 
3293c896fe29Sbellard         if (ts->fixed_reg) {
3294c896fe29Sbellard             if (ts->reg != reg) {
32953b6dac34SRichard Henderson                 tcg_out_mov(s, ts->type, ts->reg, reg);
3296c896fe29Sbellard             }
3297c896fe29Sbellard         } else {
3298639368ddSAurelien Jarno             if (ts->val_type == TEMP_VAL_REG) {
3299f8b2f202SRichard Henderson                 s->reg_to_temp[ts->reg] = NULL;
3300639368ddSAurelien Jarno             }
3301c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
3302c896fe29Sbellard             ts->reg = reg;
3303c896fe29Sbellard             ts->mem_coherent = 0;
3304f8b2f202SRichard Henderson             s->reg_to_temp[reg] = ts;
3305ec7a869dSAurelien Jarno             if (NEED_SYNC_ARG(i)) {
330659d7c14eSRichard Henderson                 temp_sync(s, ts, allocated_regs, IS_DEAD_ARG(i));
330759d7c14eSRichard Henderson             } else if (IS_DEAD_ARG(i)) {
3308f8bf00f1SRichard Henderson                 temp_dead(s, ts);
3309c896fe29Sbellard             }
3310c896fe29Sbellard         }
33118c11ad25SAurelien Jarno     }
3312c896fe29Sbellard }
3313c896fe29Sbellard 
3314c896fe29Sbellard #ifdef CONFIG_PROFILER
3315c896fe29Sbellard 
3316c3fac113SEmilio G. Cota /* avoid copy/paste errors */
3317c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field)                       \
3318c3fac113SEmilio G. Cota     do {                                                \
3319c3fac113SEmilio G. Cota         (to)->field += atomic_read(&((from)->field));   \
3320c3fac113SEmilio G. Cota     } while (0)
3321c896fe29Sbellard 
3322c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field)                                       \
3323c3fac113SEmilio G. Cota     do {                                                                \
3324c3fac113SEmilio G. Cota         typeof((from)->field) val__ = atomic_read(&((from)->field));    \
3325c3fac113SEmilio G. Cota         if (val__ > (to)->field) {                                      \
3326c3fac113SEmilio G. Cota             (to)->field = val__;                                        \
3327c3fac113SEmilio G. Cota         }                                                               \
3328c3fac113SEmilio G. Cota     } while (0)
3329c3fac113SEmilio G. Cota 
3330c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */
3331c3fac113SEmilio G. Cota static inline
3332c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
3333c896fe29Sbellard {
33343468b59eSEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
3335c3fac113SEmilio G. Cota     unsigned int i;
3336c3fac113SEmilio G. Cota 
33373468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
33383468b59eSEmilio G. Cota         TCGContext *s = atomic_read(&tcg_ctxs[i]);
33393468b59eSEmilio G. Cota         const TCGProfile *orig = &s->prof;
3340c3fac113SEmilio G. Cota 
3341c3fac113SEmilio G. Cota         if (counters) {
3342c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count1);
3343c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count);
3344c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, op_count);
3345c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, op_count_max);
3346c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, temp_count);
3347c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, temp_count_max);
3348c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, del_op_count);
3349c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_in_len);
3350c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_out_len);
3351c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, search_out_len);
3352c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, interm_time);
3353c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_time);
3354c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, la_time);
3355c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, opt_time);
3356c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_count);
3357c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_time);
3358c3fac113SEmilio G. Cota         }
3359c3fac113SEmilio G. Cota         if (table) {
3360c896fe29Sbellard             int i;
3361d70724ceSzhanghailiang 
336215fc7daaSRichard Henderson             for (i = 0; i < NB_OPS; i++) {
3363c3fac113SEmilio G. Cota                 PROF_ADD(prof, orig, table_op_count[i]);
3364c3fac113SEmilio G. Cota             }
3365c3fac113SEmilio G. Cota         }
3366c3fac113SEmilio G. Cota     }
3367c3fac113SEmilio G. Cota }
3368c3fac113SEmilio G. Cota 
3369c3fac113SEmilio G. Cota #undef PROF_ADD
3370c3fac113SEmilio G. Cota #undef PROF_MAX
3371c3fac113SEmilio G. Cota 
3372c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof)
3373c3fac113SEmilio G. Cota {
3374c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, true, false);
3375c3fac113SEmilio G. Cota }
3376c3fac113SEmilio G. Cota 
3377c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof)
3378c3fac113SEmilio G. Cota {
3379c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, false, true);
3380c3fac113SEmilio G. Cota }
3381c3fac113SEmilio G. Cota 
3382c3fac113SEmilio G. Cota void tcg_dump_op_count(FILE *f, fprintf_function cpu_fprintf)
3383c3fac113SEmilio G. Cota {
3384c3fac113SEmilio G. Cota     TCGProfile prof = {};
3385c3fac113SEmilio G. Cota     int i;
3386c3fac113SEmilio G. Cota 
3387c3fac113SEmilio G. Cota     tcg_profile_snapshot_table(&prof);
3388c3fac113SEmilio G. Cota     for (i = 0; i < NB_OPS; i++) {
3389246ae24dSMax Filippov         cpu_fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name,
3390c3fac113SEmilio G. Cota                     prof.table_op_count[i]);
3391c896fe29Sbellard     }
3392c896fe29Sbellard }
3393246ae24dSMax Filippov #else
3394246ae24dSMax Filippov void tcg_dump_op_count(FILE *f, fprintf_function cpu_fprintf)
3395246ae24dSMax Filippov {
3396246ae24dSMax Filippov     cpu_fprintf(f, "[TCG profiler not compiled]\n");
3397246ae24dSMax Filippov }
3398c896fe29Sbellard #endif
3399c896fe29Sbellard 
3400c896fe29Sbellard 
34015bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
3402c896fe29Sbellard {
3403c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER
3404c3fac113SEmilio G. Cota     TCGProfile *prof = &s->prof;
3405c3fac113SEmilio G. Cota #endif
340615fa08f8SRichard Henderson     int i, num_insns;
340715fa08f8SRichard Henderson     TCGOp *op;
3408c896fe29Sbellard 
340904fe6400SRichard Henderson #ifdef CONFIG_PROFILER
341004fe6400SRichard Henderson     {
341104fe6400SRichard Henderson         int n;
341204fe6400SRichard Henderson 
341315fa08f8SRichard Henderson         QTAILQ_FOREACH(op, &s->ops, link) {
341415fa08f8SRichard Henderson             n++;
341515fa08f8SRichard Henderson         }
3416c3fac113SEmilio G. Cota         atomic_set(&prof->op_count, prof->op_count + n);
3417c3fac113SEmilio G. Cota         if (n > prof->op_count_max) {
3418c3fac113SEmilio G. Cota             atomic_set(&prof->op_count_max, n);
341904fe6400SRichard Henderson         }
342004fe6400SRichard Henderson 
342104fe6400SRichard Henderson         n = s->nb_temps;
3422c3fac113SEmilio G. Cota         atomic_set(&prof->temp_count, prof->temp_count + n);
3423c3fac113SEmilio G. Cota         if (n > prof->temp_count_max) {
3424c3fac113SEmilio G. Cota             atomic_set(&prof->temp_count_max, n);
342504fe6400SRichard Henderson         }
342604fe6400SRichard Henderson     }
342704fe6400SRichard Henderson #endif
342804fe6400SRichard Henderson 
3429c896fe29Sbellard #ifdef DEBUG_DISAS
3430d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
3431d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
34321ee73216SRichard Henderson         qemu_log_lock();
343393fcfe39Saliguori         qemu_log("OP:\n");
3434eeacee4dSBlue Swirl         tcg_dump_ops(s);
343593fcfe39Saliguori         qemu_log("\n");
34361ee73216SRichard Henderson         qemu_log_unlock();
3437c896fe29Sbellard     }
3438c896fe29Sbellard #endif
3439c896fe29Sbellard 
3440c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
3441c3fac113SEmilio G. Cota     atomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
3442c5cc28ffSAurelien Jarno #endif
3443c5cc28ffSAurelien Jarno 
34448f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
3445c45cb8bbSRichard Henderson     tcg_optimize(s);
34468f2e8c07SKirill Batuzov #endif
34478f2e8c07SKirill Batuzov 
3448a23a9ec6Sbellard #ifdef CONFIG_PROFILER
3449c3fac113SEmilio G. Cota     atomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
3450c3fac113SEmilio G. Cota     atomic_set(&prof->la_time, prof->la_time - profile_getclock());
3451a23a9ec6Sbellard #endif
3452c5cc28ffSAurelien Jarno 
3453b83eabeaSRichard Henderson     liveness_pass_1(s);
34545a18407fSRichard Henderson 
34555a18407fSRichard Henderson     if (s->nb_indirects > 0) {
34565a18407fSRichard Henderson #ifdef DEBUG_DISAS
34575a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
34585a18407fSRichard Henderson                      && qemu_log_in_addr_range(tb->pc))) {
34591ee73216SRichard Henderson             qemu_log_lock();
34605a18407fSRichard Henderson             qemu_log("OP before indirect lowering:\n");
34615a18407fSRichard Henderson             tcg_dump_ops(s);
34625a18407fSRichard Henderson             qemu_log("\n");
34631ee73216SRichard Henderson             qemu_log_unlock();
34645a18407fSRichard Henderson         }
34655a18407fSRichard Henderson #endif
34665a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
3467b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
34685a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
3469b83eabeaSRichard Henderson             liveness_pass_1(s);
34705a18407fSRichard Henderson         }
34715a18407fSRichard Henderson     }
3472c5cc28ffSAurelien Jarno 
3473a23a9ec6Sbellard #ifdef CONFIG_PROFILER
3474c3fac113SEmilio G. Cota     atomic_set(&prof->la_time, prof->la_time + profile_getclock());
3475a23a9ec6Sbellard #endif
3476c896fe29Sbellard 
3477c896fe29Sbellard #ifdef DEBUG_DISAS
3478d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
3479d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
34801ee73216SRichard Henderson         qemu_log_lock();
3481c5cc28ffSAurelien Jarno         qemu_log("OP after optimization and liveness analysis:\n");
3482eeacee4dSBlue Swirl         tcg_dump_ops(s);
348393fcfe39Saliguori         qemu_log("\n");
34841ee73216SRichard Henderson         qemu_log_unlock();
3485c896fe29Sbellard     }
3486c896fe29Sbellard #endif
3487c896fe29Sbellard 
3488c896fe29Sbellard     tcg_reg_alloc_start(s);
3489c896fe29Sbellard 
3490e7e168f4SEmilio G. Cota     s->code_buf = tb->tc.ptr;
3491e7e168f4SEmilio G. Cota     s->code_ptr = tb->tc.ptr;
3492c896fe29Sbellard 
3493659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
34946001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
3495659ef5cbSRichard Henderson #endif
349657a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
349757a26946SRichard Henderson     s->pool_labels = NULL;
349857a26946SRichard Henderson #endif
34999ecefc84SRichard Henderson 
3500fca8a500SRichard Henderson     num_insns = -1;
350115fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
3502c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
3503b3db8758Sblueswir1 
3504c896fe29Sbellard #ifdef CONFIG_PROFILER
3505c3fac113SEmilio G. Cota         atomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
3506c896fe29Sbellard #endif
3507c45cb8bbSRichard Henderson 
3508c896fe29Sbellard         switch (opc) {
3509c896fe29Sbellard         case INDEX_op_mov_i32:
3510c896fe29Sbellard         case INDEX_op_mov_i64:
3511d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
3512dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
3513c896fe29Sbellard             break;
3514e8996ee0Sbellard         case INDEX_op_movi_i32:
3515e8996ee0Sbellard         case INDEX_op_movi_i64:
3516d2fd745fSRichard Henderson         case INDEX_op_dupi_vec:
3517dd186292SRichard Henderson             tcg_reg_alloc_movi(s, op);
3518e8996ee0Sbellard             break;
3519765b842aSRichard Henderson         case INDEX_op_insn_start:
3520fca8a500SRichard Henderson             if (num_insns >= 0) {
3521fca8a500SRichard Henderson                 s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
3522fca8a500SRichard Henderson             }
3523fca8a500SRichard Henderson             num_insns++;
3524bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
3525bad729e2SRichard Henderson                 target_ulong a;
3526bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
3527efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
3528bad729e2SRichard Henderson #else
3529efee3746SRichard Henderson                 a = op->args[i];
3530bad729e2SRichard Henderson #endif
3531fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
3532bad729e2SRichard Henderson             }
3533c896fe29Sbellard             break;
35345ff9d6a4Sbellard         case INDEX_op_discard:
353543439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
35365ff9d6a4Sbellard             break;
3537c896fe29Sbellard         case INDEX_op_set_label:
3538e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
3539efee3746SRichard Henderson             tcg_out_label(s, arg_label(op->args[0]), s->code_ptr);
3540c896fe29Sbellard             break;
3541c896fe29Sbellard         case INDEX_op_call:
3542dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
3543c45cb8bbSRichard Henderson             break;
3544c896fe29Sbellard         default:
354525c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
3546be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
3547c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
3548c896fe29Sbellard                faster to have specialized register allocator functions for
3549c896fe29Sbellard                some common argument patterns */
3550dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
3551c896fe29Sbellard             break;
3552c896fe29Sbellard         }
35538d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
3554c896fe29Sbellard         check_regs(s);
3555c896fe29Sbellard #endif
3556b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
3557b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
3558b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
3559b125f9dcSRichard Henderson            generating code without having to check during generation.  */
3560644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
3561b125f9dcSRichard Henderson             return -1;
3562b125f9dcSRichard Henderson         }
3563c896fe29Sbellard     }
3564fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
3565fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
3566c45cb8bbSRichard Henderson 
3567b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
3568659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
3569659ef5cbSRichard Henderson     if (!tcg_out_ldst_finalize(s)) {
357023dceda6SRichard Henderson         return -1;
357123dceda6SRichard Henderson     }
3572659ef5cbSRichard Henderson #endif
357357a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
357457a26946SRichard Henderson     if (!tcg_out_pool_finalize(s)) {
357557a26946SRichard Henderson         return -1;
357657a26946SRichard Henderson     }
357757a26946SRichard Henderson #endif
3578c896fe29Sbellard 
3579c896fe29Sbellard     /* flush instruction cache */
35801813e175SRichard Henderson     flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr);
35812aeabc08SStefan Weil 
35821813e175SRichard Henderson     return tcg_current_code_size(s);
3583c896fe29Sbellard }
3584c896fe29Sbellard 
3585a23a9ec6Sbellard #ifdef CONFIG_PROFILER
3586405cf9ffSStefan Weil void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
3587a23a9ec6Sbellard {
3588c3fac113SEmilio G. Cota     TCGProfile prof = {};
3589c3fac113SEmilio G. Cota     const TCGProfile *s;
3590c3fac113SEmilio G. Cota     int64_t tb_count;
3591c3fac113SEmilio G. Cota     int64_t tb_div_count;
3592c3fac113SEmilio G. Cota     int64_t tot;
3593c3fac113SEmilio G. Cota 
3594c3fac113SEmilio G. Cota     tcg_profile_snapshot_counters(&prof);
3595c3fac113SEmilio G. Cota     s = &prof;
3596c3fac113SEmilio G. Cota     tb_count = s->tb_count;
3597c3fac113SEmilio G. Cota     tb_div_count = tb_count ? tb_count : 1;
3598c3fac113SEmilio G. Cota     tot = s->interm_time + s->code_time;
3599a23a9ec6Sbellard 
3600a23a9ec6Sbellard     cpu_fprintf(f, "JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
3601a23a9ec6Sbellard                 tot, tot / 2.4e9);
3602a23a9ec6Sbellard     cpu_fprintf(f, "translated TBs      %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n",
3603fca8a500SRichard Henderson                 tb_count, s->tb_count1 - tb_count,
3604fca8a500SRichard Henderson                 (double)(s->tb_count1 - s->tb_count)
3605fca8a500SRichard Henderson                 / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
3606a23a9ec6Sbellard     cpu_fprintf(f, "avg ops/TB          %0.1f max=%d\n",
3607fca8a500SRichard Henderson                 (double)s->op_count / tb_div_count, s->op_count_max);
3608a23a9ec6Sbellard     cpu_fprintf(f, "deleted ops/TB      %0.2f\n",
3609fca8a500SRichard Henderson                 (double)s->del_op_count / tb_div_count);
3610a23a9ec6Sbellard     cpu_fprintf(f, "avg temps/TB        %0.2f max=%d\n",
3611fca8a500SRichard Henderson                 (double)s->temp_count / tb_div_count, s->temp_count_max);
3612fca8a500SRichard Henderson     cpu_fprintf(f, "avg host code/TB    %0.1f\n",
3613fca8a500SRichard Henderson                 (double)s->code_out_len / tb_div_count);
3614fca8a500SRichard Henderson     cpu_fprintf(f, "avg search data/TB  %0.1f\n",
3615fca8a500SRichard Henderson                 (double)s->search_out_len / tb_div_count);
3616a23a9ec6Sbellard 
3617a23a9ec6Sbellard     cpu_fprintf(f, "cycles/op           %0.1f\n",
3618a23a9ec6Sbellard                 s->op_count ? (double)tot / s->op_count : 0);
3619a23a9ec6Sbellard     cpu_fprintf(f, "cycles/in byte      %0.1f\n",
3620a23a9ec6Sbellard                 s->code_in_len ? (double)tot / s->code_in_len : 0);
3621a23a9ec6Sbellard     cpu_fprintf(f, "cycles/out byte     %0.1f\n",
3622a23a9ec6Sbellard                 s->code_out_len ? (double)tot / s->code_out_len : 0);
3623fca8a500SRichard Henderson     cpu_fprintf(f, "cycles/search byte     %0.1f\n",
3624fca8a500SRichard Henderson                 s->search_out_len ? (double)tot / s->search_out_len : 0);
3625fca8a500SRichard Henderson     if (tot == 0) {
3626a23a9ec6Sbellard         tot = 1;
3627fca8a500SRichard Henderson     }
3628a23a9ec6Sbellard     cpu_fprintf(f, "  gen_interm time   %0.1f%%\n",
3629a23a9ec6Sbellard                 (double)s->interm_time / tot * 100.0);
3630a23a9ec6Sbellard     cpu_fprintf(f, "  gen_code time     %0.1f%%\n",
3631a23a9ec6Sbellard                 (double)s->code_time / tot * 100.0);
3632c5cc28ffSAurelien Jarno     cpu_fprintf(f, "optim./code time    %0.1f%%\n",
3633c5cc28ffSAurelien Jarno                 (double)s->opt_time / (s->code_time ? s->code_time : 1)
3634c5cc28ffSAurelien Jarno                 * 100.0);
3635a23a9ec6Sbellard     cpu_fprintf(f, "liveness/code time  %0.1f%%\n",
3636a23a9ec6Sbellard                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
3637a23a9ec6Sbellard     cpu_fprintf(f, "cpu_restore count   %" PRId64 "\n",
3638a23a9ec6Sbellard                 s->restore_count);
3639a23a9ec6Sbellard     cpu_fprintf(f, "  avg cycles        %0.1f\n",
3640a23a9ec6Sbellard                 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
3641a23a9ec6Sbellard }
3642a23a9ec6Sbellard #else
3643405cf9ffSStefan Weil void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
3644a23a9ec6Sbellard {
364524bf7b3aSbellard     cpu_fprintf(f, "[TCG profiler not compiled]\n");
3646a23a9ec6Sbellard }
3647a23a9ec6Sbellard #endif
3648813da627SRichard Henderson 
3649813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
36505872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
36515872bbf2SRichard Henderson 
36525872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
36535872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
36545872bbf2SRichard Henderson 
36555872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
36565872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
36575872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
36585872bbf2SRichard Henderson 
36595872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
36605872bbf2SRichard Henderson */
3661813da627SRichard Henderson 
3662813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
3663813da627SRichard Henderson typedef enum {
3664813da627SRichard Henderson     JIT_NOACTION = 0,
3665813da627SRichard Henderson     JIT_REGISTER_FN,
3666813da627SRichard Henderson     JIT_UNREGISTER_FN
3667813da627SRichard Henderson } jit_actions_t;
3668813da627SRichard Henderson 
3669813da627SRichard Henderson struct jit_code_entry {
3670813da627SRichard Henderson     struct jit_code_entry *next_entry;
3671813da627SRichard Henderson     struct jit_code_entry *prev_entry;
3672813da627SRichard Henderson     const void *symfile_addr;
3673813da627SRichard Henderson     uint64_t symfile_size;
3674813da627SRichard Henderson };
3675813da627SRichard Henderson 
3676813da627SRichard Henderson struct jit_descriptor {
3677813da627SRichard Henderson     uint32_t version;
3678813da627SRichard Henderson     uint32_t action_flag;
3679813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
3680813da627SRichard Henderson     struct jit_code_entry *first_entry;
3681813da627SRichard Henderson };
3682813da627SRichard Henderson 
3683813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
3684813da627SRichard Henderson void __jit_debug_register_code(void)
3685813da627SRichard Henderson {
3686813da627SRichard Henderson     asm("");
3687813da627SRichard Henderson }
3688813da627SRichard Henderson 
3689813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
3690813da627SRichard Henderson    the version before we can set it.  */
3691813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
3692813da627SRichard Henderson 
3693813da627SRichard Henderson /* End GDB interface.  */
3694813da627SRichard Henderson 
3695813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
3696813da627SRichard Henderson {
3697813da627SRichard Henderson     const char *p = strtab + 1;
3698813da627SRichard Henderson 
3699813da627SRichard Henderson     while (1) {
3700813da627SRichard Henderson         if (strcmp(p, str) == 0) {
3701813da627SRichard Henderson             return p - strtab;
3702813da627SRichard Henderson         }
3703813da627SRichard Henderson         p += strlen(p) + 1;
3704813da627SRichard Henderson     }
3705813da627SRichard Henderson }
3706813da627SRichard Henderson 
37075872bbf2SRichard Henderson static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
37082c90784aSRichard Henderson                                  const void *debug_frame,
37092c90784aSRichard Henderson                                  size_t debug_frame_size)
3710813da627SRichard Henderson {
37115872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
37125872bbf2SRichard Henderson         uint32_t  len;
37135872bbf2SRichard Henderson         uint16_t  version;
37145872bbf2SRichard Henderson         uint32_t  abbrev;
37155872bbf2SRichard Henderson         uint8_t   ptr_size;
37165872bbf2SRichard Henderson         uint8_t   cu_die;
37175872bbf2SRichard Henderson         uint16_t  cu_lang;
37185872bbf2SRichard Henderson         uintptr_t cu_low_pc;
37195872bbf2SRichard Henderson         uintptr_t cu_high_pc;
37205872bbf2SRichard Henderson         uint8_t   fn_die;
37215872bbf2SRichard Henderson         char      fn_name[16];
37225872bbf2SRichard Henderson         uintptr_t fn_low_pc;
37235872bbf2SRichard Henderson         uintptr_t fn_high_pc;
37245872bbf2SRichard Henderson         uint8_t   cu_eoc;
37255872bbf2SRichard Henderson     };
3726813da627SRichard Henderson 
3727813da627SRichard Henderson     struct ElfImage {
3728813da627SRichard Henderson         ElfW(Ehdr) ehdr;
3729813da627SRichard Henderson         ElfW(Phdr) phdr;
37305872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
37315872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
37325872bbf2SRichard Henderson         struct DebugInfo di;
37335872bbf2SRichard Henderson         uint8_t    da[24];
37345872bbf2SRichard Henderson         char       str[80];
37355872bbf2SRichard Henderson     };
37365872bbf2SRichard Henderson 
37375872bbf2SRichard Henderson     struct ElfImage *img;
37385872bbf2SRichard Henderson 
37395872bbf2SRichard Henderson     static const struct ElfImage img_template = {
37405872bbf2SRichard Henderson         .ehdr = {
37415872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
37425872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
37435872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
37445872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
37455872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
37465872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
37475872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
37485872bbf2SRichard Henderson             .e_type = ET_EXEC,
37495872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
37505872bbf2SRichard Henderson             .e_version = EV_CURRENT,
37515872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
37525872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
37535872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
37545872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
37555872bbf2SRichard Henderson             .e_phnum = 1,
37565872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
37575872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
37585872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
3759abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
3760abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
3761abbb3eaeSRichard Henderson #endif
3762abbb3eaeSRichard Henderson #ifdef ELF_OSABI
3763abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
3764abbb3eaeSRichard Henderson #endif
37655872bbf2SRichard Henderson         },
37665872bbf2SRichard Henderson         .phdr = {
37675872bbf2SRichard Henderson             .p_type = PT_LOAD,
37685872bbf2SRichard Henderson             .p_flags = PF_X,
37695872bbf2SRichard Henderson         },
37705872bbf2SRichard Henderson         .shdr = {
37715872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
37725872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
37735872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
37745872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
37755872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
37765872bbf2SRichard Henderson             [1] = { /* .text */
37775872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
37785872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
37795872bbf2SRichard Henderson             },
37805872bbf2SRichard Henderson             [2] = { /* .debug_info */
37815872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
37825872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
37835872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
37845872bbf2SRichard Henderson             },
37855872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
37865872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
37875872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
37885872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
37895872bbf2SRichard Henderson             },
37905872bbf2SRichard Henderson             [4] = { /* .debug_frame */
37915872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
37925872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
37935872bbf2SRichard Henderson             },
37945872bbf2SRichard Henderson             [5] = { /* .symtab */
37955872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
37965872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
37975872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
37985872bbf2SRichard Henderson                 .sh_info = 1,
37995872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
38005872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
38015872bbf2SRichard Henderson             },
38025872bbf2SRichard Henderson             [6] = { /* .strtab */
38035872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
38045872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
38055872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
38065872bbf2SRichard Henderson             }
38075872bbf2SRichard Henderson         },
38085872bbf2SRichard Henderson         .sym = {
38095872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
38105872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
38115872bbf2SRichard Henderson                 .st_shndx = 1,
38125872bbf2SRichard Henderson             }
38135872bbf2SRichard Henderson         },
38145872bbf2SRichard Henderson         .di = {
38155872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
38165872bbf2SRichard Henderson             .version = 2,
38175872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
38185872bbf2SRichard Henderson             .cu_die = 1,
38195872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
38205872bbf2SRichard Henderson             .fn_die = 2,
38215872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
38225872bbf2SRichard Henderson         },
38235872bbf2SRichard Henderson         .da = {
38245872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
38255872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
38265872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
38275872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
38285872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
38295872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
38305872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
38315872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
38325872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
38335872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
38345872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
38355872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
38365872bbf2SRichard Henderson             0           /* no more abbrev */
38375872bbf2SRichard Henderson         },
38385872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
38395872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
3840813da627SRichard Henderson     };
3841813da627SRichard Henderson 
3842813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
3843813da627SRichard Henderson     static struct jit_code_entry one_entry;
3844813da627SRichard Henderson 
38455872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
3846813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
38472c90784aSRichard Henderson     DebugFrameHeader *dfh;
3848813da627SRichard Henderson 
38495872bbf2SRichard Henderson     img = g_malloc(img_size);
38505872bbf2SRichard Henderson     *img = img_template;
3851813da627SRichard Henderson 
38525872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
38535872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
38545872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
3855813da627SRichard Henderson 
38565872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
38575872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
38585872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
3859813da627SRichard Henderson 
38605872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
38615872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
38625872bbf2SRichard Henderson 
38635872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
38645872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
38655872bbf2SRichard Henderson 
38665872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
38675872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
38685872bbf2SRichard Henderson 
38695872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
38705872bbf2SRichard Henderson     img->sym[1].st_value = buf;
38715872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
38725872bbf2SRichard Henderson 
38735872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
387445aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
38755872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
387645aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
3877813da627SRichard Henderson 
38782c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
38792c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
38802c90784aSRichard Henderson     dfh->fde.func_start = buf;
38812c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
38822c90784aSRichard Henderson 
3883813da627SRichard Henderson #ifdef DEBUG_JIT
3884813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
3885813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
3886813da627SRichard Henderson     {
3887813da627SRichard Henderson         FILE *f = fopen("/tmp/qemu.jit", "w+b");
3888813da627SRichard Henderson         if (f) {
38895872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
3890813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
3891813da627SRichard Henderson             }
3892813da627SRichard Henderson             fclose(f);
3893813da627SRichard Henderson         }
3894813da627SRichard Henderson     }
3895813da627SRichard Henderson #endif
3896813da627SRichard Henderson 
3897813da627SRichard Henderson     one_entry.symfile_addr = img;
3898813da627SRichard Henderson     one_entry.symfile_size = img_size;
3899813da627SRichard Henderson 
3900813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
3901813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
3902813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
3903813da627SRichard Henderson     __jit_debug_register_code();
3904813da627SRichard Henderson }
3905813da627SRichard Henderson #else
39065872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
39075872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
3908813da627SRichard Henderson 
3909813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size,
39102c90784aSRichard Henderson                                  const void *debug_frame,
39112c90784aSRichard Henderson                                  size_t debug_frame_size)
3912813da627SRichard Henderson {
3913813da627SRichard Henderson }
3914813da627SRichard Henderson 
3915813da627SRichard Henderson void tcg_register_jit(void *buf, size_t buf_size)
3916813da627SRichard Henderson {
3917813da627SRichard Henderson }
3918813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
3919db432672SRichard Henderson 
3920db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
3921db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
3922db432672SRichard Henderson {
3923db432672SRichard Henderson     g_assert_not_reached();
3924db432672SRichard Henderson }
3925db432672SRichard Henderson #endif
3926