xref: /qemu/tcg/tcg.c (revision d4c51a0af35f5a29da3d58e144f8352581a3f34e)
1c896fe29Sbellard /*
2c896fe29Sbellard  * Tiny Code Generator for QEMU
3c896fe29Sbellard  *
4c896fe29Sbellard  * Copyright (c) 2008 Fabrice Bellard
5c896fe29Sbellard  *
6c896fe29Sbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
7c896fe29Sbellard  * of this software and associated documentation files (the "Software"), to deal
8c896fe29Sbellard  * in the Software without restriction, including without limitation the rights
9c896fe29Sbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10c896fe29Sbellard  * copies of the Software, and to permit persons to whom the Software is
11c896fe29Sbellard  * furnished to do so, subject to the following conditions:
12c896fe29Sbellard  *
13c896fe29Sbellard  * The above copyright notice and this permission notice shall be included in
14c896fe29Sbellard  * all copies or substantial portions of the Software.
15c896fe29Sbellard  *
16c896fe29Sbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17c896fe29Sbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18c896fe29Sbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19c896fe29Sbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20c896fe29Sbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21c896fe29Sbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22c896fe29Sbellard  * THE SOFTWARE.
23c896fe29Sbellard  */
24c896fe29Sbellard 
25c896fe29Sbellard /* define it to use liveness analysis (better code) */
268f2e8c07SKirill Batuzov #define USE_TCG_OPTIMIZATIONS
27c896fe29Sbellard 
28757e725bSPeter Maydell #include "qemu/osdep.h"
29cca82982Saurel32 
30813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB.  */
31813da627SRichard Henderson #undef DEBUG_JIT
32813da627SRichard Henderson 
3372fd2efbSEmilio G. Cota #include "qemu/error-report.h"
34f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
351de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
36*d4c51a0aSMarkus Armbruster #include "qemu/qemu-print.h"
371de7afc9SPaolo Bonzini #include "qemu/timer.h"
38c896fe29Sbellard 
39c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU
40c896fe29Sbellard    CPU definitions. Currently they are used for qemu_ld/st
41c896fe29Sbellard    instructions */
42c896fe29Sbellard #define NO_CPU_IO_DEFS
43c896fe29Sbellard #include "cpu.h"
44c896fe29Sbellard 
4563c91552SPaolo Bonzini #include "exec/cpu-common.h"
4663c91552SPaolo Bonzini #include "exec/exec-all.h"
4763c91552SPaolo Bonzini 
48c896fe29Sbellard #include "tcg-op.h"
49813da627SRichard Henderson 
50edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX
51813da627SRichard Henderson # define ELF_CLASS  ELFCLASS32
52edee2579SRichard Henderson #else
53edee2579SRichard Henderson # define ELF_CLASS  ELFCLASS64
54813da627SRichard Henderson #endif
55813da627SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
56813da627SRichard Henderson # define ELF_DATA   ELFDATA2MSB
57813da627SRichard Henderson #else
58813da627SRichard Henderson # define ELF_DATA   ELFDATA2LSB
59813da627SRichard Henderson #endif
60813da627SRichard Henderson 
61c896fe29Sbellard #include "elf.h"
62508127e2SPaolo Bonzini #include "exec/log.h"
633468b59eSEmilio G. Cota #include "sysemu/sysemu.h"
64c896fe29Sbellard 
65ce151109SPeter Maydell /* Forward declarations for functions declared in tcg-target.inc.c and
66ce151109SPeter Maydell    used here. */
67e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s);
68f69d277eSRichard Henderson static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode);
69e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
706ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
712ba7fae2SRichard Henderson                         intptr_t value, intptr_t addend);
72c896fe29Sbellard 
73497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts.  */
74497a22ebSRichard Henderson typedef struct {
75497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
76497a22ebSRichard Henderson     uint32_t id;
77497a22ebSRichard Henderson     uint8_t version;
78497a22ebSRichard Henderson     char augmentation[1];
79497a22ebSRichard Henderson     uint8_t code_align;
80497a22ebSRichard Henderson     uint8_t data_align;
81497a22ebSRichard Henderson     uint8_t return_column;
82497a22ebSRichard Henderson } DebugFrameCIE;
83497a22ebSRichard Henderson 
84497a22ebSRichard Henderson typedef struct QEMU_PACKED {
85497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
86497a22ebSRichard Henderson     uint32_t cie_offset;
87edee2579SRichard Henderson     uintptr_t func_start;
88edee2579SRichard Henderson     uintptr_t func_len;
89497a22ebSRichard Henderson } DebugFrameFDEHeader;
90497a22ebSRichard Henderson 
912c90784aSRichard Henderson typedef struct QEMU_PACKED {
922c90784aSRichard Henderson     DebugFrameCIE cie;
932c90784aSRichard Henderson     DebugFrameFDEHeader fde;
942c90784aSRichard Henderson } DebugFrameHeader;
952c90784aSRichard Henderson 
96813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size,
972c90784aSRichard Henderson                                  const void *debug_frame,
982c90784aSRichard Henderson                                  size_t debug_frame_size)
99813da627SRichard Henderson     __attribute__((unused));
100813da627SRichard Henderson 
101ce151109SPeter Maydell /* Forward declarations for functions declared and used in tcg-target.inc.c. */
102069ea736SRichard Henderson static const char *target_parse_constraint(TCGArgConstraint *ct,
103069ea736SRichard Henderson                                            const char *ct_str, TCGType type);
1042a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
105a05b5b9bSRichard Henderson                        intptr_t arg2);
1062a534affSRichard Henderson static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
107c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1082a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
109c0ad3001SStefan Weil static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
110c0ad3001SStefan Weil                        const int *const_args);
111d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec
112d2fd745fSRichard Henderson static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl,
113d2fd745fSRichard Henderson                            unsigned vece, const TCGArg *args,
114d2fd745fSRichard Henderson                            const int *const_args);
115d2fd745fSRichard Henderson #else
116d2fd745fSRichard Henderson static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl,
117d2fd745fSRichard Henderson                                   unsigned vece, const TCGArg *args,
118d2fd745fSRichard Henderson                                   const int *const_args)
119d2fd745fSRichard Henderson {
120d2fd745fSRichard Henderson     g_assert_not_reached();
121d2fd745fSRichard Henderson }
122d2fd745fSRichard Henderson #endif
1232a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
124a05b5b9bSRichard Henderson                        intptr_t arg2);
12559d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
12659d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
127cf066674SRichard Henderson static void tcg_out_call(TCGContext *s, tcg_insn_unit *target);
128f6c6afc1SRichard Henderson static int tcg_target_const_match(tcg_target_long val, TCGType type,
129c0ad3001SStefan Weil                                   const TCGArgConstraint *arg_ct);
130659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
131659ef5cbSRichard Henderson static bool tcg_out_ldst_finalize(TCGContext *s);
132659ef5cbSRichard Henderson #endif
133c896fe29Sbellard 
134a505785cSEmilio G. Cota #define TCG_HIGHWATER 1024
135a505785cSEmilio G. Cota 
136df2cce29SEmilio G. Cota static TCGContext **tcg_ctxs;
137df2cce29SEmilio G. Cota static unsigned int n_tcg_ctxs;
1381c2adb95SRichard Henderson TCGv_env cpu_env = 0;
139df2cce29SEmilio G. Cota 
140be2cdc5eSEmilio G. Cota struct tcg_region_tree {
141be2cdc5eSEmilio G. Cota     QemuMutex lock;
142be2cdc5eSEmilio G. Cota     GTree *tree;
143be2cdc5eSEmilio G. Cota     /* padding to avoid false sharing is computed at run-time */
144be2cdc5eSEmilio G. Cota };
145be2cdc5eSEmilio G. Cota 
146e8feb96fSEmilio G. Cota /*
147e8feb96fSEmilio G. Cota  * We divide code_gen_buffer into equally-sized "regions" that TCG threads
148e8feb96fSEmilio G. Cota  * dynamically allocate from as demand dictates. Given appropriate region
149e8feb96fSEmilio G. Cota  * sizing, this minimizes flushes even when some TCG threads generate a lot
150e8feb96fSEmilio G. Cota  * more code than others.
151e8feb96fSEmilio G. Cota  */
152e8feb96fSEmilio G. Cota struct tcg_region_state {
153e8feb96fSEmilio G. Cota     QemuMutex lock;
154e8feb96fSEmilio G. Cota 
155e8feb96fSEmilio G. Cota     /* fields set at init time */
156e8feb96fSEmilio G. Cota     void *start;
157e8feb96fSEmilio G. Cota     void *start_aligned;
158e8feb96fSEmilio G. Cota     void *end;
159e8feb96fSEmilio G. Cota     size_t n;
160e8feb96fSEmilio G. Cota     size_t size; /* size of one region */
161e8feb96fSEmilio G. Cota     size_t stride; /* .size + guard size */
162e8feb96fSEmilio G. Cota 
163e8feb96fSEmilio G. Cota     /* fields protected by the lock */
164e8feb96fSEmilio G. Cota     size_t current; /* current region index */
165e8feb96fSEmilio G. Cota     size_t agg_size_full; /* aggregate size of full regions */
166e8feb96fSEmilio G. Cota };
167e8feb96fSEmilio G. Cota 
168e8feb96fSEmilio G. Cota static struct tcg_region_state region;
169be2cdc5eSEmilio G. Cota /*
170be2cdc5eSEmilio G. Cota  * This is an array of struct tcg_region_tree's, with padding.
171be2cdc5eSEmilio G. Cota  * We use void * to simplify the computation of region_trees[i]; each
172be2cdc5eSEmilio G. Cota  * struct is found every tree_size bytes.
173be2cdc5eSEmilio G. Cota  */
174be2cdc5eSEmilio G. Cota static void *region_trees;
175be2cdc5eSEmilio G. Cota static size_t tree_size;
176d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
177b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
178c896fe29Sbellard 
1791813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
1804196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
181c896fe29Sbellard {
182c896fe29Sbellard     *s->code_ptr++ = v;
183c896fe29Sbellard }
184c896fe29Sbellard 
1854196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
1864196dca6SPeter Maydell                                                       uint8_t v)
1875c53bb81SPeter Maydell {
1881813e175SRichard Henderson     *p = v;
1895c53bb81SPeter Maydell }
1901813e175SRichard Henderson #endif
1915c53bb81SPeter Maydell 
1921813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
1934196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
194c896fe29Sbellard {
1951813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
1961813e175SRichard Henderson         *s->code_ptr++ = v;
1971813e175SRichard Henderson     } else {
1981813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
1994387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2001813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
2011813e175SRichard Henderson     }
202c896fe29Sbellard }
203c896fe29Sbellard 
2044196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2054196dca6SPeter Maydell                                                        uint16_t v)
2065c53bb81SPeter Maydell {
2071813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2081813e175SRichard Henderson         *p = v;
2091813e175SRichard Henderson     } else {
2105c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2115c53bb81SPeter Maydell     }
2121813e175SRichard Henderson }
2131813e175SRichard Henderson #endif
2145c53bb81SPeter Maydell 
2151813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
2164196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
217c896fe29Sbellard {
2181813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2191813e175SRichard Henderson         *s->code_ptr++ = v;
2201813e175SRichard Henderson     } else {
2211813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2224387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2231813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
2241813e175SRichard Henderson     }
225c896fe29Sbellard }
226c896fe29Sbellard 
2274196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
2284196dca6SPeter Maydell                                                        uint32_t v)
2295c53bb81SPeter Maydell {
2301813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2311813e175SRichard Henderson         *p = v;
2321813e175SRichard Henderson     } else {
2335c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2345c53bb81SPeter Maydell     }
2351813e175SRichard Henderson }
2361813e175SRichard Henderson #endif
2375c53bb81SPeter Maydell 
2381813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
2394196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
240ac26eb69SRichard Henderson {
2411813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2421813e175SRichard Henderson         *s->code_ptr++ = v;
2431813e175SRichard Henderson     } else {
2441813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2454387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2461813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
2471813e175SRichard Henderson     }
248ac26eb69SRichard Henderson }
249ac26eb69SRichard Henderson 
2504196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
2514196dca6SPeter Maydell                                                        uint64_t v)
2525c53bb81SPeter Maydell {
2531813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2541813e175SRichard Henderson         *p = v;
2551813e175SRichard Henderson     } else {
2565c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2575c53bb81SPeter Maydell     }
2581813e175SRichard Henderson }
2591813e175SRichard Henderson #endif
2605c53bb81SPeter Maydell 
261c896fe29Sbellard /* label relocation processing */
262c896fe29Sbellard 
2631813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
264bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
265c896fe29Sbellard {
266c896fe29Sbellard     TCGRelocation *r;
267c896fe29Sbellard 
268c896fe29Sbellard     if (l->has_value) {
269623e265cSpbrook         /* FIXME: This may break relocations on RISC targets that
270623e265cSpbrook            modify instruction fields in place.  The caller may not have
271623e265cSpbrook            written the initial value.  */
2726ac17786SRichard Henderson         bool ok = patch_reloc(code_ptr, type, l->u.value, addend);
2736ac17786SRichard Henderson         tcg_debug_assert(ok);
274c896fe29Sbellard     } else {
275c896fe29Sbellard         /* add a new relocation entry */
276c896fe29Sbellard         r = tcg_malloc(sizeof(TCGRelocation));
277c896fe29Sbellard         r->type = type;
278c896fe29Sbellard         r->ptr = code_ptr;
279c896fe29Sbellard         r->addend = addend;
280c896fe29Sbellard         r->next = l->u.first_reloc;
281c896fe29Sbellard         l->u.first_reloc = r;
282c896fe29Sbellard     }
283c896fe29Sbellard }
284c896fe29Sbellard 
285bec16311SRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr)
286c896fe29Sbellard {
2872ba7fae2SRichard Henderson     intptr_t value = (intptr_t)ptr;
2881813e175SRichard Henderson     TCGRelocation *r;
289c896fe29Sbellard 
290eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
2911813e175SRichard Henderson 
2921813e175SRichard Henderson     for (r = l->u.first_reloc; r != NULL; r = r->next) {
2936ac17786SRichard Henderson         bool ok = patch_reloc(r->ptr, r->type, value, r->addend);
2946ac17786SRichard Henderson         tcg_debug_assert(ok);
295c896fe29Sbellard     }
2961813e175SRichard Henderson 
297c896fe29Sbellard     l->has_value = 1;
2981813e175SRichard Henderson     l->u.value_ptr = ptr;
299c896fe29Sbellard }
300c896fe29Sbellard 
30142a268c2SRichard Henderson TCGLabel *gen_new_label(void)
302c896fe29Sbellard {
303b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
30451e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
305c896fe29Sbellard 
30651e3972cSRichard Henderson     *l = (TCGLabel){
30751e3972cSRichard Henderson         .id = s->nb_labels++
30851e3972cSRichard Henderson     };
309bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
310bef16ab4SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
311bef16ab4SRichard Henderson #endif
31242a268c2SRichard Henderson 
31342a268c2SRichard Henderson     return l;
314c896fe29Sbellard }
315c896fe29Sbellard 
3169f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3179f754620SRichard Henderson {
3189f754620SRichard Henderson     size_t off = tcg_current_code_size(s);
3199f754620SRichard Henderson     s->tb_jmp_reset_offset[which] = off;
3209f754620SRichard Henderson     /* Make sure that we didn't overflow the stored offset.  */
3219f754620SRichard Henderson     assert(s->tb_jmp_reset_offset[which] == off);
3229f754620SRichard Henderson }
3239f754620SRichard Henderson 
324ce151109SPeter Maydell #include "tcg-target.inc.c"
325c896fe29Sbellard 
326be2cdc5eSEmilio G. Cota /* compare a pointer @ptr and a tb_tc @s */
327be2cdc5eSEmilio G. Cota static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s)
328be2cdc5eSEmilio G. Cota {
329be2cdc5eSEmilio G. Cota     if (ptr >= s->ptr + s->size) {
330be2cdc5eSEmilio G. Cota         return 1;
331be2cdc5eSEmilio G. Cota     } else if (ptr < s->ptr) {
332be2cdc5eSEmilio G. Cota         return -1;
333be2cdc5eSEmilio G. Cota     }
334be2cdc5eSEmilio G. Cota     return 0;
335be2cdc5eSEmilio G. Cota }
336be2cdc5eSEmilio G. Cota 
337be2cdc5eSEmilio G. Cota static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp)
338be2cdc5eSEmilio G. Cota {
339be2cdc5eSEmilio G. Cota     const struct tb_tc *a = ap;
340be2cdc5eSEmilio G. Cota     const struct tb_tc *b = bp;
341be2cdc5eSEmilio G. Cota 
342be2cdc5eSEmilio G. Cota     /*
343be2cdc5eSEmilio G. Cota      * When both sizes are set, we know this isn't a lookup.
344be2cdc5eSEmilio G. Cota      * This is the most likely case: every TB must be inserted; lookups
345be2cdc5eSEmilio G. Cota      * are a lot less frequent.
346be2cdc5eSEmilio G. Cota      */
347be2cdc5eSEmilio G. Cota     if (likely(a->size && b->size)) {
348be2cdc5eSEmilio G. Cota         if (a->ptr > b->ptr) {
349be2cdc5eSEmilio G. Cota             return 1;
350be2cdc5eSEmilio G. Cota         } else if (a->ptr < b->ptr) {
351be2cdc5eSEmilio G. Cota             return -1;
352be2cdc5eSEmilio G. Cota         }
353be2cdc5eSEmilio G. Cota         /* a->ptr == b->ptr should happen only on deletions */
354be2cdc5eSEmilio G. Cota         g_assert(a->size == b->size);
355be2cdc5eSEmilio G. Cota         return 0;
356be2cdc5eSEmilio G. Cota     }
357be2cdc5eSEmilio G. Cota     /*
358be2cdc5eSEmilio G. Cota      * All lookups have either .size field set to 0.
359be2cdc5eSEmilio G. Cota      * From the glib sources we see that @ap is always the lookup key. However
360be2cdc5eSEmilio G. Cota      * the docs provide no guarantee, so we just mark this case as likely.
361be2cdc5eSEmilio G. Cota      */
362be2cdc5eSEmilio G. Cota     if (likely(a->size == 0)) {
363be2cdc5eSEmilio G. Cota         return ptr_cmp_tb_tc(a->ptr, b);
364be2cdc5eSEmilio G. Cota     }
365be2cdc5eSEmilio G. Cota     return ptr_cmp_tb_tc(b->ptr, a);
366be2cdc5eSEmilio G. Cota }
367be2cdc5eSEmilio G. Cota 
368be2cdc5eSEmilio G. Cota static void tcg_region_trees_init(void)
369be2cdc5eSEmilio G. Cota {
370be2cdc5eSEmilio G. Cota     size_t i;
371be2cdc5eSEmilio G. Cota 
372be2cdc5eSEmilio G. Cota     tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize);
373be2cdc5eSEmilio G. Cota     region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size);
374be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
375be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
376be2cdc5eSEmilio G. Cota 
377be2cdc5eSEmilio G. Cota         qemu_mutex_init(&rt->lock);
378be2cdc5eSEmilio G. Cota         rt->tree = g_tree_new(tb_tc_cmp);
379be2cdc5eSEmilio G. Cota     }
380be2cdc5eSEmilio G. Cota }
381be2cdc5eSEmilio G. Cota 
382be2cdc5eSEmilio G. Cota static struct tcg_region_tree *tc_ptr_to_region_tree(void *p)
383be2cdc5eSEmilio G. Cota {
384be2cdc5eSEmilio G. Cota     size_t region_idx;
385be2cdc5eSEmilio G. Cota 
386be2cdc5eSEmilio G. Cota     if (p < region.start_aligned) {
387be2cdc5eSEmilio G. Cota         region_idx = 0;
388be2cdc5eSEmilio G. Cota     } else {
389be2cdc5eSEmilio G. Cota         ptrdiff_t offset = p - region.start_aligned;
390be2cdc5eSEmilio G. Cota 
391be2cdc5eSEmilio G. Cota         if (offset > region.stride * (region.n - 1)) {
392be2cdc5eSEmilio G. Cota             region_idx = region.n - 1;
393be2cdc5eSEmilio G. Cota         } else {
394be2cdc5eSEmilio G. Cota             region_idx = offset / region.stride;
395be2cdc5eSEmilio G. Cota         }
396be2cdc5eSEmilio G. Cota     }
397be2cdc5eSEmilio G. Cota     return region_trees + region_idx * tree_size;
398be2cdc5eSEmilio G. Cota }
399be2cdc5eSEmilio G. Cota 
400be2cdc5eSEmilio G. Cota void tcg_tb_insert(TranslationBlock *tb)
401be2cdc5eSEmilio G. Cota {
402be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
403be2cdc5eSEmilio G. Cota 
404be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
405be2cdc5eSEmilio G. Cota     g_tree_insert(rt->tree, &tb->tc, tb);
406be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
407be2cdc5eSEmilio G. Cota }
408be2cdc5eSEmilio G. Cota 
409be2cdc5eSEmilio G. Cota void tcg_tb_remove(TranslationBlock *tb)
410be2cdc5eSEmilio G. Cota {
411be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
412be2cdc5eSEmilio G. Cota 
413be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
414be2cdc5eSEmilio G. Cota     g_tree_remove(rt->tree, &tb->tc);
415be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
416be2cdc5eSEmilio G. Cota }
417be2cdc5eSEmilio G. Cota 
418be2cdc5eSEmilio G. Cota /*
419be2cdc5eSEmilio G. Cota  * Find the TB 'tb' such that
420be2cdc5eSEmilio G. Cota  * tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size
421be2cdc5eSEmilio G. Cota  * Return NULL if not found.
422be2cdc5eSEmilio G. Cota  */
423be2cdc5eSEmilio G. Cota TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr)
424be2cdc5eSEmilio G. Cota {
425be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr);
426be2cdc5eSEmilio G. Cota     TranslationBlock *tb;
427be2cdc5eSEmilio G. Cota     struct tb_tc s = { .ptr = (void *)tc_ptr };
428be2cdc5eSEmilio G. Cota 
429be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
430be2cdc5eSEmilio G. Cota     tb = g_tree_lookup(rt->tree, &s);
431be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
432be2cdc5eSEmilio G. Cota     return tb;
433be2cdc5eSEmilio G. Cota }
434be2cdc5eSEmilio G. Cota 
435be2cdc5eSEmilio G. Cota static void tcg_region_tree_lock_all(void)
436be2cdc5eSEmilio G. Cota {
437be2cdc5eSEmilio G. Cota     size_t i;
438be2cdc5eSEmilio G. Cota 
439be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
440be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
441be2cdc5eSEmilio G. Cota 
442be2cdc5eSEmilio G. Cota         qemu_mutex_lock(&rt->lock);
443be2cdc5eSEmilio G. Cota     }
444be2cdc5eSEmilio G. Cota }
445be2cdc5eSEmilio G. Cota 
446be2cdc5eSEmilio G. Cota static void tcg_region_tree_unlock_all(void)
447be2cdc5eSEmilio G. Cota {
448be2cdc5eSEmilio G. Cota     size_t i;
449be2cdc5eSEmilio G. Cota 
450be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
451be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
452be2cdc5eSEmilio G. Cota 
453be2cdc5eSEmilio G. Cota         qemu_mutex_unlock(&rt->lock);
454be2cdc5eSEmilio G. Cota     }
455be2cdc5eSEmilio G. Cota }
456be2cdc5eSEmilio G. Cota 
457be2cdc5eSEmilio G. Cota void tcg_tb_foreach(GTraverseFunc func, gpointer user_data)
458be2cdc5eSEmilio G. Cota {
459be2cdc5eSEmilio G. Cota     size_t i;
460be2cdc5eSEmilio G. Cota 
461be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
462be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
463be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
464be2cdc5eSEmilio G. Cota 
465be2cdc5eSEmilio G. Cota         g_tree_foreach(rt->tree, func, user_data);
466be2cdc5eSEmilio G. Cota     }
467be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
468be2cdc5eSEmilio G. Cota }
469be2cdc5eSEmilio G. Cota 
470be2cdc5eSEmilio G. Cota size_t tcg_nb_tbs(void)
471be2cdc5eSEmilio G. Cota {
472be2cdc5eSEmilio G. Cota     size_t nb_tbs = 0;
473be2cdc5eSEmilio G. Cota     size_t i;
474be2cdc5eSEmilio G. Cota 
475be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
476be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
477be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
478be2cdc5eSEmilio G. Cota 
479be2cdc5eSEmilio G. Cota         nb_tbs += g_tree_nnodes(rt->tree);
480be2cdc5eSEmilio G. Cota     }
481be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
482be2cdc5eSEmilio G. Cota     return nb_tbs;
483be2cdc5eSEmilio G. Cota }
484be2cdc5eSEmilio G. Cota 
485be2cdc5eSEmilio G. Cota static void tcg_region_tree_reset_all(void)
486be2cdc5eSEmilio G. Cota {
487be2cdc5eSEmilio G. Cota     size_t i;
488be2cdc5eSEmilio G. Cota 
489be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
490be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
491be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
492be2cdc5eSEmilio G. Cota 
493be2cdc5eSEmilio G. Cota         /* Increment the refcount first so that destroy acts as a reset */
494be2cdc5eSEmilio G. Cota         g_tree_ref(rt->tree);
495be2cdc5eSEmilio G. Cota         g_tree_destroy(rt->tree);
496be2cdc5eSEmilio G. Cota     }
497be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
498be2cdc5eSEmilio G. Cota }
499be2cdc5eSEmilio G. Cota 
500e8feb96fSEmilio G. Cota static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend)
501e8feb96fSEmilio G. Cota {
502e8feb96fSEmilio G. Cota     void *start, *end;
503e8feb96fSEmilio G. Cota 
504e8feb96fSEmilio G. Cota     start = region.start_aligned + curr_region * region.stride;
505e8feb96fSEmilio G. Cota     end = start + region.size;
506e8feb96fSEmilio G. Cota 
507e8feb96fSEmilio G. Cota     if (curr_region == 0) {
508e8feb96fSEmilio G. Cota         start = region.start;
509e8feb96fSEmilio G. Cota     }
510e8feb96fSEmilio G. Cota     if (curr_region == region.n - 1) {
511e8feb96fSEmilio G. Cota         end = region.end;
512e8feb96fSEmilio G. Cota     }
513e8feb96fSEmilio G. Cota 
514e8feb96fSEmilio G. Cota     *pstart = start;
515e8feb96fSEmilio G. Cota     *pend = end;
516e8feb96fSEmilio G. Cota }
517e8feb96fSEmilio G. Cota 
518e8feb96fSEmilio G. Cota static void tcg_region_assign(TCGContext *s, size_t curr_region)
519e8feb96fSEmilio G. Cota {
520e8feb96fSEmilio G. Cota     void *start, *end;
521e8feb96fSEmilio G. Cota 
522e8feb96fSEmilio G. Cota     tcg_region_bounds(curr_region, &start, &end);
523e8feb96fSEmilio G. Cota 
524e8feb96fSEmilio G. Cota     s->code_gen_buffer = start;
525e8feb96fSEmilio G. Cota     s->code_gen_ptr = start;
526e8feb96fSEmilio G. Cota     s->code_gen_buffer_size = end - start;
527e8feb96fSEmilio G. Cota     s->code_gen_highwater = end - TCG_HIGHWATER;
528e8feb96fSEmilio G. Cota }
529e8feb96fSEmilio G. Cota 
530e8feb96fSEmilio G. Cota static bool tcg_region_alloc__locked(TCGContext *s)
531e8feb96fSEmilio G. Cota {
532e8feb96fSEmilio G. Cota     if (region.current == region.n) {
533e8feb96fSEmilio G. Cota         return true;
534e8feb96fSEmilio G. Cota     }
535e8feb96fSEmilio G. Cota     tcg_region_assign(s, region.current);
536e8feb96fSEmilio G. Cota     region.current++;
537e8feb96fSEmilio G. Cota     return false;
538e8feb96fSEmilio G. Cota }
539e8feb96fSEmilio G. Cota 
540e8feb96fSEmilio G. Cota /*
541e8feb96fSEmilio G. Cota  * Request a new region once the one in use has filled up.
542e8feb96fSEmilio G. Cota  * Returns true on error.
543e8feb96fSEmilio G. Cota  */
544e8feb96fSEmilio G. Cota static bool tcg_region_alloc(TCGContext *s)
545e8feb96fSEmilio G. Cota {
546e8feb96fSEmilio G. Cota     bool err;
547e8feb96fSEmilio G. Cota     /* read the region size now; alloc__locked will overwrite it on success */
548e8feb96fSEmilio G. Cota     size_t size_full = s->code_gen_buffer_size;
549e8feb96fSEmilio G. Cota 
550e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
551e8feb96fSEmilio G. Cota     err = tcg_region_alloc__locked(s);
552e8feb96fSEmilio G. Cota     if (!err) {
553e8feb96fSEmilio G. Cota         region.agg_size_full += size_full - TCG_HIGHWATER;
554e8feb96fSEmilio G. Cota     }
555e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
556e8feb96fSEmilio G. Cota     return err;
557e8feb96fSEmilio G. Cota }
558e8feb96fSEmilio G. Cota 
559e8feb96fSEmilio G. Cota /*
560e8feb96fSEmilio G. Cota  * Perform a context's first region allocation.
561e8feb96fSEmilio G. Cota  * This function does _not_ increment region.agg_size_full.
562e8feb96fSEmilio G. Cota  */
563e8feb96fSEmilio G. Cota static inline bool tcg_region_initial_alloc__locked(TCGContext *s)
564e8feb96fSEmilio G. Cota {
565e8feb96fSEmilio G. Cota     return tcg_region_alloc__locked(s);
566e8feb96fSEmilio G. Cota }
567e8feb96fSEmilio G. Cota 
568e8feb96fSEmilio G. Cota /* Call from a safe-work context */
569e8feb96fSEmilio G. Cota void tcg_region_reset_all(void)
570e8feb96fSEmilio G. Cota {
5713468b59eSEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
572e8feb96fSEmilio G. Cota     unsigned int i;
573e8feb96fSEmilio G. Cota 
574e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
575e8feb96fSEmilio G. Cota     region.current = 0;
576e8feb96fSEmilio G. Cota     region.agg_size_full = 0;
577e8feb96fSEmilio G. Cota 
5783468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
5793468b59eSEmilio G. Cota         TCGContext *s = atomic_read(&tcg_ctxs[i]);
5803468b59eSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(s);
581e8feb96fSEmilio G. Cota 
582e8feb96fSEmilio G. Cota         g_assert(!err);
583e8feb96fSEmilio G. Cota     }
584e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
585be2cdc5eSEmilio G. Cota 
586be2cdc5eSEmilio G. Cota     tcg_region_tree_reset_all();
587e8feb96fSEmilio G. Cota }
588e8feb96fSEmilio G. Cota 
5893468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
5903468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
5913468b59eSEmilio G. Cota {
5923468b59eSEmilio G. Cota     return 1;
5933468b59eSEmilio G. Cota }
5943468b59eSEmilio G. Cota #else
5953468b59eSEmilio G. Cota /*
5963468b59eSEmilio G. Cota  * It is likely that some vCPUs will translate more code than others, so we
5973468b59eSEmilio G. Cota  * first try to set more regions than max_cpus, with those regions being of
5983468b59eSEmilio G. Cota  * reasonable size. If that's not possible we make do by evenly dividing
5993468b59eSEmilio G. Cota  * the code_gen_buffer among the vCPUs.
6003468b59eSEmilio G. Cota  */
6013468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
6023468b59eSEmilio G. Cota {
6033468b59eSEmilio G. Cota     size_t i;
6043468b59eSEmilio G. Cota 
6053468b59eSEmilio G. Cota     /* Use a single region if all we have is one vCPU thread */
6063468b59eSEmilio G. Cota     if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) {
6073468b59eSEmilio G. Cota         return 1;
6083468b59eSEmilio G. Cota     }
6093468b59eSEmilio G. Cota 
6103468b59eSEmilio G. Cota     /* Try to have more regions than max_cpus, with each region being >= 2 MB */
6113468b59eSEmilio G. Cota     for (i = 8; i > 0; i--) {
6123468b59eSEmilio G. Cota         size_t regions_per_thread = i;
6133468b59eSEmilio G. Cota         size_t region_size;
6143468b59eSEmilio G. Cota 
6153468b59eSEmilio G. Cota         region_size = tcg_init_ctx.code_gen_buffer_size;
6163468b59eSEmilio G. Cota         region_size /= max_cpus * regions_per_thread;
6173468b59eSEmilio G. Cota 
6183468b59eSEmilio G. Cota         if (region_size >= 2 * 1024u * 1024) {
6193468b59eSEmilio G. Cota             return max_cpus * regions_per_thread;
6203468b59eSEmilio G. Cota         }
6213468b59eSEmilio G. Cota     }
6223468b59eSEmilio G. Cota     /* If we can't, then just allocate one region per vCPU thread */
6233468b59eSEmilio G. Cota     return max_cpus;
6243468b59eSEmilio G. Cota }
6253468b59eSEmilio G. Cota #endif
6263468b59eSEmilio G. Cota 
627e8feb96fSEmilio G. Cota /*
628e8feb96fSEmilio G. Cota  * Initializes region partitioning.
629e8feb96fSEmilio G. Cota  *
630e8feb96fSEmilio G. Cota  * Called at init time from the parent thread (i.e. the one calling
631e8feb96fSEmilio G. Cota  * tcg_context_init), after the target's TCG globals have been set.
6323468b59eSEmilio G. Cota  *
6333468b59eSEmilio G. Cota  * Region partitioning works by splitting code_gen_buffer into separate regions,
6343468b59eSEmilio G. Cota  * and then assigning regions to TCG threads so that the threads can translate
6353468b59eSEmilio G. Cota  * code in parallel without synchronization.
6363468b59eSEmilio G. Cota  *
6373468b59eSEmilio G. Cota  * In softmmu the number of TCG threads is bounded by max_cpus, so we use at
6383468b59eSEmilio G. Cota  * least max_cpus regions in MTTCG. In !MTTCG we use a single region.
6393468b59eSEmilio G. Cota  * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...])
6403468b59eSEmilio G. Cota  * must have been parsed before calling this function, since it calls
6413468b59eSEmilio G. Cota  * qemu_tcg_mttcg_enabled().
6423468b59eSEmilio G. Cota  *
6433468b59eSEmilio G. Cota  * In user-mode we use a single region.  Having multiple regions in user-mode
6443468b59eSEmilio G. Cota  * is not supported, because the number of vCPU threads (recall that each thread
6453468b59eSEmilio G. Cota  * spawned by the guest corresponds to a vCPU thread) is only bounded by the
6463468b59eSEmilio G. Cota  * OS, and usually this number is huge (tens of thousands is not uncommon).
6473468b59eSEmilio G. Cota  * Thus, given this large bound on the number of vCPU threads and the fact
6483468b59eSEmilio G. Cota  * that code_gen_buffer is allocated at compile-time, we cannot guarantee
6493468b59eSEmilio G. Cota  * that the availability of at least one region per vCPU thread.
6503468b59eSEmilio G. Cota  *
6513468b59eSEmilio G. Cota  * However, this user-mode limitation is unlikely to be a significant problem
6523468b59eSEmilio G. Cota  * in practice. Multi-threaded guests share most if not all of their translated
6533468b59eSEmilio G. Cota  * code, which makes parallel code generation less appealing than in softmmu.
654e8feb96fSEmilio G. Cota  */
655e8feb96fSEmilio G. Cota void tcg_region_init(void)
656e8feb96fSEmilio G. Cota {
657e8feb96fSEmilio G. Cota     void *buf = tcg_init_ctx.code_gen_buffer;
658e8feb96fSEmilio G. Cota     void *aligned;
659e8feb96fSEmilio G. Cota     size_t size = tcg_init_ctx.code_gen_buffer_size;
660e8feb96fSEmilio G. Cota     size_t page_size = qemu_real_host_page_size;
661e8feb96fSEmilio G. Cota     size_t region_size;
662e8feb96fSEmilio G. Cota     size_t n_regions;
663e8feb96fSEmilio G. Cota     size_t i;
664e8feb96fSEmilio G. Cota 
6653468b59eSEmilio G. Cota     n_regions = tcg_n_regions();
666e8feb96fSEmilio G. Cota 
667e8feb96fSEmilio G. Cota     /* The first region will be 'aligned - buf' bytes larger than the others */
668e8feb96fSEmilio G. Cota     aligned = QEMU_ALIGN_PTR_UP(buf, page_size);
669e8feb96fSEmilio G. Cota     g_assert(aligned < tcg_init_ctx.code_gen_buffer + size);
670e8feb96fSEmilio G. Cota     /*
671e8feb96fSEmilio G. Cota      * Make region_size a multiple of page_size, using aligned as the start.
672e8feb96fSEmilio G. Cota      * As a result of this we might end up with a few extra pages at the end of
673e8feb96fSEmilio G. Cota      * the buffer; we will assign those to the last region.
674e8feb96fSEmilio G. Cota      */
675e8feb96fSEmilio G. Cota     region_size = (size - (aligned - buf)) / n_regions;
676e8feb96fSEmilio G. Cota     region_size = QEMU_ALIGN_DOWN(region_size, page_size);
677e8feb96fSEmilio G. Cota 
678e8feb96fSEmilio G. Cota     /* A region must have at least 2 pages; one code, one guard */
679e8feb96fSEmilio G. Cota     g_assert(region_size >= 2 * page_size);
680e8feb96fSEmilio G. Cota 
681e8feb96fSEmilio G. Cota     /* init the region struct */
682e8feb96fSEmilio G. Cota     qemu_mutex_init(&region.lock);
683e8feb96fSEmilio G. Cota     region.n = n_regions;
684e8feb96fSEmilio G. Cota     region.size = region_size - page_size;
685e8feb96fSEmilio G. Cota     region.stride = region_size;
686e8feb96fSEmilio G. Cota     region.start = buf;
687e8feb96fSEmilio G. Cota     region.start_aligned = aligned;
688e8feb96fSEmilio G. Cota     /* page-align the end, since its last page will be a guard page */
689e8feb96fSEmilio G. Cota     region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size);
690e8feb96fSEmilio G. Cota     /* account for that last guard page */
691e8feb96fSEmilio G. Cota     region.end -= page_size;
692e8feb96fSEmilio G. Cota 
693e8feb96fSEmilio G. Cota     /* set guard pages */
694e8feb96fSEmilio G. Cota     for (i = 0; i < region.n; i++) {
695e8feb96fSEmilio G. Cota         void *start, *end;
696e8feb96fSEmilio G. Cota         int rc;
697e8feb96fSEmilio G. Cota 
698e8feb96fSEmilio G. Cota         tcg_region_bounds(i, &start, &end);
699e8feb96fSEmilio G. Cota         rc = qemu_mprotect_none(end, page_size);
700e8feb96fSEmilio G. Cota         g_assert(!rc);
701e8feb96fSEmilio G. Cota     }
702e8feb96fSEmilio G. Cota 
703be2cdc5eSEmilio G. Cota     tcg_region_trees_init();
704be2cdc5eSEmilio G. Cota 
7053468b59eSEmilio G. Cota     /* In user-mode we support only one ctx, so do the initial allocation now */
7063468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
707e8feb96fSEmilio G. Cota     {
708e8feb96fSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(tcg_ctx);
709e8feb96fSEmilio G. Cota 
710e8feb96fSEmilio G. Cota         g_assert(!err);
711e8feb96fSEmilio G. Cota     }
7123468b59eSEmilio G. Cota #endif
713e8feb96fSEmilio G. Cota }
714e8feb96fSEmilio G. Cota 
715e8feb96fSEmilio G. Cota /*
7163468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
7173468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
7183468b59eSEmilio G. Cota  * before initiating translation.
7193468b59eSEmilio G. Cota  *
7203468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
7213468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
7223468b59eSEmilio G. Cota  *
7233468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
7243468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
7253468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
7263468b59eSEmilio G. Cota  *
7273468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
7283468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
7293468b59eSEmilio G. Cota  */
7303468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
7313468b59eSEmilio G. Cota void tcg_register_thread(void)
7323468b59eSEmilio G. Cota {
7333468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
7343468b59eSEmilio G. Cota }
7353468b59eSEmilio G. Cota #else
7363468b59eSEmilio G. Cota void tcg_register_thread(void)
7373468b59eSEmilio G. Cota {
7383468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
7393468b59eSEmilio G. Cota     unsigned int i, n;
7403468b59eSEmilio G. Cota     bool err;
7413468b59eSEmilio G. Cota 
7423468b59eSEmilio G. Cota     *s = tcg_init_ctx;
7433468b59eSEmilio G. Cota 
7443468b59eSEmilio G. Cota     /* Relink mem_base.  */
7453468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
7463468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
7473468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
7483468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
7493468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
7503468b59eSEmilio G. Cota         }
7513468b59eSEmilio G. Cota     }
7523468b59eSEmilio G. Cota 
7533468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
7543468b59eSEmilio G. Cota     n = atomic_fetch_inc(&n_tcg_ctxs);
7553468b59eSEmilio G. Cota     g_assert(n < max_cpus);
7563468b59eSEmilio G. Cota     atomic_set(&tcg_ctxs[n], s);
7573468b59eSEmilio G. Cota 
7583468b59eSEmilio G. Cota     tcg_ctx = s;
7593468b59eSEmilio G. Cota     qemu_mutex_lock(&region.lock);
7603468b59eSEmilio G. Cota     err = tcg_region_initial_alloc__locked(tcg_ctx);
7613468b59eSEmilio G. Cota     g_assert(!err);
7623468b59eSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
7633468b59eSEmilio G. Cota }
7643468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
7653468b59eSEmilio G. Cota 
7663468b59eSEmilio G. Cota /*
767e8feb96fSEmilio G. Cota  * Returns the size (in bytes) of all translated code (i.e. from all regions)
768e8feb96fSEmilio G. Cota  * currently in the cache.
769e8feb96fSEmilio G. Cota  * See also: tcg_code_capacity()
770e8feb96fSEmilio G. Cota  * Do not confuse with tcg_current_code_size(); that one applies to a single
771e8feb96fSEmilio G. Cota  * TCG context.
772e8feb96fSEmilio G. Cota  */
773e8feb96fSEmilio G. Cota size_t tcg_code_size(void)
774e8feb96fSEmilio G. Cota {
7753468b59eSEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
776e8feb96fSEmilio G. Cota     unsigned int i;
777e8feb96fSEmilio G. Cota     size_t total;
778e8feb96fSEmilio G. Cota 
779e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
780e8feb96fSEmilio G. Cota     total = region.agg_size_full;
7813468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
7823468b59eSEmilio G. Cota         const TCGContext *s = atomic_read(&tcg_ctxs[i]);
783e8feb96fSEmilio G. Cota         size_t size;
784e8feb96fSEmilio G. Cota 
785e8feb96fSEmilio G. Cota         size = atomic_read(&s->code_gen_ptr) - s->code_gen_buffer;
786e8feb96fSEmilio G. Cota         g_assert(size <= s->code_gen_buffer_size);
787e8feb96fSEmilio G. Cota         total += size;
788e8feb96fSEmilio G. Cota     }
789e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
790e8feb96fSEmilio G. Cota     return total;
791e8feb96fSEmilio G. Cota }
792e8feb96fSEmilio G. Cota 
793e8feb96fSEmilio G. Cota /*
794e8feb96fSEmilio G. Cota  * Returns the code capacity (in bytes) of the entire cache, i.e. including all
795e8feb96fSEmilio G. Cota  * regions.
796e8feb96fSEmilio G. Cota  * See also: tcg_code_size()
797e8feb96fSEmilio G. Cota  */
798e8feb96fSEmilio G. Cota size_t tcg_code_capacity(void)
799e8feb96fSEmilio G. Cota {
800e8feb96fSEmilio G. Cota     size_t guard_size, capacity;
801e8feb96fSEmilio G. Cota 
802e8feb96fSEmilio G. Cota     /* no need for synchronization; these variables are set at init time */
803e8feb96fSEmilio G. Cota     guard_size = region.stride - region.size;
804e8feb96fSEmilio G. Cota     capacity = region.end + guard_size - region.start;
805e8feb96fSEmilio G. Cota     capacity -= region.n * (guard_size + TCG_HIGHWATER);
806e8feb96fSEmilio G. Cota     return capacity;
807e8feb96fSEmilio G. Cota }
808e8feb96fSEmilio G. Cota 
809128ed227SEmilio G. Cota size_t tcg_tb_phys_invalidate_count(void)
810128ed227SEmilio G. Cota {
811128ed227SEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
812128ed227SEmilio G. Cota     unsigned int i;
813128ed227SEmilio G. Cota     size_t total = 0;
814128ed227SEmilio G. Cota 
815128ed227SEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
816128ed227SEmilio G. Cota         const TCGContext *s = atomic_read(&tcg_ctxs[i]);
817128ed227SEmilio G. Cota 
818128ed227SEmilio G. Cota         total += atomic_read(&s->tb_phys_invalidate_count);
819128ed227SEmilio G. Cota     }
820128ed227SEmilio G. Cota     return total;
821128ed227SEmilio G. Cota }
822128ed227SEmilio G. Cota 
823c896fe29Sbellard /* pool based memory allocation */
824c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
825c896fe29Sbellard {
826c896fe29Sbellard     TCGPool *p;
827c896fe29Sbellard     int pool_size;
828c896fe29Sbellard 
829c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
830c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
8317267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
832c896fe29Sbellard         p->size = size;
8334055299eSKirill Batuzov         p->next = s->pool_first_large;
8344055299eSKirill Batuzov         s->pool_first_large = p;
8354055299eSKirill Batuzov         return p->data;
836c896fe29Sbellard     } else {
837c896fe29Sbellard         p = s->pool_current;
838c896fe29Sbellard         if (!p) {
839c896fe29Sbellard             p = s->pool_first;
840c896fe29Sbellard             if (!p)
841c896fe29Sbellard                 goto new_pool;
842c896fe29Sbellard         } else {
843c896fe29Sbellard             if (!p->next) {
844c896fe29Sbellard             new_pool:
845c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
8467267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
847c896fe29Sbellard                 p->size = pool_size;
848c896fe29Sbellard                 p->next = NULL;
849c896fe29Sbellard                 if (s->pool_current)
850c896fe29Sbellard                     s->pool_current->next = p;
851c896fe29Sbellard                 else
852c896fe29Sbellard                     s->pool_first = p;
853c896fe29Sbellard             } else {
854c896fe29Sbellard                 p = p->next;
855c896fe29Sbellard             }
856c896fe29Sbellard         }
857c896fe29Sbellard     }
858c896fe29Sbellard     s->pool_current = p;
859c896fe29Sbellard     s->pool_cur = p->data + size;
860c896fe29Sbellard     s->pool_end = p->data + p->size;
861c896fe29Sbellard     return p->data;
862c896fe29Sbellard }
863c896fe29Sbellard 
864c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
865c896fe29Sbellard {
8664055299eSKirill Batuzov     TCGPool *p, *t;
8674055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
8684055299eSKirill Batuzov         t = p->next;
8694055299eSKirill Batuzov         g_free(p);
8704055299eSKirill Batuzov     }
8714055299eSKirill Batuzov     s->pool_first_large = NULL;
872c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
873c896fe29Sbellard     s->pool_current = NULL;
874c896fe29Sbellard }
875c896fe29Sbellard 
876100b5e01SRichard Henderson typedef struct TCGHelperInfo {
877100b5e01SRichard Henderson     void *func;
878100b5e01SRichard Henderson     const char *name;
879afb49896SRichard Henderson     unsigned flags;
880afb49896SRichard Henderson     unsigned sizemask;
881100b5e01SRichard Henderson } TCGHelperInfo;
882100b5e01SRichard Henderson 
8832ef6175aSRichard Henderson #include "exec/helper-proto.h"
8842ef6175aSRichard Henderson 
885100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = {
8862ef6175aSRichard Henderson #include "exec/helper-tcg.h"
887100b5e01SRichard Henderson };
888619205fdSEmilio G. Cota static GHashTable *helper_table;
889100b5e01SRichard Henderson 
89091478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
891f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
8921c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
8931c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
89491478cefSRichard Henderson 
895c896fe29Sbellard void tcg_context_init(TCGContext *s)
896c896fe29Sbellard {
897100b5e01SRichard Henderson     int op, total_args, n, i;
898c896fe29Sbellard     TCGOpDef *def;
899c896fe29Sbellard     TCGArgConstraint *args_ct;
900c896fe29Sbellard     int *sorted_args;
9011c2adb95SRichard Henderson     TCGTemp *ts;
902c896fe29Sbellard 
903c896fe29Sbellard     memset(s, 0, sizeof(*s));
904c896fe29Sbellard     s->nb_globals = 0;
905c896fe29Sbellard 
906c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
907c896fe29Sbellard        space */
908c896fe29Sbellard     total_args = 0;
909c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
910c896fe29Sbellard         def = &tcg_op_defs[op];
911c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
912c896fe29Sbellard         total_args += n;
913c896fe29Sbellard     }
914c896fe29Sbellard 
9157267c094SAnthony Liguori     args_ct = g_malloc(sizeof(TCGArgConstraint) * total_args);
9167267c094SAnthony Liguori     sorted_args = g_malloc(sizeof(int) * total_args);
917c896fe29Sbellard 
918c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
919c896fe29Sbellard         def = &tcg_op_defs[op];
920c896fe29Sbellard         def->args_ct = args_ct;
921c896fe29Sbellard         def->sorted_args = sorted_args;
922c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
923c896fe29Sbellard         sorted_args += n;
924c896fe29Sbellard         args_ct += n;
925c896fe29Sbellard     }
926c896fe29Sbellard 
9275cd8f621SRichard Henderson     /* Register helpers.  */
92884fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
929619205fdSEmilio G. Cota     helper_table = g_hash_table_new(NULL, NULL);
93084fd9dd3SRichard Henderson 
931100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
93284fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
93372866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
934100b5e01SRichard Henderson     }
9355cd8f621SRichard Henderson 
936c896fe29Sbellard     tcg_target_init(s);
937f69d277eSRichard Henderson     process_op_defs(s);
93891478cefSRichard Henderson 
93991478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
94091478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
94191478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
94291478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
94391478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
94491478cefSRichard Henderson             break;
94591478cefSRichard Henderson         }
94691478cefSRichard Henderson     }
94791478cefSRichard Henderson     for (i = 0; i < n; ++i) {
94891478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
94991478cefSRichard Henderson     }
95091478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
95191478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
95291478cefSRichard Henderson     }
953b1311c4aSEmilio G. Cota 
954b1311c4aSEmilio G. Cota     tcg_ctx = s;
9553468b59eSEmilio G. Cota     /*
9563468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
9573468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
9583468b59eSEmilio G. Cota      * reasoning behind this.
9593468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
9603468b59eSEmilio G. Cota      */
9613468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
962df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
963df2cce29SEmilio G. Cota     n_tcg_ctxs = 1;
9643468b59eSEmilio G. Cota #else
9653468b59eSEmilio G. Cota     tcg_ctxs = g_new(TCGContext *, max_cpus);
9663468b59eSEmilio G. Cota #endif
9671c2adb95SRichard Henderson 
9681c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
9691c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
9701c2adb95SRichard Henderson     cpu_env = temp_tcgv_ptr(ts);
9719002ec79SRichard Henderson }
972b03cce8eSbellard 
9736e3b2bfdSEmilio G. Cota /*
9746e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
9756e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
9766e3b2bfdSEmilio G. Cota  */
9776e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
9786e3b2bfdSEmilio G. Cota {
9796e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
9806e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
9816e3b2bfdSEmilio G. Cota     void *next;
9826e3b2bfdSEmilio G. Cota 
983e8feb96fSEmilio G. Cota  retry:
9846e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
9856e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
9866e3b2bfdSEmilio G. Cota 
9876e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
988e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
9896e3b2bfdSEmilio G. Cota             return NULL;
9906e3b2bfdSEmilio G. Cota         }
991e8feb96fSEmilio G. Cota         goto retry;
992e8feb96fSEmilio G. Cota     }
993e8feb96fSEmilio G. Cota     atomic_set(&s->code_gen_ptr, next);
99457a26946SRichard Henderson     s->data_gen_ptr = NULL;
9956e3b2bfdSEmilio G. Cota     return tb;
9966e3b2bfdSEmilio G. Cota }
9976e3b2bfdSEmilio G. Cota 
9989002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
9999002ec79SRichard Henderson {
10008163b749SRichard Henderson     size_t prologue_size, total_size;
10018163b749SRichard Henderson     void *buf0, *buf1;
10028163b749SRichard Henderson 
10038163b749SRichard Henderson     /* Put the prologue at the beginning of code_gen_buffer.  */
10048163b749SRichard Henderson     buf0 = s->code_gen_buffer;
10055b38ee31SRichard Henderson     total_size = s->code_gen_buffer_size;
10068163b749SRichard Henderson     s->code_ptr = buf0;
10078163b749SRichard Henderson     s->code_buf = buf0;
10085b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
10098163b749SRichard Henderson     s->code_gen_prologue = buf0;
10108163b749SRichard Henderson 
10115b38ee31SRichard Henderson     /* Compute a high-water mark, at which we voluntarily flush the buffer
10125b38ee31SRichard Henderson        and start over.  The size here is arbitrary, significantly larger
10135b38ee31SRichard Henderson        than we expect the code generation for any one opcode to require.  */
10145b38ee31SRichard Henderson     s->code_gen_highwater = s->code_gen_buffer + (total_size - TCG_HIGHWATER);
10155b38ee31SRichard Henderson 
10165b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
10175b38ee31SRichard Henderson     s->pool_labels = NULL;
10185b38ee31SRichard Henderson #endif
10195b38ee31SRichard Henderson 
10208163b749SRichard Henderson     /* Generate the prologue.  */
1021b03cce8eSbellard     tcg_target_qemu_prologue(s);
10225b38ee31SRichard Henderson 
10235b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
10245b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
10255b38ee31SRichard Henderson     {
10265b38ee31SRichard Henderson         bool ok = tcg_out_pool_finalize(s);
10275b38ee31SRichard Henderson         tcg_debug_assert(ok);
10285b38ee31SRichard Henderson     }
10295b38ee31SRichard Henderson #endif
10305b38ee31SRichard Henderson 
10318163b749SRichard Henderson     buf1 = s->code_ptr;
10328163b749SRichard Henderson     flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1);
10338163b749SRichard Henderson 
10348163b749SRichard Henderson     /* Deduct the prologue from the buffer.  */
10358163b749SRichard Henderson     prologue_size = tcg_current_code_size(s);
10368163b749SRichard Henderson     s->code_gen_ptr = buf1;
10378163b749SRichard Henderson     s->code_gen_buffer = buf1;
10388163b749SRichard Henderson     s->code_buf = buf1;
10395b38ee31SRichard Henderson     total_size -= prologue_size;
10408163b749SRichard Henderson     s->code_gen_buffer_size = total_size;
10418163b749SRichard Henderson 
10428163b749SRichard Henderson     tcg_register_jit(s->code_gen_buffer, total_size);
1043d6b64b2bSRichard Henderson 
1044d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
1045d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
10461ee73216SRichard Henderson         qemu_log_lock();
10478163b749SRichard Henderson         qemu_log("PROLOGUE: [size=%zu]\n", prologue_size);
10485b38ee31SRichard Henderson         if (s->data_gen_ptr) {
10495b38ee31SRichard Henderson             size_t code_size = s->data_gen_ptr - buf0;
10505b38ee31SRichard Henderson             size_t data_size = prologue_size - code_size;
10515b38ee31SRichard Henderson             size_t i;
10525b38ee31SRichard Henderson 
10535b38ee31SRichard Henderson             log_disas(buf0, code_size);
10545b38ee31SRichard Henderson 
10555b38ee31SRichard Henderson             for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
10565b38ee31SRichard Henderson                 if (sizeof(tcg_target_ulong) == 8) {
10575b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
10585b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
10595b38ee31SRichard Henderson                              *(uint64_t *)(s->data_gen_ptr + i));
10605b38ee31SRichard Henderson                 } else {
10615b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .long  0x%08x\n",
10625b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
10635b38ee31SRichard Henderson                              *(uint32_t *)(s->data_gen_ptr + i));
10645b38ee31SRichard Henderson                 }
10655b38ee31SRichard Henderson             }
10665b38ee31SRichard Henderson         } else {
10678163b749SRichard Henderson             log_disas(buf0, prologue_size);
10685b38ee31SRichard Henderson         }
1069d6b64b2bSRichard Henderson         qemu_log("\n");
1070d6b64b2bSRichard Henderson         qemu_log_flush();
10711ee73216SRichard Henderson         qemu_log_unlock();
1072d6b64b2bSRichard Henderson     }
1073d6b64b2bSRichard Henderson #endif
1074cedbcb01SEmilio G. Cota 
1075cedbcb01SEmilio G. Cota     /* Assert that goto_ptr is implemented completely.  */
1076cedbcb01SEmilio G. Cota     if (TCG_TARGET_HAS_goto_ptr) {
1077cedbcb01SEmilio G. Cota         tcg_debug_assert(s->code_gen_epilogue != NULL);
1078cedbcb01SEmilio G. Cota     }
1079c896fe29Sbellard }
1080c896fe29Sbellard 
1081c896fe29Sbellard void tcg_func_start(TCGContext *s)
1082c896fe29Sbellard {
1083c896fe29Sbellard     tcg_pool_reset(s);
1084c896fe29Sbellard     s->nb_temps = s->nb_globals;
10850ec9eabcSRichard Henderson 
10860ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
10870ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
10880ec9eabcSRichard Henderson 
1089abebf925SRichard Henderson     s->nb_ops = 0;
1090c896fe29Sbellard     s->nb_labels = 0;
1091c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1092c896fe29Sbellard 
10930a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
10940a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
10950a209d4bSRichard Henderson #endif
10960a209d4bSRichard Henderson 
109715fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
109815fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
1099bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
1100bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
1101bef16ab4SRichard Henderson #endif
1102c896fe29Sbellard }
1103c896fe29Sbellard 
11047ca4b752SRichard Henderson static inline TCGTemp *tcg_temp_alloc(TCGContext *s)
11057ca4b752SRichard Henderson {
11067ca4b752SRichard Henderson     int n = s->nb_temps++;
11077ca4b752SRichard Henderson     tcg_debug_assert(n < TCG_MAX_TEMPS);
11087ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
11097ca4b752SRichard Henderson }
11107ca4b752SRichard Henderson 
11117ca4b752SRichard Henderson static inline TCGTemp *tcg_global_alloc(TCGContext *s)
11127ca4b752SRichard Henderson {
1113fa477d25SRichard Henderson     TCGTemp *ts;
1114fa477d25SRichard Henderson 
11157ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
11167ca4b752SRichard Henderson     s->nb_globals++;
1117fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1118fa477d25SRichard Henderson     ts->temp_global = 1;
1119fa477d25SRichard Henderson 
1120fa477d25SRichard Henderson     return ts;
1121c896fe29Sbellard }
1122c896fe29Sbellard 
1123085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1124b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1125c896fe29Sbellard {
1126c896fe29Sbellard     TCGTemp *ts;
1127c896fe29Sbellard 
1128b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
1129c896fe29Sbellard         tcg_abort();
1130b3a62939SRichard Henderson     }
11317ca4b752SRichard Henderson 
11327ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1133c896fe29Sbellard     ts->base_type = type;
1134c896fe29Sbellard     ts->type = type;
1135c896fe29Sbellard     ts->fixed_reg = 1;
1136c896fe29Sbellard     ts->reg = reg;
1137c896fe29Sbellard     ts->name = name;
1138c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
11397ca4b752SRichard Henderson 
1140085272b3SRichard Henderson     return ts;
1141a7812ae4Spbrook }
1142a7812ae4Spbrook 
1143b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1144a7812ae4Spbrook {
1145b3a62939SRichard Henderson     s->frame_start = start;
1146b3a62939SRichard Henderson     s->frame_end = start + size;
1147085272b3SRichard Henderson     s->frame_temp
1148085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1149b3a62939SRichard Henderson }
1150a7812ae4Spbrook 
1151085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
1152e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
1153c896fe29Sbellard {
1154b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1155dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
11567ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1157b3915dbbSRichard Henderson     int indirect_reg = 0, bigendian = 0;
11587ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
11597ca4b752SRichard Henderson     bigendian = 1;
11607ca4b752SRichard Henderson #endif
1161c896fe29Sbellard 
1162b3915dbbSRichard Henderson     if (!base_ts->fixed_reg) {
11635a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
11645a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1165b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
11665a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
11675a18407fSRichard Henderson                             ? 2 : 1);
11685a18407fSRichard Henderson         indirect_reg = 1;
1169b3915dbbSRichard Henderson     }
1170b3915dbbSRichard Henderson 
11717ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
11727ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1173c896fe29Sbellard         char buf[64];
11747ca4b752SRichard Henderson 
11757ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1176c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1177b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1178c896fe29Sbellard         ts->mem_allocated = 1;
1179b3a62939SRichard Henderson         ts->mem_base = base_ts;
11807ca4b752SRichard Henderson         ts->mem_offset = offset + bigendian * 4;
1181c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1182c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1183c896fe29Sbellard         ts->name = strdup(buf);
1184c896fe29Sbellard 
11857ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
11867ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
11877ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1188b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
11897ca4b752SRichard Henderson         ts2->mem_allocated = 1;
11907ca4b752SRichard Henderson         ts2->mem_base = base_ts;
11917ca4b752SRichard Henderson         ts2->mem_offset = offset + (1 - bigendian) * 4;
1192c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1193c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1194120c1084SRichard Henderson         ts2->name = strdup(buf);
11957ca4b752SRichard Henderson     } else {
1196c896fe29Sbellard         ts->base_type = type;
1197c896fe29Sbellard         ts->type = type;
1198b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1199c896fe29Sbellard         ts->mem_allocated = 1;
1200b3a62939SRichard Henderson         ts->mem_base = base_ts;
1201c896fe29Sbellard         ts->mem_offset = offset;
1202c896fe29Sbellard         ts->name = name;
1203c896fe29Sbellard     }
1204085272b3SRichard Henderson     return ts;
1205c896fe29Sbellard }
1206c896fe29Sbellard 
12075bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local)
1208c896fe29Sbellard {
1209b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1210c896fe29Sbellard     TCGTemp *ts;
1211641d5fbeSbellard     int idx, k;
1212c896fe29Sbellard 
12130ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
12140ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
12150ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
12160ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
12170ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
12180ec9eabcSRichard Henderson 
1219e8996ee0Sbellard         ts = &s->temps[idx];
1220e8996ee0Sbellard         ts->temp_allocated = 1;
12217ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
12227ca4b752SRichard Henderson         tcg_debug_assert(ts->temp_local == temp_local);
1223e8996ee0Sbellard     } else {
12247ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
12257ca4b752SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
12267ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
12277ca4b752SRichard Henderson 
1228c896fe29Sbellard             ts->base_type = type;
1229c896fe29Sbellard             ts->type = TCG_TYPE_I32;
1230e8996ee0Sbellard             ts->temp_allocated = 1;
1231641d5fbeSbellard             ts->temp_local = temp_local;
12327ca4b752SRichard Henderson 
12337ca4b752SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
12347ca4b752SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
12357ca4b752SRichard Henderson             ts2->type = TCG_TYPE_I32;
12367ca4b752SRichard Henderson             ts2->temp_allocated = 1;
12377ca4b752SRichard Henderson             ts2->temp_local = temp_local;
12387ca4b752SRichard Henderson         } else {
1239c896fe29Sbellard             ts->base_type = type;
1240c896fe29Sbellard             ts->type = type;
1241e8996ee0Sbellard             ts->temp_allocated = 1;
1242641d5fbeSbellard             ts->temp_local = temp_local;
1243c896fe29Sbellard         }
1244e8996ee0Sbellard     }
124527bfd83cSPeter Maydell 
124627bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
124727bfd83cSPeter Maydell     s->temps_in_use++;
124827bfd83cSPeter Maydell #endif
1249085272b3SRichard Henderson     return ts;
1250c896fe29Sbellard }
1251c896fe29Sbellard 
1252d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1253d2fd745fSRichard Henderson {
1254d2fd745fSRichard Henderson     TCGTemp *t;
1255d2fd745fSRichard Henderson 
1256d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1257d2fd745fSRichard Henderson     switch (type) {
1258d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1259d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1260d2fd745fSRichard Henderson         break;
1261d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1262d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1263d2fd745fSRichard Henderson         break;
1264d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1265d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1266d2fd745fSRichard Henderson         break;
1267d2fd745fSRichard Henderson     default:
1268d2fd745fSRichard Henderson         g_assert_not_reached();
1269d2fd745fSRichard Henderson     }
1270d2fd745fSRichard Henderson #endif
1271d2fd745fSRichard Henderson 
1272d2fd745fSRichard Henderson     t = tcg_temp_new_internal(type, 0);
1273d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1274d2fd745fSRichard Henderson }
1275d2fd745fSRichard Henderson 
1276d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1277d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1278d2fd745fSRichard Henderson {
1279d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1280d2fd745fSRichard Henderson 
1281d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1282d2fd745fSRichard Henderson 
1283d2fd745fSRichard Henderson     t = tcg_temp_new_internal(t->base_type, 0);
1284d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1285d2fd745fSRichard Henderson }
1286d2fd745fSRichard Henderson 
12875bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1288c896fe29Sbellard {
1289b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1290085272b3SRichard Henderson     int k, idx;
1291c896fe29Sbellard 
129227bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
129327bfd83cSPeter Maydell     s->temps_in_use--;
129427bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
129527bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
129627bfd83cSPeter Maydell     }
129727bfd83cSPeter Maydell #endif
129827bfd83cSPeter Maydell 
1299085272b3SRichard Henderson     tcg_debug_assert(ts->temp_global == 0);
1300eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
1301e8996ee0Sbellard     ts->temp_allocated = 0;
13020ec9eabcSRichard Henderson 
1303085272b3SRichard Henderson     idx = temp_idx(ts);
130418d13fa2SAlexander Graf     k = ts->base_type + (ts->temp_local ? TCG_TYPE_COUNT : 0);
13050ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
1306e8996ee0Sbellard }
1307e8996ee0Sbellard 
1308a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
1309a7812ae4Spbrook {
1310a7812ae4Spbrook     TCGv_i32 t0;
1311a7812ae4Spbrook     t0 = tcg_temp_new_i32();
1312e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
1313e8996ee0Sbellard     return t0;
1314c896fe29Sbellard }
1315c896fe29Sbellard 
1316a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
1317c896fe29Sbellard {
1318a7812ae4Spbrook     TCGv_i64 t0;
1319a7812ae4Spbrook     t0 = tcg_temp_new_i64();
1320e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
1321e8996ee0Sbellard     return t0;
1322c896fe29Sbellard }
1323c896fe29Sbellard 
1324a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
1325bdffd4a9Saurel32 {
1326a7812ae4Spbrook     TCGv_i32 t0;
1327a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
1328bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
1329bdffd4a9Saurel32     return t0;
1330bdffd4a9Saurel32 }
1331bdffd4a9Saurel32 
1332a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
1333bdffd4a9Saurel32 {
1334a7812ae4Spbrook     TCGv_i64 t0;
1335a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
1336bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
1337bdffd4a9Saurel32     return t0;
1338bdffd4a9Saurel32 }
1339bdffd4a9Saurel32 
134027bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
134127bfd83cSPeter Maydell void tcg_clear_temp_count(void)
134227bfd83cSPeter Maydell {
1343b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
134427bfd83cSPeter Maydell     s->temps_in_use = 0;
134527bfd83cSPeter Maydell }
134627bfd83cSPeter Maydell 
134727bfd83cSPeter Maydell int tcg_check_temp_count(void)
134827bfd83cSPeter Maydell {
1349b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
135027bfd83cSPeter Maydell     if (s->temps_in_use) {
135127bfd83cSPeter Maydell         /* Clear the count so that we don't give another
135227bfd83cSPeter Maydell          * warning immediately next time around.
135327bfd83cSPeter Maydell          */
135427bfd83cSPeter Maydell         s->temps_in_use = 0;
135527bfd83cSPeter Maydell         return 1;
135627bfd83cSPeter Maydell     }
135727bfd83cSPeter Maydell     return 0;
135827bfd83cSPeter Maydell }
135927bfd83cSPeter Maydell #endif
136027bfd83cSPeter Maydell 
1361be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1362be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1363be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1364be0f34b5SRichard Henderson {
1365d2fd745fSRichard Henderson     const bool have_vec
1366d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1367d2fd745fSRichard Henderson 
1368be0f34b5SRichard Henderson     switch (op) {
1369be0f34b5SRichard Henderson     case INDEX_op_discard:
1370be0f34b5SRichard Henderson     case INDEX_op_set_label:
1371be0f34b5SRichard Henderson     case INDEX_op_call:
1372be0f34b5SRichard Henderson     case INDEX_op_br:
1373be0f34b5SRichard Henderson     case INDEX_op_mb:
1374be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1375be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1376be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1377be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i32:
1378be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i32:
1379be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i64:
1380be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i64:
1381be0f34b5SRichard Henderson         return true;
1382be0f34b5SRichard Henderson 
1383be0f34b5SRichard Henderson     case INDEX_op_goto_ptr:
1384be0f34b5SRichard Henderson         return TCG_TARGET_HAS_goto_ptr;
1385be0f34b5SRichard Henderson 
1386be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1387be0f34b5SRichard Henderson     case INDEX_op_movi_i32:
1388be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1389be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1390be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1391be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1392be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1393be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1394be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1395be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1396be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1397be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1398be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1399be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1400be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1401be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1402be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1403be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1404be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1405be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1406be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1407be0f34b5SRichard Henderson         return true;
1408be0f34b5SRichard Henderson 
1409be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1410be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1411be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1412be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1413be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1414be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1415be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1416be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1417be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1418be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1419be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1420be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1421be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1422be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1423be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1424be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1425be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1426be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1427be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1428be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1429be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1430be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1431be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1432be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1433be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1434be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1435be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1436be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1437be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1438be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1439be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1440be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1441be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1442be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1443be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1444be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1445be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1446be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1447be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1448be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1449be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1450be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1451be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1452be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1453be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1454be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1455be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1456be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1457be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1458be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1459be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1460be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1461be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1462be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1463be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1464be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1465be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1466be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1467be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1468be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1469be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1470be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1471be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1472be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1473be0f34b5SRichard Henderson 
1474be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1475be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1476be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1477be0f34b5SRichard Henderson 
1478be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1479be0f34b5SRichard Henderson     case INDEX_op_movi_i64:
1480be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1481be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1482be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1483be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1484be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1485be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1486be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1487be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1488be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1489be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1490be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1491be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1492be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1493be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1494be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1495be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1496be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1497be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1498be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1499be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1500be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1501be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1502be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1503be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1504be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1505be0f34b5SRichard Henderson 
1506be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1507be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1508be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1509be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1510be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1511be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1512be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1513be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1514be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1515be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
1516be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
1517be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
1518be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
1519be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
1520be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
1521be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
1522be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
1523be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
1524be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
1525be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
1526be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
1527be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrl_i64_i32;
1528be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
1529be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrh_i64_i32;
1530be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
1531be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
1532be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
1533be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
1534be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
1535be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
1536be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
1537be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
1538be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
1539be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
1540be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
1541be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
1542be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
1543be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
1544be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
1545be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
1546be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
1547be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
1548be0f34b5SRichard Henderson     case INDEX_op_not_i64:
1549be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
1550be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
1551be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
1552be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
1553be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
1554be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
1555be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
1556be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
1557be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
1558be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
1559be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
1560be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
1561be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
1562be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
1563be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
1564be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
1565be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
1566be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
1567be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
1568be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
1569be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
1570be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
1571be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
1572be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
1573be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
1574be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
1575be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
1576be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
1577be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
1578be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
1579be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
1580be0f34b5SRichard Henderson 
1581d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
1582d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
1583d2fd745fSRichard Henderson     case INDEX_op_dupi_vec:
1584d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
1585d2fd745fSRichard Henderson     case INDEX_op_st_vec:
1586d2fd745fSRichard Henderson     case INDEX_op_add_vec:
1587d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
1588d2fd745fSRichard Henderson     case INDEX_op_and_vec:
1589d2fd745fSRichard Henderson     case INDEX_op_or_vec:
1590d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
1591212be173SRichard Henderson     case INDEX_op_cmp_vec:
1592d2fd745fSRichard Henderson         return have_vec;
1593d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
1594d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
1595d2fd745fSRichard Henderson     case INDEX_op_not_vec:
1596d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
1597d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
1598d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
1599d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
1600d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
1601d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
1602d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
16033774030aSRichard Henderson     case INDEX_op_mul_vec:
16043774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
1605d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
1606d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
1607d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
1608d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
1609d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
1610d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
1611d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
1612d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
1613d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
1614d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
1615d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
1616d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
16178afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
16188afaf050SRichard Henderson     case INDEX_op_usadd_vec:
16198afaf050SRichard Henderson     case INDEX_op_sssub_vec:
16208afaf050SRichard Henderson     case INDEX_op_ussub_vec:
16218afaf050SRichard Henderson         return have_vec && TCG_TARGET_HAS_sat_vec;
1622dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
1623dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
1624dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
1625dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
1626dd0a0fcdSRichard Henderson         return have_vec && TCG_TARGET_HAS_minmax_vec;
1627d2fd745fSRichard Henderson 
1628db432672SRichard Henderson     default:
1629db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
1630db432672SRichard Henderson         return true;
1631be0f34b5SRichard Henderson     }
1632be0f34b5SRichard Henderson }
1633be0f34b5SRichard Henderson 
163439cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment
163539cf05d3Sbellard    and endian swap. Maybe it would be better to do the alignment
163639cf05d3Sbellard    and endian swap in tcg_reg_alloc_call(). */
1637ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
1638c896fe29Sbellard {
163975e8b9b7SRichard Henderson     int i, real_args, nb_rets, pi;
1640bbb8a1b4SRichard Henderson     unsigned sizemask, flags;
1641afb49896SRichard Henderson     TCGHelperInfo *info;
164275e8b9b7SRichard Henderson     TCGOp *op;
1643afb49896SRichard Henderson 
1644619205fdSEmilio G. Cota     info = g_hash_table_lookup(helper_table, (gpointer)func);
1645bbb8a1b4SRichard Henderson     flags = info->flags;
1646bbb8a1b4SRichard Henderson     sizemask = info->sizemask;
16472bece2c8SRichard Henderson 
164834b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
164934b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
165034b1a49cSRichard Henderson     /* We have 64-bit values in one register, but need to pass as two
165134b1a49cSRichard Henderson        separate parameters.  Split them.  */
165234b1a49cSRichard Henderson     int orig_sizemask = sizemask;
165334b1a49cSRichard Henderson     int orig_nargs = nargs;
165434b1a49cSRichard Henderson     TCGv_i64 retl, reth;
1655ae8b75dcSRichard Henderson     TCGTemp *split_args[MAX_OPC_PARAM];
165634b1a49cSRichard Henderson 
1657f764718dSRichard Henderson     retl = NULL;
1658f764718dSRichard Henderson     reth = NULL;
165934b1a49cSRichard Henderson     if (sizemask != 0) {
166034b1a49cSRichard Henderson         for (i = real_args = 0; i < nargs; ++i) {
166134b1a49cSRichard Henderson             int is_64bit = sizemask & (1 << (i+1)*2);
166234b1a49cSRichard Henderson             if (is_64bit) {
1663085272b3SRichard Henderson                 TCGv_i64 orig = temp_tcgv_i64(args[i]);
166434b1a49cSRichard Henderson                 TCGv_i32 h = tcg_temp_new_i32();
166534b1a49cSRichard Henderson                 TCGv_i32 l = tcg_temp_new_i32();
166634b1a49cSRichard Henderson                 tcg_gen_extr_i64_i32(l, h, orig);
1667ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(h);
1668ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(l);
166934b1a49cSRichard Henderson             } else {
167034b1a49cSRichard Henderson                 split_args[real_args++] = args[i];
167134b1a49cSRichard Henderson             }
167234b1a49cSRichard Henderson         }
167334b1a49cSRichard Henderson         nargs = real_args;
167434b1a49cSRichard Henderson         args = split_args;
167534b1a49cSRichard Henderson         sizemask = 0;
167634b1a49cSRichard Henderson     }
167734b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
16782bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
16792bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
16802bece2c8SRichard Henderson         int is_signed = sizemask & (2 << (i+1)*2);
16812bece2c8SRichard Henderson         if (!is_64bit) {
16822bece2c8SRichard Henderson             TCGv_i64 temp = tcg_temp_new_i64();
1683085272b3SRichard Henderson             TCGv_i64 orig = temp_tcgv_i64(args[i]);
16842bece2c8SRichard Henderson             if (is_signed) {
16852bece2c8SRichard Henderson                 tcg_gen_ext32s_i64(temp, orig);
16862bece2c8SRichard Henderson             } else {
16872bece2c8SRichard Henderson                 tcg_gen_ext32u_i64(temp, orig);
16882bece2c8SRichard Henderson             }
1689ae8b75dcSRichard Henderson             args[i] = tcgv_i64_temp(temp);
16902bece2c8SRichard Henderson         }
16912bece2c8SRichard Henderson     }
16922bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
16932bece2c8SRichard Henderson 
169415fa08f8SRichard Henderson     op = tcg_emit_op(INDEX_op_call);
169575e8b9b7SRichard Henderson 
169675e8b9b7SRichard Henderson     pi = 0;
1697ae8b75dcSRichard Henderson     if (ret != NULL) {
169834b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
169934b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
170034b1a49cSRichard Henderson         if (orig_sizemask & 1) {
170134b1a49cSRichard Henderson             /* The 32-bit ABI is going to return the 64-bit value in
170234b1a49cSRichard Henderson                the %o0/%o1 register pair.  Prepare for this by using
170334b1a49cSRichard Henderson                two return temporaries, and reassemble below.  */
170434b1a49cSRichard Henderson             retl = tcg_temp_new_i64();
170534b1a49cSRichard Henderson             reth = tcg_temp_new_i64();
1706ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(reth);
1707ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(retl);
170834b1a49cSRichard Henderson             nb_rets = 2;
170934b1a49cSRichard Henderson         } else {
1710ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
171134b1a49cSRichard Henderson             nb_rets = 1;
171234b1a49cSRichard Henderson         }
171334b1a49cSRichard Henderson #else
171434b1a49cSRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) {
171502eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
1716ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1717ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1718a7812ae4Spbrook #else
1719ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1720ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1721a7812ae4Spbrook #endif
1722a7812ae4Spbrook             nb_rets = 2;
172334b1a49cSRichard Henderson         } else {
1724ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1725a7812ae4Spbrook             nb_rets = 1;
1726a7812ae4Spbrook         }
172734b1a49cSRichard Henderson #endif
1728a7812ae4Spbrook     } else {
1729a7812ae4Spbrook         nb_rets = 0;
1730a7812ae4Spbrook     }
1731cd9090aaSRichard Henderson     TCGOP_CALLO(op) = nb_rets;
173275e8b9b7SRichard Henderson 
1733a7812ae4Spbrook     real_args = 0;
1734a7812ae4Spbrook     for (i = 0; i < nargs; i++) {
17352bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
1736bbb8a1b4SRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
173739cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS
173839cf05d3Sbellard             /* some targets want aligned 64 bit args */
1739ebd486d5Smalc             if (real_args & 1) {
174075e8b9b7SRichard Henderson                 op->args[pi++] = TCG_CALL_DUMMY_ARG;
1741ebd486d5Smalc                 real_args++;
174239cf05d3Sbellard             }
174339cf05d3Sbellard #endif
17443f90f252SRichard Henderson            /* If stack grows up, then we will be placing successive
17453f90f252SRichard Henderson               arguments at lower addresses, which means we need to
17463f90f252SRichard Henderson               reverse the order compared to how we would normally
17473f90f252SRichard Henderson               treat either big or little-endian.  For those arguments
17483f90f252SRichard Henderson               that will wind up in registers, this still works for
17493f90f252SRichard Henderson               HPPA (the only current STACK_GROWSUP target) since the
17503f90f252SRichard Henderson               argument registers are *also* allocated in decreasing
17513f90f252SRichard Henderson               order.  If another such target is added, this logic may
17523f90f252SRichard Henderson               have to get more complicated to differentiate between
17533f90f252SRichard Henderson               stack arguments and register arguments.  */
175402eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
1755ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1756ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1757c896fe29Sbellard #else
1758ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1759ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1760c896fe29Sbellard #endif
1761a7812ae4Spbrook             real_args += 2;
17622bece2c8SRichard Henderson             continue;
17632bece2c8SRichard Henderson         }
17642bece2c8SRichard Henderson 
1765ae8b75dcSRichard Henderson         op->args[pi++] = temp_arg(args[i]);
1766a7812ae4Spbrook         real_args++;
1767c896fe29Sbellard     }
176875e8b9b7SRichard Henderson     op->args[pi++] = (uintptr_t)func;
176975e8b9b7SRichard Henderson     op->args[pi++] = flags;
1770cd9090aaSRichard Henderson     TCGOP_CALLI(op) = real_args;
1771a7812ae4Spbrook 
177275e8b9b7SRichard Henderson     /* Make sure the fields didn't overflow.  */
1773cd9090aaSRichard Henderson     tcg_debug_assert(TCGOP_CALLI(op) == real_args);
177475e8b9b7SRichard Henderson     tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
17752bece2c8SRichard Henderson 
177634b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
177734b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
177834b1a49cSRichard Henderson     /* Free all of the parts we allocated above.  */
177934b1a49cSRichard Henderson     for (i = real_args = 0; i < orig_nargs; ++i) {
178034b1a49cSRichard Henderson         int is_64bit = orig_sizemask & (1 << (i+1)*2);
178134b1a49cSRichard Henderson         if (is_64bit) {
1782085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
1783085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
178434b1a49cSRichard Henderson         } else {
178534b1a49cSRichard Henderson             real_args++;
178634b1a49cSRichard Henderson         }
178734b1a49cSRichard Henderson     }
178834b1a49cSRichard Henderson     if (orig_sizemask & 1) {
178934b1a49cSRichard Henderson         /* The 32-bit ABI returned two 32-bit pieces.  Re-assemble them.
179034b1a49cSRichard Henderson            Note that describing these as TCGv_i64 eliminates an unnecessary
179134b1a49cSRichard Henderson            zero-extension that tcg_gen_concat_i32_i64 would create.  */
1792085272b3SRichard Henderson         tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth);
179334b1a49cSRichard Henderson         tcg_temp_free_i64(retl);
179434b1a49cSRichard Henderson         tcg_temp_free_i64(reth);
179534b1a49cSRichard Henderson     }
179634b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
17972bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
17982bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
17992bece2c8SRichard Henderson         if (!is_64bit) {
1800085272b3SRichard Henderson             tcg_temp_free_internal(args[i]);
18012bece2c8SRichard Henderson         }
18022bece2c8SRichard Henderson     }
18032bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
1804a7812ae4Spbrook }
1805c896fe29Sbellard 
18068fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
1807c896fe29Sbellard {
1808ac3b8891SRichard Henderson     int i, n;
1809c896fe29Sbellard     TCGTemp *ts;
1810ac3b8891SRichard Henderson 
1811ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
1812c896fe29Sbellard         ts = &s->temps[i];
1813ac3b8891SRichard Henderson         ts->val_type = (ts->fixed_reg ? TEMP_VAL_REG : TEMP_VAL_MEM);
1814c896fe29Sbellard     }
1815ac3b8891SRichard Henderson     for (n = s->nb_temps; i < n; i++) {
1816e8996ee0Sbellard         ts = &s->temps[i];
1817ac3b8891SRichard Henderson         ts->val_type = (ts->temp_local ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
1818e8996ee0Sbellard         ts->mem_allocated = 0;
1819e8996ee0Sbellard         ts->fixed_reg = 0;
1820e8996ee0Sbellard     }
1821f8b2f202SRichard Henderson 
1822f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
1823c896fe29Sbellard }
1824c896fe29Sbellard 
1825f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
1826f8b2f202SRichard Henderson                                  TCGTemp *ts)
1827c896fe29Sbellard {
18281807f4c4SRichard Henderson     int idx = temp_idx(ts);
1829ac56dd48Spbrook 
1830fa477d25SRichard Henderson     if (ts->temp_global) {
1831ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
1832f8b2f202SRichard Henderson     } else if (ts->temp_local) {
1833641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
1834f8b2f202SRichard Henderson     } else {
1835ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
1836c896fe29Sbellard     }
1837c896fe29Sbellard     return buf;
1838c896fe29Sbellard }
1839c896fe29Sbellard 
184043439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
184143439139SRichard Henderson                              int buf_size, TCGArg arg)
1842f8b2f202SRichard Henderson {
184343439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
1844f8b2f202SRichard Henderson }
1845f8b2f202SRichard Henderson 
18466e085f72SRichard Henderson /* Find helper name.  */
18476e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val)
1848e8996ee0Sbellard {
18496e085f72SRichard Henderson     const char *ret = NULL;
1850619205fdSEmilio G. Cota     if (helper_table) {
1851619205fdSEmilio G. Cota         TCGHelperInfo *info = g_hash_table_lookup(helper_table, (gpointer)val);
185272866e82SRichard Henderson         if (info) {
185372866e82SRichard Henderson             ret = info->name;
185472866e82SRichard Henderson         }
1855e8996ee0Sbellard     }
18566e085f72SRichard Henderson     return ret;
18574dc81f28Sbellard }
18584dc81f28Sbellard 
1859f48f3edeSblueswir1 static const char * const cond_name[] =
1860f48f3edeSblueswir1 {
18610aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
18620aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
1863f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
1864f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
1865f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
1866f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
1867f48f3edeSblueswir1     [TCG_COND_LE] = "le",
1868f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
1869f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
1870f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
1871f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
1872f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
1873f48f3edeSblueswir1 };
1874f48f3edeSblueswir1 
1875f713d6adSRichard Henderson static const char * const ldst_name[] =
1876f713d6adSRichard Henderson {
1877f713d6adSRichard Henderson     [MO_UB]   = "ub",
1878f713d6adSRichard Henderson     [MO_SB]   = "sb",
1879f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
1880f713d6adSRichard Henderson     [MO_LESW] = "lesw",
1881f713d6adSRichard Henderson     [MO_LEUL] = "leul",
1882f713d6adSRichard Henderson     [MO_LESL] = "lesl",
1883f713d6adSRichard Henderson     [MO_LEQ]  = "leq",
1884f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
1885f713d6adSRichard Henderson     [MO_BESW] = "besw",
1886f713d6adSRichard Henderson     [MO_BEUL] = "beul",
1887f713d6adSRichard Henderson     [MO_BESL] = "besl",
1888f713d6adSRichard Henderson     [MO_BEQ]  = "beq",
1889f713d6adSRichard Henderson };
1890f713d6adSRichard Henderson 
18911f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
18921f00b27fSSergey Sorokin #ifdef ALIGNED_ONLY
18931f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
18941f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
18951f00b27fSSergey Sorokin #else
18961f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
18971f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
18981f00b27fSSergey Sorokin #endif
18991f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
19001f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
19011f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
19021f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
19031f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
19041f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
19051f00b27fSSergey Sorokin };
19061f00b27fSSergey Sorokin 
1907b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
1908b016486eSRichard Henderson {
1909b016486eSRichard Henderson     return (d & (d - 1)) == 0;
1910b016486eSRichard Henderson }
1911b016486eSRichard Henderson 
1912b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
1913b016486eSRichard Henderson {
1914b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
1915b016486eSRichard Henderson         return ctz32(d);
1916b016486eSRichard Henderson     } else {
1917b016486eSRichard Henderson         return ctz64(d);
1918b016486eSRichard Henderson     }
1919b016486eSRichard Henderson }
1920b016486eSRichard Henderson 
19211894f69aSRichard Henderson static void tcg_dump_ops(TCGContext *s, bool have_prefs)
1922c896fe29Sbellard {
1923c896fe29Sbellard     char buf[128];
1924c45cb8bbSRichard Henderson     TCGOp *op;
1925c896fe29Sbellard 
192615fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
1927c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
1928c45cb8bbSRichard Henderson         const TCGOpDef *def;
1929c45cb8bbSRichard Henderson         TCGOpcode c;
1930bdfb460eSRichard Henderson         int col = 0;
1931c45cb8bbSRichard Henderson 
1932c45cb8bbSRichard Henderson         c = op->opc;
1933c896fe29Sbellard         def = &tcg_op_defs[c];
1934c45cb8bbSRichard Henderson 
1935765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
1936b016486eSRichard Henderson             nb_oargs = 0;
193715fa08f8SRichard Henderson             col += qemu_log("\n ----");
19389aef40edSRichard Henderson 
19399aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
19409aef40edSRichard Henderson                 target_ulong a;
19417e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
1942efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
19437e4597d7Sbellard #else
1944efee3746SRichard Henderson                 a = op->args[i];
19457e4597d7Sbellard #endif
1946bdfb460eSRichard Henderson                 col += qemu_log(" " TARGET_FMT_lx, a);
1947eeacee4dSBlue Swirl             }
19487e4597d7Sbellard         } else if (c == INDEX_op_call) {
1949c896fe29Sbellard             /* variable number of arguments */
1950cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
1951cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
1952c896fe29Sbellard             nb_cargs = def->nb_cargs;
1953b03cce8eSbellard 
1954cf066674SRichard Henderson             /* function name, flags, out args */
1955bdfb460eSRichard Henderson             col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name,
1956efee3746SRichard Henderson                             tcg_find_helper(s, op->args[nb_oargs + nb_iargs]),
1957efee3746SRichard Henderson                             op->args[nb_oargs + nb_iargs + 1], nb_oargs);
1958b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
195943439139SRichard Henderson                 col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf),
1960efee3746SRichard Henderson                                                        op->args[i]));
1961b03cce8eSbellard             }
1962cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
1963efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
1964cf066674SRichard Henderson                 const char *t = "<dummy>";
1965cf066674SRichard Henderson                 if (arg != TCG_CALL_DUMMY_ARG) {
196643439139SRichard Henderson                     t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
1967b03cce8eSbellard                 }
1968bdfb460eSRichard Henderson                 col += qemu_log(",%s", t);
1969e8996ee0Sbellard             }
1970b03cce8eSbellard         } else {
1971bdfb460eSRichard Henderson             col += qemu_log(" %s ", def->name);
1972c45cb8bbSRichard Henderson 
1973c896fe29Sbellard             nb_oargs = def->nb_oargs;
1974c896fe29Sbellard             nb_iargs = def->nb_iargs;
1975c896fe29Sbellard             nb_cargs = def->nb_cargs;
1976c896fe29Sbellard 
1977d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
1978d2fd745fSRichard Henderson                 col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op),
1979d2fd745fSRichard Henderson                                 8 << TCGOP_VECE(op));
1980d2fd745fSRichard Henderson             }
1981d2fd745fSRichard Henderson 
1982c896fe29Sbellard             k = 0;
1983c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
1984eeacee4dSBlue Swirl                 if (k != 0) {
1985bdfb460eSRichard Henderson                     col += qemu_log(",");
1986eeacee4dSBlue Swirl                 }
198743439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
1988efee3746SRichard Henderson                                                       op->args[k++]));
1989c896fe29Sbellard             }
1990c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
1991eeacee4dSBlue Swirl                 if (k != 0) {
1992bdfb460eSRichard Henderson                     col += qemu_log(",");
1993eeacee4dSBlue Swirl                 }
199443439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
1995efee3746SRichard Henderson                                                       op->args[k++]));
1996c896fe29Sbellard             }
1997be210acbSRichard Henderson             switch (c) {
1998be210acbSRichard Henderson             case INDEX_op_brcond_i32:
1999ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
2000ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
2001be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
2002be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
2003ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
2004be210acbSRichard Henderson             case INDEX_op_setcond_i64:
2005ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
2006212be173SRichard Henderson             case INDEX_op_cmp_vec:
2007efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
2008efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
2009efee3746SRichard Henderson                     col += qemu_log(",%s", cond_name[op->args[k++]]);
2010eeacee4dSBlue Swirl                 } else {
2011efee3746SRichard Henderson                     col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]);
2012eeacee4dSBlue Swirl                 }
2013f48f3edeSblueswir1                 i = 1;
2014be210acbSRichard Henderson                 break;
2015f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
2016f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
2017f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
2018f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
201959227d5dSRichard Henderson                 {
2020efee3746SRichard Henderson                     TCGMemOpIdx oi = op->args[k++];
202159227d5dSRichard Henderson                     TCGMemOp op = get_memop(oi);
202259227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
202359227d5dSRichard Henderson 
202459c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
2025bdfb460eSRichard Henderson                         col += qemu_log(",$0x%x,%u", op, ix);
202659c4b7e8SRichard Henderson                     } else {
20271f00b27fSSergey Sorokin                         const char *s_al, *s_op;
20281f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
202959c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
2030bdfb460eSRichard Henderson                         col += qemu_log(",%s%s,%u", s_al, s_op, ix);
2031f713d6adSRichard Henderson                     }
2032f713d6adSRichard Henderson                     i = 1;
203359227d5dSRichard Henderson                 }
2034f713d6adSRichard Henderson                 break;
2035be210acbSRichard Henderson             default:
2036f48f3edeSblueswir1                 i = 0;
2037be210acbSRichard Henderson                 break;
2038be210acbSRichard Henderson             }
203951e3972cSRichard Henderson             switch (c) {
204051e3972cSRichard Henderson             case INDEX_op_set_label:
204151e3972cSRichard Henderson             case INDEX_op_br:
204251e3972cSRichard Henderson             case INDEX_op_brcond_i32:
204351e3972cSRichard Henderson             case INDEX_op_brcond_i64:
204451e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2045efee3746SRichard Henderson                 col += qemu_log("%s$L%d", k ? "," : "",
2046efee3746SRichard Henderson                                 arg_label(op->args[k])->id);
204751e3972cSRichard Henderson                 i++, k++;
204851e3972cSRichard Henderson                 break;
204951e3972cSRichard Henderson             default:
205051e3972cSRichard Henderson                 break;
2051eeacee4dSBlue Swirl             }
205251e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
2053efee3746SRichard Henderson                 col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]);
2054bdfb460eSRichard Henderson             }
2055bdfb460eSRichard Henderson         }
2056bdfb460eSRichard Henderson 
20571894f69aSRichard Henderson         if (have_prefs || op->life) {
20581894f69aSRichard Henderson             for (; col < 40; ++col) {
2059bdfb460eSRichard Henderson                 putc(' ', qemu_logfile);
2060bdfb460eSRichard Henderson             }
20611894f69aSRichard Henderson         }
20621894f69aSRichard Henderson 
20631894f69aSRichard Henderson         if (op->life) {
20641894f69aSRichard Henderson             unsigned life = op->life;
2065bdfb460eSRichard Henderson 
2066bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
2067bdfb460eSRichard Henderson                 qemu_log("  sync:");
2068bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
2069bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
2070bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2071bdfb460eSRichard Henderson                     }
2072bdfb460eSRichard Henderson                 }
2073bdfb460eSRichard Henderson             }
2074bdfb460eSRichard Henderson             life /= DEAD_ARG;
2075bdfb460eSRichard Henderson             if (life) {
2076bdfb460eSRichard Henderson                 qemu_log("  dead:");
2077bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
2078bdfb460eSRichard Henderson                     if (life & 1) {
2079bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2080bdfb460eSRichard Henderson                     }
2081bdfb460eSRichard Henderson                 }
2082c896fe29Sbellard             }
2083b03cce8eSbellard         }
20841894f69aSRichard Henderson 
20851894f69aSRichard Henderson         if (have_prefs) {
20861894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
20871894f69aSRichard Henderson                 TCGRegSet set = op->output_pref[i];
20881894f69aSRichard Henderson 
20891894f69aSRichard Henderson                 if (i == 0) {
20901894f69aSRichard Henderson                     qemu_log("  pref=");
20911894f69aSRichard Henderson                 } else {
20921894f69aSRichard Henderson                     qemu_log(",");
20931894f69aSRichard Henderson                 }
20941894f69aSRichard Henderson                 if (set == 0) {
20951894f69aSRichard Henderson                     qemu_log("none");
20961894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
20971894f69aSRichard Henderson                     qemu_log("all");
20981894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
20991894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
21001894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
21011894f69aSRichard Henderson                     qemu_log("%s", tcg_target_reg_names[reg]);
21021894f69aSRichard Henderson #endif
21031894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
21041894f69aSRichard Henderson                     qemu_log("%#x", (uint32_t)set);
21051894f69aSRichard Henderson                 } else {
21061894f69aSRichard Henderson                     qemu_log("%#" PRIx64, (uint64_t)set);
21071894f69aSRichard Henderson                 }
21081894f69aSRichard Henderson             }
21091894f69aSRichard Henderson         }
21101894f69aSRichard Henderson 
2111eeacee4dSBlue Swirl         qemu_log("\n");
2112c896fe29Sbellard     }
2113c896fe29Sbellard }
2114c896fe29Sbellard 
2115c896fe29Sbellard /* we give more priority to constraints with less registers */
2116c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2117c896fe29Sbellard {
2118c896fe29Sbellard     const TCGArgConstraint *arg_ct;
2119c896fe29Sbellard 
2120c896fe29Sbellard     int i, n;
2121c896fe29Sbellard     arg_ct = &def->args_ct[k];
2122c896fe29Sbellard     if (arg_ct->ct & TCG_CT_ALIAS) {
2123c896fe29Sbellard         /* an alias is equivalent to a single register */
2124c896fe29Sbellard         n = 1;
2125c896fe29Sbellard     } else {
2126c896fe29Sbellard         if (!(arg_ct->ct & TCG_CT_REG))
2127c896fe29Sbellard             return 0;
2128c896fe29Sbellard         n = 0;
2129c896fe29Sbellard         for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
2130c896fe29Sbellard             if (tcg_regset_test_reg(arg_ct->u.regs, i))
2131c896fe29Sbellard                 n++;
2132c896fe29Sbellard         }
2133c896fe29Sbellard     }
2134c896fe29Sbellard     return TCG_TARGET_NB_REGS - n + 1;
2135c896fe29Sbellard }
2136c896fe29Sbellard 
2137c896fe29Sbellard /* sort from highest priority to lowest */
2138c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2139c896fe29Sbellard {
2140c896fe29Sbellard     int i, j, p1, p2, tmp;
2141c896fe29Sbellard 
2142c896fe29Sbellard     for(i = 0; i < n; i++)
2143c896fe29Sbellard         def->sorted_args[start + i] = start + i;
2144c896fe29Sbellard     if (n <= 1)
2145c896fe29Sbellard         return;
2146c896fe29Sbellard     for(i = 0; i < n - 1; i++) {
2147c896fe29Sbellard         for(j = i + 1; j < n; j++) {
2148c896fe29Sbellard             p1 = get_constraint_priority(def, def->sorted_args[start + i]);
2149c896fe29Sbellard             p2 = get_constraint_priority(def, def->sorted_args[start + j]);
2150c896fe29Sbellard             if (p1 < p2) {
2151c896fe29Sbellard                 tmp = def->sorted_args[start + i];
2152c896fe29Sbellard                 def->sorted_args[start + i] = def->sorted_args[start + j];
2153c896fe29Sbellard                 def->sorted_args[start + j] = tmp;
2154c896fe29Sbellard             }
2155c896fe29Sbellard         }
2156c896fe29Sbellard     }
2157c896fe29Sbellard }
2158c896fe29Sbellard 
2159f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2160c896fe29Sbellard {
2161a9751609SRichard Henderson     TCGOpcode op;
2162c896fe29Sbellard 
2163f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
2164f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
2165f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
2166069ea736SRichard Henderson         TCGType type;
2167069ea736SRichard Henderson         int i, nb_args;
2168f69d277eSRichard Henderson 
2169f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
2170f69d277eSRichard Henderson             continue;
2171f69d277eSRichard Henderson         }
2172f69d277eSRichard Henderson 
2173c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
2174f69d277eSRichard Henderson         if (nb_args == 0) {
2175f69d277eSRichard Henderson             continue;
2176f69d277eSRichard Henderson         }
2177f69d277eSRichard Henderson 
2178f69d277eSRichard Henderson         tdefs = tcg_target_op_def(op);
2179f69d277eSRichard Henderson         /* Missing TCGTargetOpDef entry. */
2180f69d277eSRichard Henderson         tcg_debug_assert(tdefs != NULL);
2181f69d277eSRichard Henderson 
2182069ea736SRichard Henderson         type = (def->flags & TCG_OPF_64BIT ? TCG_TYPE_I64 : TCG_TYPE_I32);
2183c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2184f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
2185f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2186eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2187f69d277eSRichard Henderson 
2188ccb1bb66SRichard Henderson             def->args_ct[i].u.regs = 0;
2189c896fe29Sbellard             def->args_ct[i].ct = 0;
219017280ff4SRichard Henderson             while (*ct_str != '\0') {
219117280ff4SRichard Henderson                 switch(*ct_str) {
219217280ff4SRichard Henderson                 case '0' ... '9':
219317280ff4SRichard Henderson                     {
219417280ff4SRichard Henderson                         int oarg = *ct_str - '0';
219517280ff4SRichard Henderson                         tcg_debug_assert(ct_str == tdefs->args_ct_str[i]);
2196eabb7b91SAurelien Jarno                         tcg_debug_assert(oarg < def->nb_oargs);
2197eabb7b91SAurelien Jarno                         tcg_debug_assert(def->args_ct[oarg].ct & TCG_CT_REG);
219817280ff4SRichard Henderson                         /* TCG_CT_ALIAS is for the output arguments.
219917280ff4SRichard Henderson                            The input is tagged with TCG_CT_IALIAS. */
2200c896fe29Sbellard                         def->args_ct[i] = def->args_ct[oarg];
220117280ff4SRichard Henderson                         def->args_ct[oarg].ct |= TCG_CT_ALIAS;
22025ff9d6a4Sbellard                         def->args_ct[oarg].alias_index = i;
2203c896fe29Sbellard                         def->args_ct[i].ct |= TCG_CT_IALIAS;
22045ff9d6a4Sbellard                         def->args_ct[i].alias_index = oarg;
220517280ff4SRichard Henderson                     }
220617280ff4SRichard Henderson                     ct_str++;
2207c896fe29Sbellard                     break;
220882790a87SRichard Henderson                 case '&':
220982790a87SRichard Henderson                     def->args_ct[i].ct |= TCG_CT_NEWREG;
221082790a87SRichard Henderson                     ct_str++;
221182790a87SRichard Henderson                     break;
2212c896fe29Sbellard                 case 'i':
2213c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2214c896fe29Sbellard                     ct_str++;
2215c896fe29Sbellard                     break;
2216c896fe29Sbellard                 default:
2217069ea736SRichard Henderson                     ct_str = target_parse_constraint(&def->args_ct[i],
2218069ea736SRichard Henderson                                                      ct_str, type);
2219f69d277eSRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2220069ea736SRichard Henderson                     tcg_debug_assert(ct_str != NULL);
2221c896fe29Sbellard                 }
2222c896fe29Sbellard             }
2223c896fe29Sbellard         }
2224c896fe29Sbellard 
2225c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2226eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2227c68aaa18SStefan Weil 
2228c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
2229c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
2230c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
2231c896fe29Sbellard     }
2232c896fe29Sbellard }
2233c896fe29Sbellard 
22340c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
22350c627cdcSRichard Henderson {
2236d88a117eSRichard Henderson     TCGLabel *label;
2237d88a117eSRichard Henderson 
2238d88a117eSRichard Henderson     switch (op->opc) {
2239d88a117eSRichard Henderson     case INDEX_op_br:
2240d88a117eSRichard Henderson         label = arg_label(op->args[0]);
2241d88a117eSRichard Henderson         label->refs--;
2242d88a117eSRichard Henderson         break;
2243d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
2244d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
2245d88a117eSRichard Henderson         label = arg_label(op->args[3]);
2246d88a117eSRichard Henderson         label->refs--;
2247d88a117eSRichard Henderson         break;
2248d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
2249d88a117eSRichard Henderson         label = arg_label(op->args[5]);
2250d88a117eSRichard Henderson         label->refs--;
2251d88a117eSRichard Henderson         break;
2252d88a117eSRichard Henderson     default:
2253d88a117eSRichard Henderson         break;
2254d88a117eSRichard Henderson     }
2255d88a117eSRichard Henderson 
225615fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
225715fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
2258abebf925SRichard Henderson     s->nb_ops--;
22590c627cdcSRichard Henderson 
22600c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
2261c3fac113SEmilio G. Cota     atomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
22620c627cdcSRichard Henderson #endif
22630c627cdcSRichard Henderson }
22640c627cdcSRichard Henderson 
226515fa08f8SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc)
226615fa08f8SRichard Henderson {
226715fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
226815fa08f8SRichard Henderson     TCGOp *op;
226915fa08f8SRichard Henderson 
227015fa08f8SRichard Henderson     if (likely(QTAILQ_EMPTY(&s->free_ops))) {
227115fa08f8SRichard Henderson         op = tcg_malloc(sizeof(TCGOp));
227215fa08f8SRichard Henderson     } else {
227315fa08f8SRichard Henderson         op = QTAILQ_FIRST(&s->free_ops);
227415fa08f8SRichard Henderson         QTAILQ_REMOVE(&s->free_ops, op, link);
227515fa08f8SRichard Henderson     }
227615fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
227715fa08f8SRichard Henderson     op->opc = opc;
2278abebf925SRichard Henderson     s->nb_ops++;
227915fa08f8SRichard Henderson 
228015fa08f8SRichard Henderson     return op;
228115fa08f8SRichard Henderson }
228215fa08f8SRichard Henderson 
228315fa08f8SRichard Henderson TCGOp *tcg_emit_op(TCGOpcode opc)
228415fa08f8SRichard Henderson {
228515fa08f8SRichard Henderson     TCGOp *op = tcg_op_alloc(opc);
228615fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
228715fa08f8SRichard Henderson     return op;
228815fa08f8SRichard Henderson }
228915fa08f8SRichard Henderson 
2290ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
22915a18407fSRichard Henderson {
229215fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
229315fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
22945a18407fSRichard Henderson     return new_op;
22955a18407fSRichard Henderson }
22965a18407fSRichard Henderson 
2297ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
22985a18407fSRichard Henderson {
229915fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
230015fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
23015a18407fSRichard Henderson     return new_op;
23025a18407fSRichard Henderson }
23035a18407fSRichard Henderson 
2304b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
2305b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s)
2306b4fc67c7SRichard Henderson {
2307b4fc67c7SRichard Henderson     TCGOp *op, *op_next;
2308b4fc67c7SRichard Henderson     bool dead = false;
2309b4fc67c7SRichard Henderson 
2310b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
2311b4fc67c7SRichard Henderson         bool remove = dead;
2312b4fc67c7SRichard Henderson         TCGLabel *label;
2313b4fc67c7SRichard Henderson         int call_flags;
2314b4fc67c7SRichard Henderson 
2315b4fc67c7SRichard Henderson         switch (op->opc) {
2316b4fc67c7SRichard Henderson         case INDEX_op_set_label:
2317b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
2318b4fc67c7SRichard Henderson             if (label->refs == 0) {
2319b4fc67c7SRichard Henderson                 /*
2320b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
2321b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
2322b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
2323b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
2324b4fc67c7SRichard Henderson                  * little to be gained by iterating.
2325b4fc67c7SRichard Henderson                  */
2326b4fc67c7SRichard Henderson                 remove = true;
2327b4fc67c7SRichard Henderson             } else {
2328b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
2329b4fc67c7SRichard Henderson                 dead = false;
2330b4fc67c7SRichard Henderson                 remove = false;
2331b4fc67c7SRichard Henderson 
2332b4fc67c7SRichard Henderson                 /*
2333b4fc67c7SRichard Henderson                  * Optimization can fold conditional branches to unconditional.
2334b4fc67c7SRichard Henderson                  * If we find a label with one reference which is preceded by
2335b4fc67c7SRichard Henderson                  * an unconditional branch to it, remove both.  This needed to
2336b4fc67c7SRichard Henderson                  * wait until the dead code in between them was removed.
2337b4fc67c7SRichard Henderson                  */
2338b4fc67c7SRichard Henderson                 if (label->refs == 1) {
2339eae3eb3eSPaolo Bonzini                     TCGOp *op_prev = QTAILQ_PREV(op, link);
2340b4fc67c7SRichard Henderson                     if (op_prev->opc == INDEX_op_br &&
2341b4fc67c7SRichard Henderson                         label == arg_label(op_prev->args[0])) {
2342b4fc67c7SRichard Henderson                         tcg_op_remove(s, op_prev);
2343b4fc67c7SRichard Henderson                         remove = true;
2344b4fc67c7SRichard Henderson                     }
2345b4fc67c7SRichard Henderson                 }
2346b4fc67c7SRichard Henderson             }
2347b4fc67c7SRichard Henderson             break;
2348b4fc67c7SRichard Henderson 
2349b4fc67c7SRichard Henderson         case INDEX_op_br:
2350b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
2351b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
2352b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
2353b4fc67c7SRichard Henderson             dead = true;
2354b4fc67c7SRichard Henderson             break;
2355b4fc67c7SRichard Henderson 
2356b4fc67c7SRichard Henderson         case INDEX_op_call:
2357b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
2358b4fc67c7SRichard Henderson             call_flags = op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1];
2359b4fc67c7SRichard Henderson             if (call_flags & TCG_CALL_NO_RETURN) {
2360b4fc67c7SRichard Henderson                 dead = true;
2361b4fc67c7SRichard Henderson             }
2362b4fc67c7SRichard Henderson             break;
2363b4fc67c7SRichard Henderson 
2364b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
2365b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
2366b4fc67c7SRichard Henderson             remove = false;
2367b4fc67c7SRichard Henderson             break;
2368b4fc67c7SRichard Henderson 
2369b4fc67c7SRichard Henderson         default:
2370b4fc67c7SRichard Henderson             break;
2371b4fc67c7SRichard Henderson         }
2372b4fc67c7SRichard Henderson 
2373b4fc67c7SRichard Henderson         if (remove) {
2374b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
2375b4fc67c7SRichard Henderson         }
2376b4fc67c7SRichard Henderson     }
2377b4fc67c7SRichard Henderson }
2378b4fc67c7SRichard Henderson 
2379c70fbf0aSRichard Henderson #define TS_DEAD  1
2380c70fbf0aSRichard Henderson #define TS_MEM   2
2381c70fbf0aSRichard Henderson 
23825a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
23835a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
23845a18407fSRichard Henderson 
238525f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
238625f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
238725f49c5fSRichard Henderson {
238825f49c5fSRichard Henderson     return ts->state_ptr;
238925f49c5fSRichard Henderson }
239025f49c5fSRichard Henderson 
239125f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
239225f49c5fSRichard Henderson  * maximal regset for its type.
239325f49c5fSRichard Henderson  */
239425f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
239525f49c5fSRichard Henderson {
239625f49c5fSRichard Henderson     *la_temp_pref(ts)
239725f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
239825f49c5fSRichard Henderson }
239925f49c5fSRichard Henderson 
24009c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
24019c43b68dSAurelien Jarno    should be in memory. */
24022616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
2403c896fe29Sbellard {
2404b83eabeaSRichard Henderson     int i;
2405b83eabeaSRichard Henderson 
2406b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2407b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
240825f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2409b83eabeaSRichard Henderson     }
2410b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2411b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
241225f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2413b83eabeaSRichard Henderson     }
2414c896fe29Sbellard }
2415c896fe29Sbellard 
24169c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
24179c43b68dSAurelien Jarno    and local temps should be in memory. */
24182616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
2419641d5fbeSbellard {
2420b83eabeaSRichard Henderson     int i;
2421641d5fbeSbellard 
2422b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2423b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
242425f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2425c70fbf0aSRichard Henderson     }
2426b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2427b83eabeaSRichard Henderson         s->temps[i].state = (s->temps[i].temp_local
2428b83eabeaSRichard Henderson                              ? TS_DEAD | TS_MEM
2429b83eabeaSRichard Henderson                              : TS_DEAD);
243025f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2431641d5fbeSbellard     }
2432641d5fbeSbellard }
2433641d5fbeSbellard 
2434f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
2435f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
2436f65a061cSRichard Henderson {
2437f65a061cSRichard Henderson     int i;
2438f65a061cSRichard Henderson 
2439f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
244025f49c5fSRichard Henderson         int state = s->temps[i].state;
244125f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
244225f49c5fSRichard Henderson         if (state == TS_DEAD) {
244325f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
244425f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
244525f49c5fSRichard Henderson         }
2446f65a061cSRichard Henderson     }
2447f65a061cSRichard Henderson }
2448f65a061cSRichard Henderson 
2449f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
2450f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
2451f65a061cSRichard Henderson {
2452f65a061cSRichard Henderson     int i;
2453f65a061cSRichard Henderson 
2454f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
2455f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
245625f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
245725f49c5fSRichard Henderson     }
245825f49c5fSRichard Henderson }
245925f49c5fSRichard Henderson 
246025f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
246125f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
246225f49c5fSRichard Henderson {
246325f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
246425f49c5fSRichard Henderson     int i;
246525f49c5fSRichard Henderson 
246625f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
246725f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
246825f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
246925f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
247025f49c5fSRichard Henderson             TCGRegSet set = *pset;
247125f49c5fSRichard Henderson 
247225f49c5fSRichard Henderson             set &= mask;
247325f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
247425f49c5fSRichard Henderson             if (set == 0) {
247525f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
247625f49c5fSRichard Henderson             }
247725f49c5fSRichard Henderson             *pset = set;
247825f49c5fSRichard Henderson         }
2479f65a061cSRichard Henderson     }
2480f65a061cSRichard Henderson }
2481f65a061cSRichard Henderson 
2482a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
2483c896fe29Sbellard    given input arguments is dead. Instructions updating dead
2484c896fe29Sbellard    temporaries are removed. */
2485b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s)
2486c896fe29Sbellard {
2487c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
24882616c808SRichard Henderson     int nb_temps = s->nb_temps;
248915fa08f8SRichard Henderson     TCGOp *op, *op_prev;
249025f49c5fSRichard Henderson     TCGRegSet *prefs;
249125f49c5fSRichard Henderson     int i;
249225f49c5fSRichard Henderson 
249325f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
249425f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
249525f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
249625f49c5fSRichard Henderson     }
2497c896fe29Sbellard 
2498ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
24992616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
2500c896fe29Sbellard 
2501eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
250225f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
2503c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
2504c45cb8bbSRichard Henderson         bool have_opc_new2;
2505a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
250625f49c5fSRichard Henderson         TCGTemp *ts;
2507c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2508c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2509c45cb8bbSRichard Henderson 
2510c45cb8bbSRichard Henderson         switch (opc) {
2511c896fe29Sbellard         case INDEX_op_call:
2512c6e113f5Sbellard             {
2513c6e113f5Sbellard                 int call_flags;
251425f49c5fSRichard Henderson                 int nb_call_regs;
2515c6e113f5Sbellard 
2516cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
2517cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
2518efee3746SRichard Henderson                 call_flags = op->args[nb_oargs + nb_iargs + 1];
2519c6e113f5Sbellard 
2520c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
252178505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
2522c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
252325f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
252425f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
2525c6e113f5Sbellard                             goto do_not_remove_call;
2526c6e113f5Sbellard                         }
25279c43b68dSAurelien Jarno                     }
2528c45cb8bbSRichard Henderson                     goto do_remove;
2529152c35aaSRichard Henderson                 }
2530c6e113f5Sbellard             do_not_remove_call:
2531c896fe29Sbellard 
253225f49c5fSRichard Henderson                 /* Output args are dead.  */
2533c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
253425f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
253525f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
2536a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
25376b64b624SAurelien Jarno                     }
253825f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
2539a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
25409c43b68dSAurelien Jarno                     }
254125f49c5fSRichard Henderson                     ts->state = TS_DEAD;
254225f49c5fSRichard Henderson                     la_reset_pref(ts);
254325f49c5fSRichard Henderson 
254425f49c5fSRichard Henderson                     /* Not used -- it will be tcg_target_call_oarg_regs[i].  */
254525f49c5fSRichard Henderson                     op->output_pref[i] = 0;
2546c896fe29Sbellard                 }
2547c896fe29Sbellard 
254878505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
254978505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
2550f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
2551c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
2552f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
2553b9c18f56Saurel32                 }
2554c896fe29Sbellard 
255525f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
2556866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
255725f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
255825f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
2559a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
2560c896fe29Sbellard                     }
2561c896fe29Sbellard                 }
256225f49c5fSRichard Henderson 
256325f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
256425f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
256525f49c5fSRichard Henderson 
256625f49c5fSRichard Henderson                 nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
256725f49c5fSRichard Henderson 
256825f49c5fSRichard Henderson                 /* Input arguments are live for preceding opcodes.  */
256925f49c5fSRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
257025f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
257125f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
257225f49c5fSRichard Henderson                         /* For those arguments that die, and will be allocated
257325f49c5fSRichard Henderson                          * in registers, clear the register set for that arg,
257425f49c5fSRichard Henderson                          * to be filled in below.  For args that will be on
257525f49c5fSRichard Henderson                          * the stack, reset to any available reg.
257625f49c5fSRichard Henderson                          */
257725f49c5fSRichard Henderson                         *la_temp_pref(ts)
257825f49c5fSRichard Henderson                             = (i < nb_call_regs ? 0 :
257925f49c5fSRichard Henderson                                tcg_target_available_regs[ts->type]);
258025f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
258125f49c5fSRichard Henderson                     }
258225f49c5fSRichard Henderson                 }
258325f49c5fSRichard Henderson 
258425f49c5fSRichard Henderson                 /* For each input argument, add its input register to prefs.
258525f49c5fSRichard Henderson                    If a temp is used once, this produces a single set bit.  */
258625f49c5fSRichard Henderson                 for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) {
258725f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
258825f49c5fSRichard Henderson                     if (ts) {
258925f49c5fSRichard Henderson                         tcg_regset_set_reg(*la_temp_pref(ts),
259025f49c5fSRichard Henderson                                            tcg_target_call_iarg_regs[i]);
2591c70fbf0aSRichard Henderson                     }
2592c19f47bfSAurelien Jarno                 }
2593c6e113f5Sbellard             }
2594c896fe29Sbellard             break;
2595765b842aSRichard Henderson         case INDEX_op_insn_start:
2596c896fe29Sbellard             break;
25975ff9d6a4Sbellard         case INDEX_op_discard:
25985ff9d6a4Sbellard             /* mark the temporary as dead */
259925f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
260025f49c5fSRichard Henderson             ts->state = TS_DEAD;
260125f49c5fSRichard Henderson             la_reset_pref(ts);
26025ff9d6a4Sbellard             break;
26031305c451SRichard Henderson 
26041305c451SRichard Henderson         case INDEX_op_add2_i32:
2605c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
2606f1fae40cSRichard Henderson             goto do_addsub2;
26071305c451SRichard Henderson         case INDEX_op_sub2_i32:
2608c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
2609f1fae40cSRichard Henderson             goto do_addsub2;
2610f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
2611c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
2612f1fae40cSRichard Henderson             goto do_addsub2;
2613f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
2614c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
2615f1fae40cSRichard Henderson         do_addsub2:
26161305c451SRichard Henderson             nb_iargs = 4;
26171305c451SRichard Henderson             nb_oargs = 2;
26181305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
26191305c451SRichard Henderson                the low part.  The result can be optimized to a simple
26201305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
26211305c451SRichard Henderson                cpu mode is set to 32 bit.  */
2622b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2623b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
26241305c451SRichard Henderson                     goto do_remove;
26251305c451SRichard Henderson                 }
2626c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
2627c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
2628c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2629efee3746SRichard Henderson                 op->args[1] = op->args[2];
2630efee3746SRichard Henderson                 op->args[2] = op->args[4];
26311305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
26321305c451SRichard Henderson                 nb_iargs = 2;
26331305c451SRichard Henderson                 nb_oargs = 1;
26341305c451SRichard Henderson             }
26351305c451SRichard Henderson             goto do_not_remove;
26361305c451SRichard Henderson 
26371414968aSRichard Henderson         case INDEX_op_mulu2_i32:
2638c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2639c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
2640c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
264103271524SRichard Henderson             goto do_mul2;
2642f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
2643c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2644c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
2645c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
2646f1fae40cSRichard Henderson             goto do_mul2;
2647f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
2648c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2649c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
2650c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
265103271524SRichard Henderson             goto do_mul2;
2652f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
2653c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2654c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
2655c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
265603271524SRichard Henderson             goto do_mul2;
2657f1fae40cSRichard Henderson         do_mul2:
26581414968aSRichard Henderson             nb_iargs = 2;
26591414968aSRichard Henderson             nb_oargs = 2;
2660b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2661b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
266203271524SRichard Henderson                     /* Both parts of the operation are dead.  */
26631414968aSRichard Henderson                     goto do_remove;
26641414968aSRichard Henderson                 }
266503271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
2666c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2667efee3746SRichard Henderson                 op->args[1] = op->args[2];
2668efee3746SRichard Henderson                 op->args[2] = op->args[3];
2669b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
267003271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
2671c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
2672efee3746SRichard Henderson                 op->args[0] = op->args[1];
2673efee3746SRichard Henderson                 op->args[1] = op->args[2];
2674efee3746SRichard Henderson                 op->args[2] = op->args[3];
267503271524SRichard Henderson             } else {
267603271524SRichard Henderson                 goto do_not_remove;
267703271524SRichard Henderson             }
267803271524SRichard Henderson             /* Mark the single-word operation live.  */
26791414968aSRichard Henderson             nb_oargs = 1;
26801414968aSRichard Henderson             goto do_not_remove;
26811414968aSRichard Henderson 
2682c896fe29Sbellard         default:
26831305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
2684c896fe29Sbellard             nb_iargs = def->nb_iargs;
2685c896fe29Sbellard             nb_oargs = def->nb_oargs;
2686c896fe29Sbellard 
2687c896fe29Sbellard             /* Test if the operation can be removed because all
26885ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
26895ff9d6a4Sbellard                implies side effects */
26905ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
2691c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
2692b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
2693c896fe29Sbellard                         goto do_not_remove;
2694c896fe29Sbellard                     }
26959c43b68dSAurelien Jarno                 }
2696152c35aaSRichard Henderson                 goto do_remove;
2697152c35aaSRichard Henderson             }
2698152c35aaSRichard Henderson             goto do_not_remove;
2699152c35aaSRichard Henderson 
27001305c451SRichard Henderson         do_remove:
27010c627cdcSRichard Henderson             tcg_op_remove(s, op);
2702152c35aaSRichard Henderson             break;
2703152c35aaSRichard Henderson 
2704c896fe29Sbellard         do_not_remove:
2705c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
270625f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
270725f49c5fSRichard Henderson 
270825f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
270925f49c5fSRichard Henderson                 op->output_pref[i] = *la_temp_pref(ts);
271025f49c5fSRichard Henderson 
271125f49c5fSRichard Henderson                 /* Output args are dead.  */
271225f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2713a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
27146b64b624SAurelien Jarno                 }
271525f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
2716a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
27179c43b68dSAurelien Jarno                 }
271825f49c5fSRichard Henderson                 ts->state = TS_DEAD;
271925f49c5fSRichard Henderson                 la_reset_pref(ts);
2720c896fe29Sbellard             }
2721c896fe29Sbellard 
272225f49c5fSRichard Henderson             /* If end of basic block, update.  */
2723ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
2724ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
2725ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
27262616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
27273d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
2728f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
272925f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
273025f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
273125f49c5fSRichard Henderson                 }
2732c896fe29Sbellard             }
2733c896fe29Sbellard 
273425f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
2735866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
273625f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
273725f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2738a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
2739c896fe29Sbellard                 }
2740c19f47bfSAurelien Jarno             }
274125f49c5fSRichard Henderson 
274225f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
2743c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
274425f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
274525f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
274625f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
274725f49c5fSRichard Henderson                        all regs for the type.  */
274825f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
274925f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
275025f49c5fSRichard Henderson                 }
275125f49c5fSRichard Henderson             }
275225f49c5fSRichard Henderson 
275325f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
275425f49c5fSRichard Henderson             switch (opc) {
275525f49c5fSRichard Henderson             case INDEX_op_mov_i32:
275625f49c5fSRichard Henderson             case INDEX_op_mov_i64:
275725f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
275825f49c5fSRichard Henderson                    have proper constraints.  That said, special case
275925f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
276025f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
276125f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
276225f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
276325f49c5fSRichard Henderson                 }
276425f49c5fSRichard Henderson                 break;
276525f49c5fSRichard Henderson 
276625f49c5fSRichard Henderson             default:
276725f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
276825f49c5fSRichard Henderson                     const TCGArgConstraint *ct = &def->args_ct[i];
276925f49c5fSRichard Henderson                     TCGRegSet set, *pset;
277025f49c5fSRichard Henderson 
277125f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
277225f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
277325f49c5fSRichard Henderson                     set = *pset;
277425f49c5fSRichard Henderson 
277525f49c5fSRichard Henderson                     set &= ct->u.regs;
277625f49c5fSRichard Henderson                     if (ct->ct & TCG_CT_IALIAS) {
277725f49c5fSRichard Henderson                         set &= op->output_pref[ct->alias_index];
277825f49c5fSRichard Henderson                     }
277925f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
278025f49c5fSRichard Henderson                     if (set == 0) {
278125f49c5fSRichard Henderson                         set = ct->u.regs;
278225f49c5fSRichard Henderson                     }
278325f49c5fSRichard Henderson                     *pset = set;
278425f49c5fSRichard Henderson                 }
278525f49c5fSRichard Henderson                 break;
2786c896fe29Sbellard             }
2787c896fe29Sbellard             break;
2788c896fe29Sbellard         }
2789bee158cbSRichard Henderson         op->life = arg_life;
2790c896fe29Sbellard     }
27911ff0a2c5SEvgeny Voevodin }
2792c896fe29Sbellard 
27935a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
2794b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s)
27955a18407fSRichard Henderson {
27965a18407fSRichard Henderson     int nb_globals = s->nb_globals;
279715fa08f8SRichard Henderson     int nb_temps, i;
27985a18407fSRichard Henderson     bool changes = false;
279915fa08f8SRichard Henderson     TCGOp *op, *op_next;
28005a18407fSRichard Henderson 
28015a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
28025a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
28035a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
28045a18407fSRichard Henderson         if (its->indirect_reg) {
28055a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
28065a18407fSRichard Henderson             dts->type = its->type;
28075a18407fSRichard Henderson             dts->base_type = its->base_type;
2808b83eabeaSRichard Henderson             its->state_ptr = dts;
2809b83eabeaSRichard Henderson         } else {
2810b83eabeaSRichard Henderson             its->state_ptr = NULL;
28115a18407fSRichard Henderson         }
2812b83eabeaSRichard Henderson         /* All globals begin dead.  */
2813b83eabeaSRichard Henderson         its->state = TS_DEAD;
28145a18407fSRichard Henderson     }
2815b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
2816b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
2817b83eabeaSRichard Henderson         its->state_ptr = NULL;
2818b83eabeaSRichard Henderson         its->state = TS_DEAD;
2819b83eabeaSRichard Henderson     }
28205a18407fSRichard Henderson 
282115fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
28225a18407fSRichard Henderson         TCGOpcode opc = op->opc;
28235a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
28245a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
28255a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
2826b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
28275a18407fSRichard Henderson 
28285a18407fSRichard Henderson         if (opc == INDEX_op_call) {
2829cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2830cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2831efee3746SRichard Henderson             call_flags = op->args[nb_oargs + nb_iargs + 1];
28325a18407fSRichard Henderson         } else {
28335a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
28345a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
28355a18407fSRichard Henderson 
28365a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
28375a18407fSRichard Henderson             if (def->flags & TCG_OPF_BB_END) {
28385a18407fSRichard Henderson                 /* Like writing globals: save_globals */
28395a18407fSRichard Henderson                 call_flags = 0;
28405a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
28415a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
28425a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
28435a18407fSRichard Henderson             } else {
28445a18407fSRichard Henderson                 /* No effect on globals.  */
28455a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
28465a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
28475a18407fSRichard Henderson             }
28485a18407fSRichard Henderson         }
28495a18407fSRichard Henderson 
28505a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
28515a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2852b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2853b83eabeaSRichard Henderson             if (arg_ts) {
2854b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
2855b83eabeaSRichard Henderson                 if (dir_ts && arg_ts->state == TS_DEAD) {
2856b83eabeaSRichard Henderson                     TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
28575a18407fSRichard Henderson                                       ? INDEX_op_ld_i32
28585a18407fSRichard Henderson                                       : INDEX_op_ld_i64);
2859ac1043f6SEmilio G. Cota                     TCGOp *lop = tcg_op_insert_before(s, op, lopc);
28605a18407fSRichard Henderson 
2861b83eabeaSRichard Henderson                     lop->args[0] = temp_arg(dir_ts);
2862b83eabeaSRichard Henderson                     lop->args[1] = temp_arg(arg_ts->mem_base);
2863b83eabeaSRichard Henderson                     lop->args[2] = arg_ts->mem_offset;
28645a18407fSRichard Henderson 
28655a18407fSRichard Henderson                     /* Loaded, but synced with memory.  */
2866b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
28675a18407fSRichard Henderson                 }
28685a18407fSRichard Henderson             }
28695a18407fSRichard Henderson         }
28705a18407fSRichard Henderson 
28715a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
28725a18407fSRichard Henderson            No action is required except keeping temp_state up to date
28735a18407fSRichard Henderson            so that we reload when needed.  */
28745a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2875b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2876b83eabeaSRichard Henderson             if (arg_ts) {
2877b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
2878b83eabeaSRichard Henderson                 if (dir_ts) {
2879b83eabeaSRichard Henderson                     op->args[i] = temp_arg(dir_ts);
28805a18407fSRichard Henderson                     changes = true;
28815a18407fSRichard Henderson                     if (IS_DEAD_ARG(i)) {
2882b83eabeaSRichard Henderson                         arg_ts->state = TS_DEAD;
28835a18407fSRichard Henderson                     }
28845a18407fSRichard Henderson                 }
28855a18407fSRichard Henderson             }
28865a18407fSRichard Henderson         }
28875a18407fSRichard Henderson 
28885a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
28895a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
28905a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
28915a18407fSRichard Henderson             /* Nothing to do */
28925a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
28935a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
28945a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
28955a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
2896b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
2897b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
2898b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
28995a18407fSRichard Henderson             }
29005a18407fSRichard Henderson         } else {
29015a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
29025a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
29035a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
2904b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
2905b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
2906b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
29075a18407fSRichard Henderson             }
29085a18407fSRichard Henderson         }
29095a18407fSRichard Henderson 
29105a18407fSRichard Henderson         /* Outputs become available.  */
29115a18407fSRichard Henderson         for (i = 0; i < nb_oargs; i++) {
2912b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2913b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
2914b83eabeaSRichard Henderson             if (!dir_ts) {
29155a18407fSRichard Henderson                 continue;
29165a18407fSRichard Henderson             }
2917b83eabeaSRichard Henderson             op->args[i] = temp_arg(dir_ts);
29185a18407fSRichard Henderson             changes = true;
29195a18407fSRichard Henderson 
29205a18407fSRichard Henderson             /* The output is now live and modified.  */
2921b83eabeaSRichard Henderson             arg_ts->state = 0;
29225a18407fSRichard Henderson 
29235a18407fSRichard Henderson             /* Sync outputs upon their last write.  */
29245a18407fSRichard Henderson             if (NEED_SYNC_ARG(i)) {
2925b83eabeaSRichard Henderson                 TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
29265a18407fSRichard Henderson                                   ? INDEX_op_st_i32
29275a18407fSRichard Henderson                                   : INDEX_op_st_i64);
2928ac1043f6SEmilio G. Cota                 TCGOp *sop = tcg_op_insert_after(s, op, sopc);
29295a18407fSRichard Henderson 
2930b83eabeaSRichard Henderson                 sop->args[0] = temp_arg(dir_ts);
2931b83eabeaSRichard Henderson                 sop->args[1] = temp_arg(arg_ts->mem_base);
2932b83eabeaSRichard Henderson                 sop->args[2] = arg_ts->mem_offset;
29335a18407fSRichard Henderson 
2934b83eabeaSRichard Henderson                 arg_ts->state = TS_MEM;
29355a18407fSRichard Henderson             }
29365a18407fSRichard Henderson             /* Drop outputs that are dead.  */
29375a18407fSRichard Henderson             if (IS_DEAD_ARG(i)) {
2938b83eabeaSRichard Henderson                 arg_ts->state = TS_DEAD;
29395a18407fSRichard Henderson             }
29405a18407fSRichard Henderson         }
29415a18407fSRichard Henderson     }
29425a18407fSRichard Henderson 
29435a18407fSRichard Henderson     return changes;
29445a18407fSRichard Henderson }
29455a18407fSRichard Henderson 
29468d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
2947c896fe29Sbellard static void dump_regs(TCGContext *s)
2948c896fe29Sbellard {
2949c896fe29Sbellard     TCGTemp *ts;
2950c896fe29Sbellard     int i;
2951c896fe29Sbellard     char buf[64];
2952c896fe29Sbellard 
2953c896fe29Sbellard     for(i = 0; i < s->nb_temps; i++) {
2954c896fe29Sbellard         ts = &s->temps[i];
295543439139SRichard Henderson         printf("  %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
2956c896fe29Sbellard         switch(ts->val_type) {
2957c896fe29Sbellard         case TEMP_VAL_REG:
2958c896fe29Sbellard             printf("%s", tcg_target_reg_names[ts->reg]);
2959c896fe29Sbellard             break;
2960c896fe29Sbellard         case TEMP_VAL_MEM:
2961b3a62939SRichard Henderson             printf("%d(%s)", (int)ts->mem_offset,
2962b3a62939SRichard Henderson                    tcg_target_reg_names[ts->mem_base->reg]);
2963c896fe29Sbellard             break;
2964c896fe29Sbellard         case TEMP_VAL_CONST:
2965c896fe29Sbellard             printf("$0x%" TCG_PRIlx, ts->val);
2966c896fe29Sbellard             break;
2967c896fe29Sbellard         case TEMP_VAL_DEAD:
2968c896fe29Sbellard             printf("D");
2969c896fe29Sbellard             break;
2970c896fe29Sbellard         default:
2971c896fe29Sbellard             printf("???");
2972c896fe29Sbellard             break;
2973c896fe29Sbellard         }
2974c896fe29Sbellard         printf("\n");
2975c896fe29Sbellard     }
2976c896fe29Sbellard 
2977c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
2978f8b2f202SRichard Henderson         if (s->reg_to_temp[i] != NULL) {
2979c896fe29Sbellard             printf("%s: %s\n",
2980c896fe29Sbellard                    tcg_target_reg_names[i],
2981f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i]));
2982c896fe29Sbellard         }
2983c896fe29Sbellard     }
2984c896fe29Sbellard }
2985c896fe29Sbellard 
2986c896fe29Sbellard static void check_regs(TCGContext *s)
2987c896fe29Sbellard {
2988869938aeSRichard Henderson     int reg;
2989b6638662SRichard Henderson     int k;
2990c896fe29Sbellard     TCGTemp *ts;
2991c896fe29Sbellard     char buf[64];
2992c896fe29Sbellard 
2993c896fe29Sbellard     for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
2994f8b2f202SRichard Henderson         ts = s->reg_to_temp[reg];
2995f8b2f202SRichard Henderson         if (ts != NULL) {
2996f8b2f202SRichard Henderson             if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) {
2997c896fe29Sbellard                 printf("Inconsistency for register %s:\n",
2998c896fe29Sbellard                        tcg_target_reg_names[reg]);
2999b03cce8eSbellard                 goto fail;
3000c896fe29Sbellard             }
3001c896fe29Sbellard         }
3002c896fe29Sbellard     }
3003c896fe29Sbellard     for (k = 0; k < s->nb_temps; k++) {
3004c896fe29Sbellard         ts = &s->temps[k];
3005f8b2f202SRichard Henderson         if (ts->val_type == TEMP_VAL_REG && !ts->fixed_reg
3006f8b2f202SRichard Henderson             && s->reg_to_temp[ts->reg] != ts) {
3007c896fe29Sbellard             printf("Inconsistency for temp %s:\n",
3008f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3009b03cce8eSbellard         fail:
3010c896fe29Sbellard             printf("reg state:\n");
3011c896fe29Sbellard             dump_regs(s);
3012c896fe29Sbellard             tcg_abort();
3013c896fe29Sbellard         }
3014c896fe29Sbellard     }
3015c896fe29Sbellard }
3016c896fe29Sbellard #endif
3017c896fe29Sbellard 
30182272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
3019c896fe29Sbellard {
30209b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64)
30219b9c37c3SRichard Henderson     /* Sparc64 stack is accessed with offset of 2047 */
3022b591dc59SBlue Swirl     s->current_frame_offset = (s->current_frame_offset +
3023b591dc59SBlue Swirl                                (tcg_target_long)sizeof(tcg_target_long) - 1) &
3024b591dc59SBlue Swirl         ~(sizeof(tcg_target_long) - 1);
3025f44c9960SBlue Swirl #endif
3026b591dc59SBlue Swirl     if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
3027b591dc59SBlue Swirl         s->frame_end) {
30285ff9d6a4Sbellard         tcg_abort();
3029b591dc59SBlue Swirl     }
3030c896fe29Sbellard     ts->mem_offset = s->current_frame_offset;
3031b3a62939SRichard Henderson     ts->mem_base = s->frame_temp;
3032c896fe29Sbellard     ts->mem_allocated = 1;
3033e2c6d1b4SRichard Henderson     s->current_frame_offset += sizeof(tcg_target_long);
3034c896fe29Sbellard }
3035c896fe29Sbellard 
3036b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
3037b3915dbbSRichard Henderson 
303859d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
303959d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
304059d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
3041c896fe29Sbellard {
304259d7c14eSRichard Henderson     if (ts->fixed_reg) {
304359d7c14eSRichard Henderson         return;
304459d7c14eSRichard Henderson     }
304559d7c14eSRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
304659d7c14eSRichard Henderson         s->reg_to_temp[ts->reg] = NULL;
304759d7c14eSRichard Henderson     }
304859d7c14eSRichard Henderson     ts->val_type = (free_or_dead < 0
304959d7c14eSRichard Henderson                     || ts->temp_local
3050fa477d25SRichard Henderson                     || ts->temp_global
305159d7c14eSRichard Henderson                     ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
305259d7c14eSRichard Henderson }
3053c896fe29Sbellard 
305459d7c14eSRichard Henderson /* Mark a temporary as dead.  */
305559d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
305659d7c14eSRichard Henderson {
305759d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
305859d7c14eSRichard Henderson }
305959d7c14eSRichard Henderson 
306059d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
306159d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
306259d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
306359d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
306498b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
306598b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
306659d7c14eSRichard Henderson {
306759d7c14eSRichard Henderson     if (ts->fixed_reg) {
306859d7c14eSRichard Henderson         return;
306959d7c14eSRichard Henderson     }
307059d7c14eSRichard Henderson     if (!ts->mem_coherent) {
30717f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
30722272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
307359d7c14eSRichard Henderson         }
307459d7c14eSRichard Henderson         switch (ts->val_type) {
307559d7c14eSRichard Henderson         case TEMP_VAL_CONST:
307659d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
307759d7c14eSRichard Henderson                require it later in a register, so attempt to store the
307859d7c14eSRichard Henderson                constant to memory directly.  */
307959d7c14eSRichard Henderson             if (free_or_dead
308059d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
308159d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
308259d7c14eSRichard Henderson                 break;
308359d7c14eSRichard Henderson             }
308459d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
308598b4e186SRichard Henderson                       allocated_regs, preferred_regs);
308659d7c14eSRichard Henderson             /* fallthrough */
308759d7c14eSRichard Henderson 
308859d7c14eSRichard Henderson         case TEMP_VAL_REG:
308959d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
309059d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
309159d7c14eSRichard Henderson             break;
309259d7c14eSRichard Henderson 
309359d7c14eSRichard Henderson         case TEMP_VAL_MEM:
309459d7c14eSRichard Henderson             break;
309559d7c14eSRichard Henderson 
309659d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
309759d7c14eSRichard Henderson         default:
309859d7c14eSRichard Henderson             tcg_abort();
3099c896fe29Sbellard         }
31007f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
31017f6ceedfSAurelien Jarno     }
310259d7c14eSRichard Henderson     if (free_or_dead) {
310359d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
310459d7c14eSRichard Henderson     }
310559d7c14eSRichard Henderson }
31067f6ceedfSAurelien Jarno 
31077f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
3108b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
31097f6ceedfSAurelien Jarno {
3110f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
3111f8b2f202SRichard Henderson     if (ts != NULL) {
311298b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
3113c896fe29Sbellard     }
3114c896fe29Sbellard }
3115c896fe29Sbellard 
3116b016486eSRichard Henderson /**
3117b016486eSRichard Henderson  * tcg_reg_alloc:
3118b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
3119b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
3120b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
3121b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
3122b016486eSRichard Henderson  *
3123b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
3124b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
3125b016486eSRichard Henderson  */
3126b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
3127b016486eSRichard Henderson                             TCGRegSet allocated_regs,
3128b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
3129c896fe29Sbellard {
3130b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
3131b016486eSRichard Henderson     TCGRegSet reg_ct[2];
313291478cefSRichard Henderson     const int *order;
3133c896fe29Sbellard 
3134b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
3135b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
3136b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
3137b016486eSRichard Henderson 
3138b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
3139b016486eSRichard Henderson        or if the preference made no difference.  */
3140b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
3141b016486eSRichard Henderson 
314291478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
3143c896fe29Sbellard 
3144b016486eSRichard Henderson     /* Try free registers, preferences first.  */
3145b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3146b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3147b016486eSRichard Henderson 
3148b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3149b016486eSRichard Henderson             /* One register in the set.  */
3150b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3151b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
3152c896fe29Sbellard                 return reg;
3153c896fe29Sbellard             }
3154b016486eSRichard Henderson         } else {
315591478cefSRichard Henderson             for (i = 0; i < n; i++) {
3156b016486eSRichard Henderson                 TCGReg reg = order[i];
3157b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
3158b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
3159b016486eSRichard Henderson                     return reg;
3160b016486eSRichard Henderson                 }
3161b016486eSRichard Henderson             }
3162b016486eSRichard Henderson         }
3163b016486eSRichard Henderson     }
3164b016486eSRichard Henderson 
3165b016486eSRichard Henderson     /* We must spill something.  */
3166b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3167b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3168b016486eSRichard Henderson 
3169b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3170b016486eSRichard Henderson             /* One register in the set.  */
3171b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3172b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
3173c896fe29Sbellard             return reg;
3174b016486eSRichard Henderson         } else {
3175b016486eSRichard Henderson             for (i = 0; i < n; i++) {
3176b016486eSRichard Henderson                 TCGReg reg = order[i];
3177b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
3178b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
3179b016486eSRichard Henderson                     return reg;
3180b016486eSRichard Henderson                 }
3181b016486eSRichard Henderson             }
3182c896fe29Sbellard         }
3183c896fe29Sbellard     }
3184c896fe29Sbellard 
3185c896fe29Sbellard     tcg_abort();
3186c896fe29Sbellard }
3187c896fe29Sbellard 
318840ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
318940ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
319040ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
3191b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
319240ae5c62SRichard Henderson {
319340ae5c62SRichard Henderson     TCGReg reg;
319440ae5c62SRichard Henderson 
319540ae5c62SRichard Henderson     switch (ts->val_type) {
319640ae5c62SRichard Henderson     case TEMP_VAL_REG:
319740ae5c62SRichard Henderson         return;
319840ae5c62SRichard Henderson     case TEMP_VAL_CONST:
3199b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3200b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
320140ae5c62SRichard Henderson         tcg_out_movi(s, ts->type, reg, ts->val);
320240ae5c62SRichard Henderson         ts->mem_coherent = 0;
320340ae5c62SRichard Henderson         break;
320440ae5c62SRichard Henderson     case TEMP_VAL_MEM:
3205b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3206b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
320740ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
320840ae5c62SRichard Henderson         ts->mem_coherent = 1;
320940ae5c62SRichard Henderson         break;
321040ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
321140ae5c62SRichard Henderson     default:
321240ae5c62SRichard Henderson         tcg_abort();
321340ae5c62SRichard Henderson     }
321440ae5c62SRichard Henderson     ts->reg = reg;
321540ae5c62SRichard Henderson     ts->val_type = TEMP_VAL_REG;
321640ae5c62SRichard Henderson     s->reg_to_temp[reg] = ts;
321740ae5c62SRichard Henderson }
321840ae5c62SRichard Henderson 
321959d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
3220e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
322159d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
32221ad80729SAurelien Jarno {
32232c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
3224eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
3225f8bf00f1SRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg);
32261ad80729SAurelien Jarno }
32271ad80729SAurelien Jarno 
32289814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
3229641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
3230641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
3231641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
3232641d5fbeSbellard {
3233ac3b8891SRichard Henderson     int i, n;
3234641d5fbeSbellard 
3235ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
3236b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
3237641d5fbeSbellard     }
3238e5097dc8Sbellard }
3239e5097dc8Sbellard 
32403d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
32413d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
32423d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
32433d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
32443d5c5f87SAurelien Jarno {
3245ac3b8891SRichard Henderson     int i, n;
32463d5c5f87SAurelien Jarno 
3247ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
324812b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
324912b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
325012b9b11aSRichard Henderson                          || ts->fixed_reg
325112b9b11aSRichard Henderson                          || ts->mem_coherent);
32523d5c5f87SAurelien Jarno     }
32533d5c5f87SAurelien Jarno }
32543d5c5f87SAurelien Jarno 
3255e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
3256e8996ee0Sbellard    all globals are stored at their canonical location. */
3257e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
3258e5097dc8Sbellard {
3259e5097dc8Sbellard     int i;
3260e5097dc8Sbellard 
3261c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
3262b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
3263641d5fbeSbellard         if (ts->temp_local) {
3264b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
3265641d5fbeSbellard         } else {
32662c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
3267eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
3268eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3269c896fe29Sbellard         }
3270641d5fbeSbellard     }
3271e8996ee0Sbellard 
3272e8996ee0Sbellard     save_globals(s, allocated_regs);
3273c896fe29Sbellard }
3274c896fe29Sbellard 
32750fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
3276ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
3277ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
3278e8996ee0Sbellard {
3279e8996ee0Sbellard     if (ots->fixed_reg) {
328059d7c14eSRichard Henderson         /* For fixed registers, we do not do any constant propagation.  */
3281e8996ee0Sbellard         tcg_out_movi(s, ots->type, ots->reg, val);
328259d7c14eSRichard Henderson         return;
328359d7c14eSRichard Henderson     }
328459d7c14eSRichard Henderson 
328559d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
3286f8b2f202SRichard Henderson     if (ots->val_type == TEMP_VAL_REG) {
3287f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = NULL;
3288f8b2f202SRichard Henderson     }
3289e8996ee0Sbellard     ots->val_type = TEMP_VAL_CONST;
3290e8996ee0Sbellard     ots->val = val;
329159d7c14eSRichard Henderson     ots->mem_coherent = 0;
3292ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
3293ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
329459d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
3295f8bf00f1SRichard Henderson         temp_dead(s, ots);
32964c4e1ab2SAurelien Jarno     }
3297e8996ee0Sbellard }
3298e8996ee0Sbellard 
3299dd186292SRichard Henderson static void tcg_reg_alloc_movi(TCGContext *s, const TCGOp *op)
33000fe4fca4SPaolo Bonzini {
330143439139SRichard Henderson     TCGTemp *ots = arg_temp(op->args[0]);
3302dd186292SRichard Henderson     tcg_target_ulong val = op->args[1];
33030fe4fca4SPaolo Bonzini 
330469e3706dSRichard Henderson     tcg_reg_alloc_do_movi(s, ots, val, op->life, op->output_pref[0]);
33050fe4fca4SPaolo Bonzini }
33060fe4fca4SPaolo Bonzini 
3307dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
3308c896fe29Sbellard {
3309dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
331069e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
3311c896fe29Sbellard     TCGTemp *ts, *ots;
3312450445d5SRichard Henderson     TCGType otype, itype;
3313c896fe29Sbellard 
3314d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
331569e3706dSRichard Henderson     preferred_regs = op->output_pref[0];
331643439139SRichard Henderson     ots = arg_temp(op->args[0]);
331743439139SRichard Henderson     ts = arg_temp(op->args[1]);
3318450445d5SRichard Henderson 
3319450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
3320450445d5SRichard Henderson     otype = ots->type;
3321450445d5SRichard Henderson     itype = ts->type;
3322c896fe29Sbellard 
33230fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
33240fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
33250fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
33260fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
33270fe4fca4SPaolo Bonzini             temp_dead(s, ts);
33280fe4fca4SPaolo Bonzini         }
332969e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
33300fe4fca4SPaolo Bonzini         return;
33310fe4fca4SPaolo Bonzini     }
33320fe4fca4SPaolo Bonzini 
33330fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
33340fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
33350fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
33360fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
33370fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
333869e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
333969e3706dSRichard Henderson                   allocated_regs, preferred_regs);
3340c29c1d7eSAurelien Jarno     }
3341c29c1d7eSAurelien Jarno 
33420fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
3343c29c1d7eSAurelien Jarno     if (IS_DEAD_ARG(0) && !ots->fixed_reg) {
3344c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
3345c29c1d7eSAurelien Jarno            liveness analysis disabled). */
3346eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
3347c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
33482272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
3349c29c1d7eSAurelien Jarno         }
3350b3a62939SRichard Henderson         tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset);
3351c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
3352f8bf00f1SRichard Henderson             temp_dead(s, ts);
3353c29c1d7eSAurelien Jarno         }
3354f8bf00f1SRichard Henderson         temp_dead(s, ots);
3355e8996ee0Sbellard     } else {
3356c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1) && !ts->fixed_reg && !ots->fixed_reg) {
3357c29c1d7eSAurelien Jarno             /* the mov can be suppressed */
3358c29c1d7eSAurelien Jarno             if (ots->val_type == TEMP_VAL_REG) {
3359f8b2f202SRichard Henderson                 s->reg_to_temp[ots->reg] = NULL;
3360c896fe29Sbellard             }
3361c29c1d7eSAurelien Jarno             ots->reg = ts->reg;
3362f8bf00f1SRichard Henderson             temp_dead(s, ts);
3363c29c1d7eSAurelien Jarno         } else {
3364c29c1d7eSAurelien Jarno             if (ots->val_type != TEMP_VAL_REG) {
3365c29c1d7eSAurelien Jarno                 /* When allocating a new register, make sure to not spill the
3366c29c1d7eSAurelien Jarno                    input one. */
3367c29c1d7eSAurelien Jarno                 tcg_regset_set_reg(allocated_regs, ts->reg);
3368450445d5SRichard Henderson                 ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
336969e3706dSRichard Henderson                                          allocated_regs, preferred_regs,
3370b016486eSRichard Henderson                                          ots->indirect_base);
3371c29c1d7eSAurelien Jarno             }
3372450445d5SRichard Henderson             tcg_out_mov(s, otype, ots->reg, ts->reg);
3373c29c1d7eSAurelien Jarno         }
3374c896fe29Sbellard         ots->val_type = TEMP_VAL_REG;
3375c896fe29Sbellard         ots->mem_coherent = 0;
3376f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3377ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(0)) {
337898b4e186SRichard Henderson             temp_sync(s, ots, allocated_regs, 0, 0);
3379c29c1d7eSAurelien Jarno         }
3380ec7a869dSAurelien Jarno     }
3381c896fe29Sbellard }
3382c896fe29Sbellard 
3383dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
3384c896fe29Sbellard {
3385dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3386dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
338782790a87SRichard Henderson     TCGRegSet i_allocated_regs;
338882790a87SRichard Henderson     TCGRegSet o_allocated_regs;
3389b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
3390b6638662SRichard Henderson     TCGReg reg;
3391c896fe29Sbellard     TCGArg arg;
3392c896fe29Sbellard     const TCGArgConstraint *arg_ct;
3393c896fe29Sbellard     TCGTemp *ts;
3394c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
3395c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
3396c896fe29Sbellard 
3397c896fe29Sbellard     nb_oargs = def->nb_oargs;
3398c896fe29Sbellard     nb_iargs = def->nb_iargs;
3399c896fe29Sbellard 
3400c896fe29Sbellard     /* copy constants */
3401c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
3402dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
3403c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
3404c896fe29Sbellard 
3405d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
3406d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
340782790a87SRichard Henderson 
3408c896fe29Sbellard     /* satisfy input constraints */
3409c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
3410d62816f2SRichard Henderson         TCGRegSet i_preferred_regs, o_preferred_regs;
3411d62816f2SRichard Henderson 
3412c896fe29Sbellard         i = def->sorted_args[nb_oargs + k];
3413dd186292SRichard Henderson         arg = op->args[i];
3414c896fe29Sbellard         arg_ct = &def->args_ct[i];
341543439139SRichard Henderson         ts = arg_temp(arg);
341640ae5c62SRichard Henderson 
341740ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
341840ae5c62SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct)) {
3419c896fe29Sbellard             /* constant is OK for instruction */
3420c896fe29Sbellard             const_args[i] = 1;
3421c896fe29Sbellard             new_args[i] = ts->val;
3422d62816f2SRichard Henderson             continue;
3423c896fe29Sbellard         }
342440ae5c62SRichard Henderson 
3425d62816f2SRichard Henderson         i_preferred_regs = o_preferred_regs = 0;
34265ff9d6a4Sbellard         if (arg_ct->ct & TCG_CT_IALIAS) {
3427d62816f2SRichard Henderson             o_preferred_regs = op->output_pref[arg_ct->alias_index];
34285ff9d6a4Sbellard             if (ts->fixed_reg) {
34295ff9d6a4Sbellard                 /* if fixed register, we must allocate a new register
34305ff9d6a4Sbellard                    if the alias is not the same register */
3431d62816f2SRichard Henderson                 if (arg != op->args[arg_ct->alias_index]) {
34325ff9d6a4Sbellard                     goto allocate_in_reg;
3433d62816f2SRichard Henderson                 }
34345ff9d6a4Sbellard             } else {
3435c896fe29Sbellard                 /* if the input is aliased to an output and if it is
3436c896fe29Sbellard                    not dead after the instruction, we must allocate
3437c896fe29Sbellard                    a new register and move it */
3438866cb6cbSAurelien Jarno                 if (!IS_DEAD_ARG(i)) {
3439c896fe29Sbellard                     goto allocate_in_reg;
3440c896fe29Sbellard                 }
3441d62816f2SRichard Henderson 
34427e1df267SAurelien Jarno                 /* check if the current register has already been allocated
34437e1df267SAurelien Jarno                    for another input aliased to an output */
3444d62816f2SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG) {
34457e1df267SAurelien Jarno                     int k2, i2;
3446d62816f2SRichard Henderson                     reg = ts->reg;
34477e1df267SAurelien Jarno                     for (k2 = 0 ; k2 < k ; k2++) {
34487e1df267SAurelien Jarno                         i2 = def->sorted_args[nb_oargs + k2];
34497e1df267SAurelien Jarno                         if ((def->args_ct[i2].ct & TCG_CT_IALIAS) &&
3450d62816f2SRichard Henderson                             reg == new_args[i2]) {
34517e1df267SAurelien Jarno                             goto allocate_in_reg;
34527e1df267SAurelien Jarno                         }
34537e1df267SAurelien Jarno                     }
34545ff9d6a4Sbellard                 }
3455d62816f2SRichard Henderson                 i_preferred_regs = o_preferred_regs;
3456866cb6cbSAurelien Jarno             }
3457d62816f2SRichard Henderson         }
3458d62816f2SRichard Henderson 
3459d62816f2SRichard Henderson         temp_load(s, ts, arg_ct->u.regs, i_allocated_regs, i_preferred_regs);
3460c896fe29Sbellard         reg = ts->reg;
3461d62816f2SRichard Henderson 
3462c896fe29Sbellard         if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
3463c896fe29Sbellard             /* nothing to do : the constraint is satisfied */
3464c896fe29Sbellard         } else {
3465c896fe29Sbellard         allocate_in_reg:
3466c896fe29Sbellard             /* allocate a new register matching the constraint
3467c896fe29Sbellard                and move the temporary register into it */
3468d62816f2SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
3469d62816f2SRichard Henderson                       i_allocated_regs, 0);
347082790a87SRichard Henderson             reg = tcg_reg_alloc(s, arg_ct->u.regs, i_allocated_regs,
3471d62816f2SRichard Henderson                                 o_preferred_regs, ts->indirect_base);
34723b6dac34SRichard Henderson             tcg_out_mov(s, ts->type, reg, ts->reg);
3473c896fe29Sbellard         }
3474c896fe29Sbellard         new_args[i] = reg;
3475c896fe29Sbellard         const_args[i] = 0;
347682790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
3477c896fe29Sbellard     }
3478c896fe29Sbellard 
3479c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
3480866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
3481866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
348243439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
3483c896fe29Sbellard         }
3484c896fe29Sbellard     }
3485c896fe29Sbellard 
3486a52ad07eSAurelien Jarno     if (def->flags & TCG_OPF_BB_END) {
348782790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
3488a52ad07eSAurelien Jarno     } else {
3489c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
3490b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
3491c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
3492c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
349382790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
3494c896fe29Sbellard                 }
3495c896fe29Sbellard             }
34963d5c5f87SAurelien Jarno         }
34973d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
34983d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
34993d5c5f87SAurelien Jarno                an exception. */
350082790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
3501c896fe29Sbellard         }
3502c896fe29Sbellard 
3503c896fe29Sbellard         /* satisfy the output constraints */
3504c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
3505c896fe29Sbellard             i = def->sorted_args[k];
3506dd186292SRichard Henderson             arg = op->args[i];
3507c896fe29Sbellard             arg_ct = &def->args_ct[i];
350843439139SRichard Henderson             ts = arg_temp(arg);
350917280ff4SRichard Henderson             if ((arg_ct->ct & TCG_CT_ALIAS)
351017280ff4SRichard Henderson                 && !const_args[arg_ct->alias_index]) {
35115ff9d6a4Sbellard                 reg = new_args[arg_ct->alias_index];
351282790a87SRichard Henderson             } else if (arg_ct->ct & TCG_CT_NEWREG) {
351382790a87SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->u.regs,
351482790a87SRichard Henderson                                     i_allocated_regs | o_allocated_regs,
351569e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
3516c896fe29Sbellard             } else {
3517c896fe29Sbellard                 /* if fixed register, we try to use it */
3518c896fe29Sbellard                 reg = ts->reg;
3519c896fe29Sbellard                 if (ts->fixed_reg &&
3520c896fe29Sbellard                     tcg_regset_test_reg(arg_ct->u.regs, reg)) {
3521c896fe29Sbellard                     goto oarg_end;
3522c896fe29Sbellard                 }
352382790a87SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->u.regs, o_allocated_regs,
352469e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
3525c896fe29Sbellard             }
352682790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
3527c896fe29Sbellard             /* if a fixed register is used, then a move will be done afterwards */
3528c896fe29Sbellard             if (!ts->fixed_reg) {
3529639368ddSAurelien Jarno                 if (ts->val_type == TEMP_VAL_REG) {
3530f8b2f202SRichard Henderson                     s->reg_to_temp[ts->reg] = NULL;
3531639368ddSAurelien Jarno                 }
3532c896fe29Sbellard                 ts->val_type = TEMP_VAL_REG;
3533c896fe29Sbellard                 ts->reg = reg;
3534c896fe29Sbellard                 /* temp value is modified, so the value kept in memory is
3535c896fe29Sbellard                    potentially not the same */
3536c896fe29Sbellard                 ts->mem_coherent = 0;
3537f8b2f202SRichard Henderson                 s->reg_to_temp[reg] = ts;
3538c896fe29Sbellard             }
3539c896fe29Sbellard         oarg_end:
3540c896fe29Sbellard             new_args[i] = reg;
3541c896fe29Sbellard         }
3542e8996ee0Sbellard     }
3543c896fe29Sbellard 
3544c896fe29Sbellard     /* emit instruction */
3545d2fd745fSRichard Henderson     if (def->flags & TCG_OPF_VECTOR) {
3546d2fd745fSRichard Henderson         tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
3547d2fd745fSRichard Henderson                        new_args, const_args);
3548d2fd745fSRichard Henderson     } else {
3549dd186292SRichard Henderson         tcg_out_op(s, op->opc, new_args, const_args);
3550d2fd745fSRichard Henderson     }
3551c896fe29Sbellard 
3552c896fe29Sbellard     /* move the outputs in the correct register if needed */
3553c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
355443439139SRichard Henderson         ts = arg_temp(op->args[i]);
3555c896fe29Sbellard         reg = new_args[i];
3556c896fe29Sbellard         if (ts->fixed_reg && ts->reg != reg) {
35573b6dac34SRichard Henderson             tcg_out_mov(s, ts->type, ts->reg, reg);
3558c896fe29Sbellard         }
3559ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
356098b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
356159d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
3562f8bf00f1SRichard Henderson             temp_dead(s, ts);
3563ec7a869dSAurelien Jarno         }
3564c896fe29Sbellard     }
3565c896fe29Sbellard }
3566c896fe29Sbellard 
3567b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP
3568b03cce8eSbellard #define STACK_DIR(x) (-(x))
3569b03cce8eSbellard #else
3570b03cce8eSbellard #define STACK_DIR(x) (x)
3571b03cce8eSbellard #endif
3572b03cce8eSbellard 
3573dd186292SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
3574c896fe29Sbellard {
3575cd9090aaSRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
3576cd9090aaSRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
3577dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3578b6638662SRichard Henderson     int flags, nb_regs, i;
3579b6638662SRichard Henderson     TCGReg reg;
3580cf066674SRichard Henderson     TCGArg arg;
3581c896fe29Sbellard     TCGTemp *ts;
3582d3452f1fSRichard Henderson     intptr_t stack_offset;
3583d3452f1fSRichard Henderson     size_t call_stack_size;
3584cf066674SRichard Henderson     tcg_insn_unit *func_addr;
3585cf066674SRichard Henderson     int allocate_args;
3586c896fe29Sbellard     TCGRegSet allocated_regs;
3587c896fe29Sbellard 
3588dd186292SRichard Henderson     func_addr = (tcg_insn_unit *)(intptr_t)op->args[nb_oargs + nb_iargs];
3589dd186292SRichard Henderson     flags = op->args[nb_oargs + nb_iargs + 1];
3590c896fe29Sbellard 
35916e17d0c5SStefan Weil     nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
3592c45cb8bbSRichard Henderson     if (nb_regs > nb_iargs) {
3593c45cb8bbSRichard Henderson         nb_regs = nb_iargs;
3594cf066674SRichard Henderson     }
3595c896fe29Sbellard 
3596c896fe29Sbellard     /* assign stack slots first */
3597c45cb8bbSRichard Henderson     call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long);
3598c896fe29Sbellard     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
3599c896fe29Sbellard         ~(TCG_TARGET_STACK_ALIGN - 1);
3600b03cce8eSbellard     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
3601b03cce8eSbellard     if (allocate_args) {
3602345649c0SBlue Swirl         /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
3603345649c0SBlue Swirl            preallocate call stack */
3604345649c0SBlue Swirl         tcg_abort();
3605b03cce8eSbellard     }
360639cf05d3Sbellard 
360739cf05d3Sbellard     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
3608c45cb8bbSRichard Henderson     for (i = nb_regs; i < nb_iargs; i++) {
3609dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
361039cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP
361139cf05d3Sbellard         stack_offset -= sizeof(tcg_target_long);
361239cf05d3Sbellard #endif
361339cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
361443439139SRichard Henderson             ts = arg_temp(arg);
361540ae5c62SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
3616b722452aSRichard Henderson                       s->reserved_regs, 0);
3617e4d5434cSblueswir1             tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
361839cf05d3Sbellard         }
361939cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP
362039cf05d3Sbellard         stack_offset += sizeof(tcg_target_long);
362139cf05d3Sbellard #endif
3622c896fe29Sbellard     }
3623c896fe29Sbellard 
3624c896fe29Sbellard     /* assign input registers */
3625d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
3626c896fe29Sbellard     for (i = 0; i < nb_regs; i++) {
3627dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
362839cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
362943439139SRichard Henderson             ts = arg_temp(arg);
3630c896fe29Sbellard             reg = tcg_target_call_iarg_regs[i];
363140ae5c62SRichard Henderson 
3632c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
3633c896fe29Sbellard                 if (ts->reg != reg) {
36344250da10SRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
36353b6dac34SRichard Henderson                     tcg_out_mov(s, ts->type, reg, ts->reg);
3636c896fe29Sbellard                 }
3637c896fe29Sbellard             } else {
3638ccb1bb66SRichard Henderson                 TCGRegSet arg_set = 0;
363940ae5c62SRichard Henderson 
36404250da10SRichard Henderson                 tcg_reg_free(s, reg, allocated_regs);
364140ae5c62SRichard Henderson                 tcg_regset_set_reg(arg_set, reg);
3642b722452aSRichard Henderson                 temp_load(s, ts, arg_set, allocated_regs, 0);
3643c896fe29Sbellard             }
364440ae5c62SRichard Henderson 
3645c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
3646c896fe29Sbellard         }
364739cf05d3Sbellard     }
3648c896fe29Sbellard 
3649c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
3650866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3651866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
365243439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
3653c896fe29Sbellard         }
3654c896fe29Sbellard     }
3655c896fe29Sbellard 
3656c896fe29Sbellard     /* clobber call registers */
3657c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
3658c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
3659b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
3660c896fe29Sbellard         }
3661c896fe29Sbellard     }
3662c896fe29Sbellard 
366378505279SAurelien Jarno     /* Save globals if they might be written by the helper, sync them if
366478505279SAurelien Jarno        they might be read. */
366578505279SAurelien Jarno     if (flags & TCG_CALL_NO_READ_GLOBALS) {
366678505279SAurelien Jarno         /* Nothing to do */
366778505279SAurelien Jarno     } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) {
366878505279SAurelien Jarno         sync_globals(s, allocated_regs);
366978505279SAurelien Jarno     } else {
3670e8996ee0Sbellard         save_globals(s, allocated_regs);
3671b9c18f56Saurel32     }
3672c896fe29Sbellard 
3673cf066674SRichard Henderson     tcg_out_call(s, func_addr);
3674c896fe29Sbellard 
3675c896fe29Sbellard     /* assign output registers and emit moves if needed */
3676c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
3677dd186292SRichard Henderson         arg = op->args[i];
367843439139SRichard Henderson         ts = arg_temp(arg);
3679c896fe29Sbellard         reg = tcg_target_call_oarg_regs[i];
3680eabb7b91SAurelien Jarno         tcg_debug_assert(s->reg_to_temp[reg] == NULL);
368134b1a49cSRichard Henderson 
3682c896fe29Sbellard         if (ts->fixed_reg) {
3683c896fe29Sbellard             if (ts->reg != reg) {
36843b6dac34SRichard Henderson                 tcg_out_mov(s, ts->type, ts->reg, reg);
3685c896fe29Sbellard             }
3686c896fe29Sbellard         } else {
3687639368ddSAurelien Jarno             if (ts->val_type == TEMP_VAL_REG) {
3688f8b2f202SRichard Henderson                 s->reg_to_temp[ts->reg] = NULL;
3689639368ddSAurelien Jarno             }
3690c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
3691c896fe29Sbellard             ts->reg = reg;
3692c896fe29Sbellard             ts->mem_coherent = 0;
3693f8b2f202SRichard Henderson             s->reg_to_temp[reg] = ts;
3694ec7a869dSAurelien Jarno             if (NEED_SYNC_ARG(i)) {
369598b4e186SRichard Henderson                 temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i));
369659d7c14eSRichard Henderson             } else if (IS_DEAD_ARG(i)) {
3697f8bf00f1SRichard Henderson                 temp_dead(s, ts);
3698c896fe29Sbellard             }
3699c896fe29Sbellard         }
37008c11ad25SAurelien Jarno     }
3701c896fe29Sbellard }
3702c896fe29Sbellard 
3703c896fe29Sbellard #ifdef CONFIG_PROFILER
3704c896fe29Sbellard 
3705c3fac113SEmilio G. Cota /* avoid copy/paste errors */
3706c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field)                       \
3707c3fac113SEmilio G. Cota     do {                                                \
3708c3fac113SEmilio G. Cota         (to)->field += atomic_read(&((from)->field));   \
3709c3fac113SEmilio G. Cota     } while (0)
3710c896fe29Sbellard 
3711c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field)                                       \
3712c3fac113SEmilio G. Cota     do {                                                                \
3713c3fac113SEmilio G. Cota         typeof((from)->field) val__ = atomic_read(&((from)->field));    \
3714c3fac113SEmilio G. Cota         if (val__ > (to)->field) {                                      \
3715c3fac113SEmilio G. Cota             (to)->field = val__;                                        \
3716c3fac113SEmilio G. Cota         }                                                               \
3717c3fac113SEmilio G. Cota     } while (0)
3718c3fac113SEmilio G. Cota 
3719c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */
3720c3fac113SEmilio G. Cota static inline
3721c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
3722c896fe29Sbellard {
37233468b59eSEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
3724c3fac113SEmilio G. Cota     unsigned int i;
3725c3fac113SEmilio G. Cota 
37263468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
37273468b59eSEmilio G. Cota         TCGContext *s = atomic_read(&tcg_ctxs[i]);
37283468b59eSEmilio G. Cota         const TCGProfile *orig = &s->prof;
3729c3fac113SEmilio G. Cota 
3730c3fac113SEmilio G. Cota         if (counters) {
373172fd2efbSEmilio G. Cota             PROF_ADD(prof, orig, cpu_exec_time);
3732c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count1);
3733c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count);
3734c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, op_count);
3735c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, op_count_max);
3736c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, temp_count);
3737c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, temp_count_max);
3738c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, del_op_count);
3739c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_in_len);
3740c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_out_len);
3741c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, search_out_len);
3742c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, interm_time);
3743c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_time);
3744c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, la_time);
3745c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, opt_time);
3746c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_count);
3747c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_time);
3748c3fac113SEmilio G. Cota         }
3749c3fac113SEmilio G. Cota         if (table) {
3750c896fe29Sbellard             int i;
3751d70724ceSzhanghailiang 
375215fc7daaSRichard Henderson             for (i = 0; i < NB_OPS; i++) {
3753c3fac113SEmilio G. Cota                 PROF_ADD(prof, orig, table_op_count[i]);
3754c3fac113SEmilio G. Cota             }
3755c3fac113SEmilio G. Cota         }
3756c3fac113SEmilio G. Cota     }
3757c3fac113SEmilio G. Cota }
3758c3fac113SEmilio G. Cota 
3759c3fac113SEmilio G. Cota #undef PROF_ADD
3760c3fac113SEmilio G. Cota #undef PROF_MAX
3761c3fac113SEmilio G. Cota 
3762c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof)
3763c3fac113SEmilio G. Cota {
3764c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, true, false);
3765c3fac113SEmilio G. Cota }
3766c3fac113SEmilio G. Cota 
3767c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof)
3768c3fac113SEmilio G. Cota {
3769c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, false, true);
3770c3fac113SEmilio G. Cota }
3771c3fac113SEmilio G. Cota 
3772*d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
3773c3fac113SEmilio G. Cota {
3774c3fac113SEmilio G. Cota     TCGProfile prof = {};
3775c3fac113SEmilio G. Cota     int i;
3776c3fac113SEmilio G. Cota 
3777c3fac113SEmilio G. Cota     tcg_profile_snapshot_table(&prof);
3778c3fac113SEmilio G. Cota     for (i = 0; i < NB_OPS; i++) {
3779*d4c51a0aSMarkus Armbruster         qemu_printf("%s %" PRId64 "\n", tcg_op_defs[i].name,
3780c3fac113SEmilio G. Cota                     prof.table_op_count[i]);
3781c896fe29Sbellard     }
3782c896fe29Sbellard }
378372fd2efbSEmilio G. Cota 
378472fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
378572fd2efbSEmilio G. Cota {
378672fd2efbSEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
378772fd2efbSEmilio G. Cota     unsigned int i;
378872fd2efbSEmilio G. Cota     int64_t ret = 0;
378972fd2efbSEmilio G. Cota 
379072fd2efbSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
379172fd2efbSEmilio G. Cota         const TCGContext *s = atomic_read(&tcg_ctxs[i]);
379272fd2efbSEmilio G. Cota         const TCGProfile *prof = &s->prof;
379372fd2efbSEmilio G. Cota 
379472fd2efbSEmilio G. Cota         ret += atomic_read(&prof->cpu_exec_time);
379572fd2efbSEmilio G. Cota     }
379672fd2efbSEmilio G. Cota     return ret;
379772fd2efbSEmilio G. Cota }
3798246ae24dSMax Filippov #else
3799*d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
3800246ae24dSMax Filippov {
3801*d4c51a0aSMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
3802246ae24dSMax Filippov }
380372fd2efbSEmilio G. Cota 
380472fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
380572fd2efbSEmilio G. Cota {
380672fd2efbSEmilio G. Cota     error_report("%s: TCG profiler not compiled", __func__);
380772fd2efbSEmilio G. Cota     exit(EXIT_FAILURE);
380872fd2efbSEmilio G. Cota }
3809c896fe29Sbellard #endif
3810c896fe29Sbellard 
3811c896fe29Sbellard 
38125bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
3813c896fe29Sbellard {
3814c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER
3815c3fac113SEmilio G. Cota     TCGProfile *prof = &s->prof;
3816c3fac113SEmilio G. Cota #endif
381715fa08f8SRichard Henderson     int i, num_insns;
381815fa08f8SRichard Henderson     TCGOp *op;
3819c896fe29Sbellard 
382004fe6400SRichard Henderson #ifdef CONFIG_PROFILER
382104fe6400SRichard Henderson     {
3822c1f543b7SEmilio G. Cota         int n = 0;
382304fe6400SRichard Henderson 
382415fa08f8SRichard Henderson         QTAILQ_FOREACH(op, &s->ops, link) {
382515fa08f8SRichard Henderson             n++;
382615fa08f8SRichard Henderson         }
3827c3fac113SEmilio G. Cota         atomic_set(&prof->op_count, prof->op_count + n);
3828c3fac113SEmilio G. Cota         if (n > prof->op_count_max) {
3829c3fac113SEmilio G. Cota             atomic_set(&prof->op_count_max, n);
383004fe6400SRichard Henderson         }
383104fe6400SRichard Henderson 
383204fe6400SRichard Henderson         n = s->nb_temps;
3833c3fac113SEmilio G. Cota         atomic_set(&prof->temp_count, prof->temp_count + n);
3834c3fac113SEmilio G. Cota         if (n > prof->temp_count_max) {
3835c3fac113SEmilio G. Cota             atomic_set(&prof->temp_count_max, n);
383604fe6400SRichard Henderson         }
383704fe6400SRichard Henderson     }
383804fe6400SRichard Henderson #endif
383904fe6400SRichard Henderson 
3840c896fe29Sbellard #ifdef DEBUG_DISAS
3841d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
3842d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
38431ee73216SRichard Henderson         qemu_log_lock();
384493fcfe39Saliguori         qemu_log("OP:\n");
38451894f69aSRichard Henderson         tcg_dump_ops(s, false);
384693fcfe39Saliguori         qemu_log("\n");
38471ee73216SRichard Henderson         qemu_log_unlock();
3848c896fe29Sbellard     }
3849c896fe29Sbellard #endif
3850c896fe29Sbellard 
3851bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
3852bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
3853bef16ab4SRichard Henderson     {
3854bef16ab4SRichard Henderson         TCGLabel *l;
3855bef16ab4SRichard Henderson         bool error = false;
3856bef16ab4SRichard Henderson 
3857bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
3858bef16ab4SRichard Henderson             if (unlikely(!l->present) && l->refs) {
3859bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
3860bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
3861bef16ab4SRichard Henderson                 error = true;
3862bef16ab4SRichard Henderson             }
3863bef16ab4SRichard Henderson         }
3864bef16ab4SRichard Henderson         assert(!error);
3865bef16ab4SRichard Henderson     }
3866bef16ab4SRichard Henderson #endif
3867bef16ab4SRichard Henderson 
3868c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
3869c3fac113SEmilio G. Cota     atomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
3870c5cc28ffSAurelien Jarno #endif
3871c5cc28ffSAurelien Jarno 
38728f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
3873c45cb8bbSRichard Henderson     tcg_optimize(s);
38748f2e8c07SKirill Batuzov #endif
38758f2e8c07SKirill Batuzov 
3876a23a9ec6Sbellard #ifdef CONFIG_PROFILER
3877c3fac113SEmilio G. Cota     atomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
3878c3fac113SEmilio G. Cota     atomic_set(&prof->la_time, prof->la_time - profile_getclock());
3879a23a9ec6Sbellard #endif
3880c5cc28ffSAurelien Jarno 
3881b4fc67c7SRichard Henderson     reachable_code_pass(s);
3882b83eabeaSRichard Henderson     liveness_pass_1(s);
38835a18407fSRichard Henderson 
38845a18407fSRichard Henderson     if (s->nb_indirects > 0) {
38855a18407fSRichard Henderson #ifdef DEBUG_DISAS
38865a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
38875a18407fSRichard Henderson                      && qemu_log_in_addr_range(tb->pc))) {
38881ee73216SRichard Henderson             qemu_log_lock();
38895a18407fSRichard Henderson             qemu_log("OP before indirect lowering:\n");
38901894f69aSRichard Henderson             tcg_dump_ops(s, false);
38915a18407fSRichard Henderson             qemu_log("\n");
38921ee73216SRichard Henderson             qemu_log_unlock();
38935a18407fSRichard Henderson         }
38945a18407fSRichard Henderson #endif
38955a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
3896b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
38975a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
3898b83eabeaSRichard Henderson             liveness_pass_1(s);
38995a18407fSRichard Henderson         }
39005a18407fSRichard Henderson     }
3901c5cc28ffSAurelien Jarno 
3902a23a9ec6Sbellard #ifdef CONFIG_PROFILER
3903c3fac113SEmilio G. Cota     atomic_set(&prof->la_time, prof->la_time + profile_getclock());
3904a23a9ec6Sbellard #endif
3905c896fe29Sbellard 
3906c896fe29Sbellard #ifdef DEBUG_DISAS
3907d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
3908d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
39091ee73216SRichard Henderson         qemu_log_lock();
3910c5cc28ffSAurelien Jarno         qemu_log("OP after optimization and liveness analysis:\n");
39111894f69aSRichard Henderson         tcg_dump_ops(s, true);
391293fcfe39Saliguori         qemu_log("\n");
39131ee73216SRichard Henderson         qemu_log_unlock();
3914c896fe29Sbellard     }
3915c896fe29Sbellard #endif
3916c896fe29Sbellard 
3917c896fe29Sbellard     tcg_reg_alloc_start(s);
3918c896fe29Sbellard 
3919e7e168f4SEmilio G. Cota     s->code_buf = tb->tc.ptr;
3920e7e168f4SEmilio G. Cota     s->code_ptr = tb->tc.ptr;
3921c896fe29Sbellard 
3922659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
39236001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
3924659ef5cbSRichard Henderson #endif
392557a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
392657a26946SRichard Henderson     s->pool_labels = NULL;
392757a26946SRichard Henderson #endif
39289ecefc84SRichard Henderson 
3929fca8a500SRichard Henderson     num_insns = -1;
393015fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
3931c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
3932b3db8758Sblueswir1 
3933c896fe29Sbellard #ifdef CONFIG_PROFILER
3934c3fac113SEmilio G. Cota         atomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
3935c896fe29Sbellard #endif
3936c45cb8bbSRichard Henderson 
3937c896fe29Sbellard         switch (opc) {
3938c896fe29Sbellard         case INDEX_op_mov_i32:
3939c896fe29Sbellard         case INDEX_op_mov_i64:
3940d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
3941dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
3942c896fe29Sbellard             break;
3943e8996ee0Sbellard         case INDEX_op_movi_i32:
3944e8996ee0Sbellard         case INDEX_op_movi_i64:
3945d2fd745fSRichard Henderson         case INDEX_op_dupi_vec:
3946dd186292SRichard Henderson             tcg_reg_alloc_movi(s, op);
3947e8996ee0Sbellard             break;
3948765b842aSRichard Henderson         case INDEX_op_insn_start:
3949fca8a500SRichard Henderson             if (num_insns >= 0) {
39509f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
39519f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
39529f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
39539f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
3954fca8a500SRichard Henderson             }
3955fca8a500SRichard Henderson             num_insns++;
3956bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
3957bad729e2SRichard Henderson                 target_ulong a;
3958bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
3959efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
3960bad729e2SRichard Henderson #else
3961efee3746SRichard Henderson                 a = op->args[i];
3962bad729e2SRichard Henderson #endif
3963fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
3964bad729e2SRichard Henderson             }
3965c896fe29Sbellard             break;
39665ff9d6a4Sbellard         case INDEX_op_discard:
396743439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
39685ff9d6a4Sbellard             break;
3969c896fe29Sbellard         case INDEX_op_set_label:
3970e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
3971efee3746SRichard Henderson             tcg_out_label(s, arg_label(op->args[0]), s->code_ptr);
3972c896fe29Sbellard             break;
3973c896fe29Sbellard         case INDEX_op_call:
3974dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
3975c45cb8bbSRichard Henderson             break;
3976c896fe29Sbellard         default:
397725c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
3978be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
3979c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
3980c896fe29Sbellard                faster to have specialized register allocator functions for
3981c896fe29Sbellard                some common argument patterns */
3982dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
3983c896fe29Sbellard             break;
3984c896fe29Sbellard         }
39858d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
3986c896fe29Sbellard         check_regs(s);
3987c896fe29Sbellard #endif
3988b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
3989b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
3990b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
3991b125f9dcSRichard Henderson            generating code without having to check during generation.  */
3992644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
3993b125f9dcSRichard Henderson             return -1;
3994b125f9dcSRichard Henderson         }
3995c896fe29Sbellard     }
3996fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
3997fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
3998c45cb8bbSRichard Henderson 
3999b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
4000659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
4001659ef5cbSRichard Henderson     if (!tcg_out_ldst_finalize(s)) {
400223dceda6SRichard Henderson         return -1;
400323dceda6SRichard Henderson     }
4004659ef5cbSRichard Henderson #endif
400557a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
400657a26946SRichard Henderson     if (!tcg_out_pool_finalize(s)) {
400757a26946SRichard Henderson         return -1;
400857a26946SRichard Henderson     }
400957a26946SRichard Henderson #endif
4010c896fe29Sbellard 
4011c896fe29Sbellard     /* flush instruction cache */
40121813e175SRichard Henderson     flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr);
40132aeabc08SStefan Weil 
40141813e175SRichard Henderson     return tcg_current_code_size(s);
4015c896fe29Sbellard }
4016c896fe29Sbellard 
4017a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4018405cf9ffSStefan Weil void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
4019a23a9ec6Sbellard {
4020c3fac113SEmilio G. Cota     TCGProfile prof = {};
4021c3fac113SEmilio G. Cota     const TCGProfile *s;
4022c3fac113SEmilio G. Cota     int64_t tb_count;
4023c3fac113SEmilio G. Cota     int64_t tb_div_count;
4024c3fac113SEmilio G. Cota     int64_t tot;
4025c3fac113SEmilio G. Cota 
4026c3fac113SEmilio G. Cota     tcg_profile_snapshot_counters(&prof);
4027c3fac113SEmilio G. Cota     s = &prof;
4028c3fac113SEmilio G. Cota     tb_count = s->tb_count;
4029c3fac113SEmilio G. Cota     tb_div_count = tb_count ? tb_count : 1;
4030c3fac113SEmilio G. Cota     tot = s->interm_time + s->code_time;
4031a23a9ec6Sbellard 
4032a23a9ec6Sbellard     cpu_fprintf(f, "JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
4033a23a9ec6Sbellard                 tot, tot / 2.4e9);
4034a23a9ec6Sbellard     cpu_fprintf(f, "translated TBs      %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n",
4035fca8a500SRichard Henderson                 tb_count, s->tb_count1 - tb_count,
4036fca8a500SRichard Henderson                 (double)(s->tb_count1 - s->tb_count)
4037fca8a500SRichard Henderson                 / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
4038a23a9ec6Sbellard     cpu_fprintf(f, "avg ops/TB          %0.1f max=%d\n",
4039fca8a500SRichard Henderson                 (double)s->op_count / tb_div_count, s->op_count_max);
4040a23a9ec6Sbellard     cpu_fprintf(f, "deleted ops/TB      %0.2f\n",
4041fca8a500SRichard Henderson                 (double)s->del_op_count / tb_div_count);
4042a23a9ec6Sbellard     cpu_fprintf(f, "avg temps/TB        %0.2f max=%d\n",
4043fca8a500SRichard Henderson                 (double)s->temp_count / tb_div_count, s->temp_count_max);
4044fca8a500SRichard Henderson     cpu_fprintf(f, "avg host code/TB    %0.1f\n",
4045fca8a500SRichard Henderson                 (double)s->code_out_len / tb_div_count);
4046fca8a500SRichard Henderson     cpu_fprintf(f, "avg search data/TB  %0.1f\n",
4047fca8a500SRichard Henderson                 (double)s->search_out_len / tb_div_count);
4048a23a9ec6Sbellard 
4049a23a9ec6Sbellard     cpu_fprintf(f, "cycles/op           %0.1f\n",
4050a23a9ec6Sbellard                 s->op_count ? (double)tot / s->op_count : 0);
4051a23a9ec6Sbellard     cpu_fprintf(f, "cycles/in byte      %0.1f\n",
4052a23a9ec6Sbellard                 s->code_in_len ? (double)tot / s->code_in_len : 0);
4053a23a9ec6Sbellard     cpu_fprintf(f, "cycles/out byte     %0.1f\n",
4054a23a9ec6Sbellard                 s->code_out_len ? (double)tot / s->code_out_len : 0);
4055fca8a500SRichard Henderson     cpu_fprintf(f, "cycles/search byte     %0.1f\n",
4056fca8a500SRichard Henderson                 s->search_out_len ? (double)tot / s->search_out_len : 0);
4057fca8a500SRichard Henderson     if (tot == 0) {
4058a23a9ec6Sbellard         tot = 1;
4059fca8a500SRichard Henderson     }
4060a23a9ec6Sbellard     cpu_fprintf(f, "  gen_interm time   %0.1f%%\n",
4061a23a9ec6Sbellard                 (double)s->interm_time / tot * 100.0);
4062a23a9ec6Sbellard     cpu_fprintf(f, "  gen_code time     %0.1f%%\n",
4063a23a9ec6Sbellard                 (double)s->code_time / tot * 100.0);
4064c5cc28ffSAurelien Jarno     cpu_fprintf(f, "optim./code time    %0.1f%%\n",
4065c5cc28ffSAurelien Jarno                 (double)s->opt_time / (s->code_time ? s->code_time : 1)
4066c5cc28ffSAurelien Jarno                 * 100.0);
4067a23a9ec6Sbellard     cpu_fprintf(f, "liveness/code time  %0.1f%%\n",
4068a23a9ec6Sbellard                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
4069a23a9ec6Sbellard     cpu_fprintf(f, "cpu_restore count   %" PRId64 "\n",
4070a23a9ec6Sbellard                 s->restore_count);
4071a23a9ec6Sbellard     cpu_fprintf(f, "  avg cycles        %0.1f\n",
4072a23a9ec6Sbellard                 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
4073a23a9ec6Sbellard }
4074a23a9ec6Sbellard #else
4075405cf9ffSStefan Weil void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
4076a23a9ec6Sbellard {
407724bf7b3aSbellard     cpu_fprintf(f, "[TCG profiler not compiled]\n");
4078a23a9ec6Sbellard }
4079a23a9ec6Sbellard #endif
4080813da627SRichard Henderson 
4081813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
40825872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
40835872bbf2SRichard Henderson 
40845872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
40855872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
40865872bbf2SRichard Henderson 
40875872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
40885872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
40895872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
40905872bbf2SRichard Henderson 
40915872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
40925872bbf2SRichard Henderson */
4093813da627SRichard Henderson 
4094813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
4095813da627SRichard Henderson typedef enum {
4096813da627SRichard Henderson     JIT_NOACTION = 0,
4097813da627SRichard Henderson     JIT_REGISTER_FN,
4098813da627SRichard Henderson     JIT_UNREGISTER_FN
4099813da627SRichard Henderson } jit_actions_t;
4100813da627SRichard Henderson 
4101813da627SRichard Henderson struct jit_code_entry {
4102813da627SRichard Henderson     struct jit_code_entry *next_entry;
4103813da627SRichard Henderson     struct jit_code_entry *prev_entry;
4104813da627SRichard Henderson     const void *symfile_addr;
4105813da627SRichard Henderson     uint64_t symfile_size;
4106813da627SRichard Henderson };
4107813da627SRichard Henderson 
4108813da627SRichard Henderson struct jit_descriptor {
4109813da627SRichard Henderson     uint32_t version;
4110813da627SRichard Henderson     uint32_t action_flag;
4111813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
4112813da627SRichard Henderson     struct jit_code_entry *first_entry;
4113813da627SRichard Henderson };
4114813da627SRichard Henderson 
4115813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
4116813da627SRichard Henderson void __jit_debug_register_code(void)
4117813da627SRichard Henderson {
4118813da627SRichard Henderson     asm("");
4119813da627SRichard Henderson }
4120813da627SRichard Henderson 
4121813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
4122813da627SRichard Henderson    the version before we can set it.  */
4123813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
4124813da627SRichard Henderson 
4125813da627SRichard Henderson /* End GDB interface.  */
4126813da627SRichard Henderson 
4127813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
4128813da627SRichard Henderson {
4129813da627SRichard Henderson     const char *p = strtab + 1;
4130813da627SRichard Henderson 
4131813da627SRichard Henderson     while (1) {
4132813da627SRichard Henderson         if (strcmp(p, str) == 0) {
4133813da627SRichard Henderson             return p - strtab;
4134813da627SRichard Henderson         }
4135813da627SRichard Henderson         p += strlen(p) + 1;
4136813da627SRichard Henderson     }
4137813da627SRichard Henderson }
4138813da627SRichard Henderson 
41395872bbf2SRichard Henderson static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
41402c90784aSRichard Henderson                                  const void *debug_frame,
41412c90784aSRichard Henderson                                  size_t debug_frame_size)
4142813da627SRichard Henderson {
41435872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
41445872bbf2SRichard Henderson         uint32_t  len;
41455872bbf2SRichard Henderson         uint16_t  version;
41465872bbf2SRichard Henderson         uint32_t  abbrev;
41475872bbf2SRichard Henderson         uint8_t   ptr_size;
41485872bbf2SRichard Henderson         uint8_t   cu_die;
41495872bbf2SRichard Henderson         uint16_t  cu_lang;
41505872bbf2SRichard Henderson         uintptr_t cu_low_pc;
41515872bbf2SRichard Henderson         uintptr_t cu_high_pc;
41525872bbf2SRichard Henderson         uint8_t   fn_die;
41535872bbf2SRichard Henderson         char      fn_name[16];
41545872bbf2SRichard Henderson         uintptr_t fn_low_pc;
41555872bbf2SRichard Henderson         uintptr_t fn_high_pc;
41565872bbf2SRichard Henderson         uint8_t   cu_eoc;
41575872bbf2SRichard Henderson     };
4158813da627SRichard Henderson 
4159813da627SRichard Henderson     struct ElfImage {
4160813da627SRichard Henderson         ElfW(Ehdr) ehdr;
4161813da627SRichard Henderson         ElfW(Phdr) phdr;
41625872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
41635872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
41645872bbf2SRichard Henderson         struct DebugInfo di;
41655872bbf2SRichard Henderson         uint8_t    da[24];
41665872bbf2SRichard Henderson         char       str[80];
41675872bbf2SRichard Henderson     };
41685872bbf2SRichard Henderson 
41695872bbf2SRichard Henderson     struct ElfImage *img;
41705872bbf2SRichard Henderson 
41715872bbf2SRichard Henderson     static const struct ElfImage img_template = {
41725872bbf2SRichard Henderson         .ehdr = {
41735872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
41745872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
41755872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
41765872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
41775872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
41785872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
41795872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
41805872bbf2SRichard Henderson             .e_type = ET_EXEC,
41815872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
41825872bbf2SRichard Henderson             .e_version = EV_CURRENT,
41835872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
41845872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
41855872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
41865872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
41875872bbf2SRichard Henderson             .e_phnum = 1,
41885872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
41895872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
41905872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
4191abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
4192abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
4193abbb3eaeSRichard Henderson #endif
4194abbb3eaeSRichard Henderson #ifdef ELF_OSABI
4195abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
4196abbb3eaeSRichard Henderson #endif
41975872bbf2SRichard Henderson         },
41985872bbf2SRichard Henderson         .phdr = {
41995872bbf2SRichard Henderson             .p_type = PT_LOAD,
42005872bbf2SRichard Henderson             .p_flags = PF_X,
42015872bbf2SRichard Henderson         },
42025872bbf2SRichard Henderson         .shdr = {
42035872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
42045872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
42055872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
42065872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
42075872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
42085872bbf2SRichard Henderson             [1] = { /* .text */
42095872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
42105872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
42115872bbf2SRichard Henderson             },
42125872bbf2SRichard Henderson             [2] = { /* .debug_info */
42135872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
42145872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
42155872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
42165872bbf2SRichard Henderson             },
42175872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
42185872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
42195872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
42205872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
42215872bbf2SRichard Henderson             },
42225872bbf2SRichard Henderson             [4] = { /* .debug_frame */
42235872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
42245872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
42255872bbf2SRichard Henderson             },
42265872bbf2SRichard Henderson             [5] = { /* .symtab */
42275872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
42285872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
42295872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
42305872bbf2SRichard Henderson                 .sh_info = 1,
42315872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
42325872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
42335872bbf2SRichard Henderson             },
42345872bbf2SRichard Henderson             [6] = { /* .strtab */
42355872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
42365872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
42375872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
42385872bbf2SRichard Henderson             }
42395872bbf2SRichard Henderson         },
42405872bbf2SRichard Henderson         .sym = {
42415872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
42425872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
42435872bbf2SRichard Henderson                 .st_shndx = 1,
42445872bbf2SRichard Henderson             }
42455872bbf2SRichard Henderson         },
42465872bbf2SRichard Henderson         .di = {
42475872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
42485872bbf2SRichard Henderson             .version = 2,
42495872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
42505872bbf2SRichard Henderson             .cu_die = 1,
42515872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
42525872bbf2SRichard Henderson             .fn_die = 2,
42535872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
42545872bbf2SRichard Henderson         },
42555872bbf2SRichard Henderson         .da = {
42565872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
42575872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
42585872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
42595872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
42605872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
42615872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
42625872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
42635872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
42645872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
42655872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
42665872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
42675872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
42685872bbf2SRichard Henderson             0           /* no more abbrev */
42695872bbf2SRichard Henderson         },
42705872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
42715872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
4272813da627SRichard Henderson     };
4273813da627SRichard Henderson 
4274813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
4275813da627SRichard Henderson     static struct jit_code_entry one_entry;
4276813da627SRichard Henderson 
42775872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
4278813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
42792c90784aSRichard Henderson     DebugFrameHeader *dfh;
4280813da627SRichard Henderson 
42815872bbf2SRichard Henderson     img = g_malloc(img_size);
42825872bbf2SRichard Henderson     *img = img_template;
4283813da627SRichard Henderson 
42845872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
42855872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
42865872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
4287813da627SRichard Henderson 
42885872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
42895872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
42905872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
4291813da627SRichard Henderson 
42925872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
42935872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
42945872bbf2SRichard Henderson 
42955872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
42965872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
42975872bbf2SRichard Henderson 
42985872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
42995872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
43005872bbf2SRichard Henderson 
43015872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
43025872bbf2SRichard Henderson     img->sym[1].st_value = buf;
43035872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
43045872bbf2SRichard Henderson 
43055872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
430645aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
43075872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
430845aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
4309813da627SRichard Henderson 
43102c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
43112c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
43122c90784aSRichard Henderson     dfh->fde.func_start = buf;
43132c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
43142c90784aSRichard Henderson 
4315813da627SRichard Henderson #ifdef DEBUG_JIT
4316813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
4317813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
4318813da627SRichard Henderson     {
4319813da627SRichard Henderson         FILE *f = fopen("/tmp/qemu.jit", "w+b");
4320813da627SRichard Henderson         if (f) {
43215872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
4322813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
4323813da627SRichard Henderson             }
4324813da627SRichard Henderson             fclose(f);
4325813da627SRichard Henderson         }
4326813da627SRichard Henderson     }
4327813da627SRichard Henderson #endif
4328813da627SRichard Henderson 
4329813da627SRichard Henderson     one_entry.symfile_addr = img;
4330813da627SRichard Henderson     one_entry.symfile_size = img_size;
4331813da627SRichard Henderson 
4332813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
4333813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
4334813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
4335813da627SRichard Henderson     __jit_debug_register_code();
4336813da627SRichard Henderson }
4337813da627SRichard Henderson #else
43385872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
43395872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
4340813da627SRichard Henderson 
4341813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size,
43422c90784aSRichard Henderson                                  const void *debug_frame,
43432c90784aSRichard Henderson                                  size_t debug_frame_size)
4344813da627SRichard Henderson {
4345813da627SRichard Henderson }
4346813da627SRichard Henderson 
4347813da627SRichard Henderson void tcg_register_jit(void *buf, size_t buf_size)
4348813da627SRichard Henderson {
4349813da627SRichard Henderson }
4350813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
4351db432672SRichard Henderson 
4352db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
4353db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
4354db432672SRichard Henderson {
4355db432672SRichard Henderson     g_assert_not_reached();
4356db432672SRichard Henderson }
4357db432672SRichard Henderson #endif
4358