xref: /qemu/tcg/tcg.c (revision d6ecb4a978b718dbe108a9fa9ecccc8b7f7cb579)
1c896fe29Sbellard /*
2c896fe29Sbellard  * Tiny Code Generator for QEMU
3c896fe29Sbellard  *
4c896fe29Sbellard  * Copyright (c) 2008 Fabrice Bellard
5c896fe29Sbellard  *
6c896fe29Sbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
7c896fe29Sbellard  * of this software and associated documentation files (the "Software"), to deal
8c896fe29Sbellard  * in the Software without restriction, including without limitation the rights
9c896fe29Sbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10c896fe29Sbellard  * copies of the Software, and to permit persons to whom the Software is
11c896fe29Sbellard  * furnished to do so, subject to the following conditions:
12c896fe29Sbellard  *
13c896fe29Sbellard  * The above copyright notice and this permission notice shall be included in
14c896fe29Sbellard  * all copies or substantial portions of the Software.
15c896fe29Sbellard  *
16c896fe29Sbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17c896fe29Sbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18c896fe29Sbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19c896fe29Sbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20c896fe29Sbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21c896fe29Sbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22c896fe29Sbellard  * THE SOFTWARE.
23c896fe29Sbellard  */
24c896fe29Sbellard 
25c896fe29Sbellard /* define it to use liveness analysis (better code) */
268f2e8c07SKirill Batuzov #define USE_TCG_OPTIMIZATIONS
27c896fe29Sbellard 
28757e725bSPeter Maydell #include "qemu/osdep.h"
29cca82982Saurel32 
30813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB.  */
31813da627SRichard Henderson #undef DEBUG_JIT
32813da627SRichard Henderson 
3372fd2efbSEmilio G. Cota #include "qemu/error-report.h"
34f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
351de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
36d4c51a0aSMarkus Armbruster #include "qemu/qemu-print.h"
371de7afc9SPaolo Bonzini #include "qemu/timer.h"
38c896fe29Sbellard 
39c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU
40c896fe29Sbellard    CPU definitions. Currently they are used for qemu_ld/st
41c896fe29Sbellard    instructions */
42c896fe29Sbellard #define NO_CPU_IO_DEFS
43c896fe29Sbellard #include "cpu.h"
44c896fe29Sbellard 
4563c91552SPaolo Bonzini #include "exec/cpu-common.h"
4663c91552SPaolo Bonzini #include "exec/exec-all.h"
4763c91552SPaolo Bonzini 
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);
10678113e83SRichard Henderson static bool 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
112e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
113e7632cfaSRichard Henderson                             TCGReg dst, TCGReg src);
114*d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
115*d6ecb4a9SRichard Henderson                              TCGReg dst, TCGReg base, intptr_t offset);
116e7632cfaSRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type,
117e7632cfaSRichard Henderson                              TCGReg dst, tcg_target_long arg);
118d2fd745fSRichard Henderson static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl,
119d2fd745fSRichard Henderson                            unsigned vece, const TCGArg *args,
120d2fd745fSRichard Henderson                            const int *const_args);
121d2fd745fSRichard Henderson #else
122e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
123e7632cfaSRichard Henderson                                    TCGReg dst, TCGReg src)
124e7632cfaSRichard Henderson {
125e7632cfaSRichard Henderson     g_assert_not_reached();
126e7632cfaSRichard Henderson }
127*d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
128*d6ecb4a9SRichard Henderson                                     TCGReg dst, TCGReg base, intptr_t offset)
129*d6ecb4a9SRichard Henderson {
130*d6ecb4a9SRichard Henderson     g_assert_not_reached();
131*d6ecb4a9SRichard Henderson }
132e7632cfaSRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type,
133e7632cfaSRichard Henderson                                     TCGReg dst, tcg_target_long arg)
134e7632cfaSRichard Henderson {
135e7632cfaSRichard Henderson     g_assert_not_reached();
136e7632cfaSRichard Henderson }
137d2fd745fSRichard Henderson static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl,
138d2fd745fSRichard Henderson                                   unsigned vece, const TCGArg *args,
139d2fd745fSRichard Henderson                                   const int *const_args)
140d2fd745fSRichard Henderson {
141d2fd745fSRichard Henderson     g_assert_not_reached();
142d2fd745fSRichard Henderson }
143d2fd745fSRichard Henderson #endif
1442a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
145a05b5b9bSRichard Henderson                        intptr_t arg2);
14659d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
14759d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
148cf066674SRichard Henderson static void tcg_out_call(TCGContext *s, tcg_insn_unit *target);
149f6c6afc1SRichard Henderson static int tcg_target_const_match(tcg_target_long val, TCGType type,
150c0ad3001SStefan Weil                                   const TCGArgConstraint *arg_ct);
151659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
152aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s);
153659ef5cbSRichard Henderson #endif
154c896fe29Sbellard 
155a505785cSEmilio G. Cota #define TCG_HIGHWATER 1024
156a505785cSEmilio G. Cota 
157df2cce29SEmilio G. Cota static TCGContext **tcg_ctxs;
158df2cce29SEmilio G. Cota static unsigned int n_tcg_ctxs;
1591c2adb95SRichard Henderson TCGv_env cpu_env = 0;
160df2cce29SEmilio G. Cota 
161be2cdc5eSEmilio G. Cota struct tcg_region_tree {
162be2cdc5eSEmilio G. Cota     QemuMutex lock;
163be2cdc5eSEmilio G. Cota     GTree *tree;
164be2cdc5eSEmilio G. Cota     /* padding to avoid false sharing is computed at run-time */
165be2cdc5eSEmilio G. Cota };
166be2cdc5eSEmilio G. Cota 
167e8feb96fSEmilio G. Cota /*
168e8feb96fSEmilio G. Cota  * We divide code_gen_buffer into equally-sized "regions" that TCG threads
169e8feb96fSEmilio G. Cota  * dynamically allocate from as demand dictates. Given appropriate region
170e8feb96fSEmilio G. Cota  * sizing, this minimizes flushes even when some TCG threads generate a lot
171e8feb96fSEmilio G. Cota  * more code than others.
172e8feb96fSEmilio G. Cota  */
173e8feb96fSEmilio G. Cota struct tcg_region_state {
174e8feb96fSEmilio G. Cota     QemuMutex lock;
175e8feb96fSEmilio G. Cota 
176e8feb96fSEmilio G. Cota     /* fields set at init time */
177e8feb96fSEmilio G. Cota     void *start;
178e8feb96fSEmilio G. Cota     void *start_aligned;
179e8feb96fSEmilio G. Cota     void *end;
180e8feb96fSEmilio G. Cota     size_t n;
181e8feb96fSEmilio G. Cota     size_t size; /* size of one region */
182e8feb96fSEmilio G. Cota     size_t stride; /* .size + guard size */
183e8feb96fSEmilio G. Cota 
184e8feb96fSEmilio G. Cota     /* fields protected by the lock */
185e8feb96fSEmilio G. Cota     size_t current; /* current region index */
186e8feb96fSEmilio G. Cota     size_t agg_size_full; /* aggregate size of full regions */
187e8feb96fSEmilio G. Cota };
188e8feb96fSEmilio G. Cota 
189e8feb96fSEmilio G. Cota static struct tcg_region_state region;
190be2cdc5eSEmilio G. Cota /*
191be2cdc5eSEmilio G. Cota  * This is an array of struct tcg_region_tree's, with padding.
192be2cdc5eSEmilio G. Cota  * We use void * to simplify the computation of region_trees[i]; each
193be2cdc5eSEmilio G. Cota  * struct is found every tree_size bytes.
194be2cdc5eSEmilio G. Cota  */
195be2cdc5eSEmilio G. Cota static void *region_trees;
196be2cdc5eSEmilio G. Cota static size_t tree_size;
197d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
198b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
199c896fe29Sbellard 
2001813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
2014196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
202c896fe29Sbellard {
203c896fe29Sbellard     *s->code_ptr++ = v;
204c896fe29Sbellard }
205c896fe29Sbellard 
2064196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
2074196dca6SPeter Maydell                                                       uint8_t v)
2085c53bb81SPeter Maydell {
2091813e175SRichard Henderson     *p = v;
2105c53bb81SPeter Maydell }
2111813e175SRichard Henderson #endif
2125c53bb81SPeter Maydell 
2131813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
2144196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
215c896fe29Sbellard {
2161813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2171813e175SRichard Henderson         *s->code_ptr++ = v;
2181813e175SRichard Henderson     } else {
2191813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2204387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2211813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
2221813e175SRichard Henderson     }
223c896fe29Sbellard }
224c896fe29Sbellard 
2254196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2264196dca6SPeter Maydell                                                        uint16_t v)
2275c53bb81SPeter Maydell {
2281813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2291813e175SRichard Henderson         *p = v;
2301813e175SRichard Henderson     } else {
2315c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2325c53bb81SPeter Maydell     }
2331813e175SRichard Henderson }
2341813e175SRichard Henderson #endif
2355c53bb81SPeter Maydell 
2361813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
2374196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
238c896fe29Sbellard {
2391813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2401813e175SRichard Henderson         *s->code_ptr++ = v;
2411813e175SRichard Henderson     } else {
2421813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2434387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2441813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
2451813e175SRichard Henderson     }
246c896fe29Sbellard }
247c896fe29Sbellard 
2484196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
2494196dca6SPeter Maydell                                                        uint32_t v)
2505c53bb81SPeter Maydell {
2511813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2521813e175SRichard Henderson         *p = v;
2531813e175SRichard Henderson     } else {
2545c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2555c53bb81SPeter Maydell     }
2561813e175SRichard Henderson }
2571813e175SRichard Henderson #endif
2585c53bb81SPeter Maydell 
2591813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
2604196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
261ac26eb69SRichard Henderson {
2621813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2631813e175SRichard Henderson         *s->code_ptr++ = v;
2641813e175SRichard Henderson     } else {
2651813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2664387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2671813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
2681813e175SRichard Henderson     }
269ac26eb69SRichard Henderson }
270ac26eb69SRichard Henderson 
2714196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
2724196dca6SPeter Maydell                                                        uint64_t v)
2735c53bb81SPeter Maydell {
2741813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2751813e175SRichard Henderson         *p = v;
2761813e175SRichard Henderson     } else {
2775c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2785c53bb81SPeter Maydell     }
2791813e175SRichard Henderson }
2801813e175SRichard Henderson #endif
2815c53bb81SPeter Maydell 
282c896fe29Sbellard /* label relocation processing */
283c896fe29Sbellard 
2841813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
285bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
286c896fe29Sbellard {
2877ecd02a0SRichard Henderson     TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation));
288c896fe29Sbellard 
289c896fe29Sbellard     r->type = type;
290c896fe29Sbellard     r->ptr = code_ptr;
291c896fe29Sbellard     r->addend = addend;
2927ecd02a0SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
293c896fe29Sbellard }
294c896fe29Sbellard 
295bec16311SRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr)
296c896fe29Sbellard {
297eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
298c896fe29Sbellard     l->has_value = 1;
2991813e175SRichard Henderson     l->u.value_ptr = ptr;
300c896fe29Sbellard }
301c896fe29Sbellard 
30242a268c2SRichard Henderson TCGLabel *gen_new_label(void)
303c896fe29Sbellard {
304b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
30551e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
306c896fe29Sbellard 
3077ecd02a0SRichard Henderson     memset(l, 0, sizeof(TCGLabel));
3087ecd02a0SRichard Henderson     l->id = s->nb_labels++;
3097ecd02a0SRichard Henderson     QSIMPLEQ_INIT(&l->relocs);
3107ecd02a0SRichard Henderson 
311bef16ab4SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
31242a268c2SRichard Henderson 
31342a268c2SRichard Henderson     return l;
314c896fe29Sbellard }
315c896fe29Sbellard 
3167ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s)
3177ecd02a0SRichard Henderson {
3187ecd02a0SRichard Henderson     TCGLabel *l;
3197ecd02a0SRichard Henderson 
3207ecd02a0SRichard Henderson     QSIMPLEQ_FOREACH(l, &s->labels, next) {
3217ecd02a0SRichard Henderson         TCGRelocation *r;
3227ecd02a0SRichard Henderson         uintptr_t value = l->u.value;
3237ecd02a0SRichard Henderson 
3247ecd02a0SRichard Henderson         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
3257ecd02a0SRichard Henderson             if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
3267ecd02a0SRichard Henderson                 return false;
3277ecd02a0SRichard Henderson             }
3287ecd02a0SRichard Henderson         }
3297ecd02a0SRichard Henderson     }
3307ecd02a0SRichard Henderson     return true;
3317ecd02a0SRichard Henderson }
3327ecd02a0SRichard Henderson 
3339f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3349f754620SRichard Henderson {
3359f754620SRichard Henderson     size_t off = tcg_current_code_size(s);
3369f754620SRichard Henderson     s->tb_jmp_reset_offset[which] = off;
3379f754620SRichard Henderson     /* Make sure that we didn't overflow the stored offset.  */
3389f754620SRichard Henderson     assert(s->tb_jmp_reset_offset[which] == off);
3399f754620SRichard Henderson }
3409f754620SRichard Henderson 
341ce151109SPeter Maydell #include "tcg-target.inc.c"
342c896fe29Sbellard 
343be2cdc5eSEmilio G. Cota /* compare a pointer @ptr and a tb_tc @s */
344be2cdc5eSEmilio G. Cota static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s)
345be2cdc5eSEmilio G. Cota {
346be2cdc5eSEmilio G. Cota     if (ptr >= s->ptr + s->size) {
347be2cdc5eSEmilio G. Cota         return 1;
348be2cdc5eSEmilio G. Cota     } else if (ptr < s->ptr) {
349be2cdc5eSEmilio G. Cota         return -1;
350be2cdc5eSEmilio G. Cota     }
351be2cdc5eSEmilio G. Cota     return 0;
352be2cdc5eSEmilio G. Cota }
353be2cdc5eSEmilio G. Cota 
354be2cdc5eSEmilio G. Cota static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp)
355be2cdc5eSEmilio G. Cota {
356be2cdc5eSEmilio G. Cota     const struct tb_tc *a = ap;
357be2cdc5eSEmilio G. Cota     const struct tb_tc *b = bp;
358be2cdc5eSEmilio G. Cota 
359be2cdc5eSEmilio G. Cota     /*
360be2cdc5eSEmilio G. Cota      * When both sizes are set, we know this isn't a lookup.
361be2cdc5eSEmilio G. Cota      * This is the most likely case: every TB must be inserted; lookups
362be2cdc5eSEmilio G. Cota      * are a lot less frequent.
363be2cdc5eSEmilio G. Cota      */
364be2cdc5eSEmilio G. Cota     if (likely(a->size && b->size)) {
365be2cdc5eSEmilio G. Cota         if (a->ptr > b->ptr) {
366be2cdc5eSEmilio G. Cota             return 1;
367be2cdc5eSEmilio G. Cota         } else if (a->ptr < b->ptr) {
368be2cdc5eSEmilio G. Cota             return -1;
369be2cdc5eSEmilio G. Cota         }
370be2cdc5eSEmilio G. Cota         /* a->ptr == b->ptr should happen only on deletions */
371be2cdc5eSEmilio G. Cota         g_assert(a->size == b->size);
372be2cdc5eSEmilio G. Cota         return 0;
373be2cdc5eSEmilio G. Cota     }
374be2cdc5eSEmilio G. Cota     /*
375be2cdc5eSEmilio G. Cota      * All lookups have either .size field set to 0.
376be2cdc5eSEmilio G. Cota      * From the glib sources we see that @ap is always the lookup key. However
377be2cdc5eSEmilio G. Cota      * the docs provide no guarantee, so we just mark this case as likely.
378be2cdc5eSEmilio G. Cota      */
379be2cdc5eSEmilio G. Cota     if (likely(a->size == 0)) {
380be2cdc5eSEmilio G. Cota         return ptr_cmp_tb_tc(a->ptr, b);
381be2cdc5eSEmilio G. Cota     }
382be2cdc5eSEmilio G. Cota     return ptr_cmp_tb_tc(b->ptr, a);
383be2cdc5eSEmilio G. Cota }
384be2cdc5eSEmilio G. Cota 
385be2cdc5eSEmilio G. Cota static void tcg_region_trees_init(void)
386be2cdc5eSEmilio G. Cota {
387be2cdc5eSEmilio G. Cota     size_t i;
388be2cdc5eSEmilio G. Cota 
389be2cdc5eSEmilio G. Cota     tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize);
390be2cdc5eSEmilio G. Cota     region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size);
391be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
392be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
393be2cdc5eSEmilio G. Cota 
394be2cdc5eSEmilio G. Cota         qemu_mutex_init(&rt->lock);
395be2cdc5eSEmilio G. Cota         rt->tree = g_tree_new(tb_tc_cmp);
396be2cdc5eSEmilio G. Cota     }
397be2cdc5eSEmilio G. Cota }
398be2cdc5eSEmilio G. Cota 
399be2cdc5eSEmilio G. Cota static struct tcg_region_tree *tc_ptr_to_region_tree(void *p)
400be2cdc5eSEmilio G. Cota {
401be2cdc5eSEmilio G. Cota     size_t region_idx;
402be2cdc5eSEmilio G. Cota 
403be2cdc5eSEmilio G. Cota     if (p < region.start_aligned) {
404be2cdc5eSEmilio G. Cota         region_idx = 0;
405be2cdc5eSEmilio G. Cota     } else {
406be2cdc5eSEmilio G. Cota         ptrdiff_t offset = p - region.start_aligned;
407be2cdc5eSEmilio G. Cota 
408be2cdc5eSEmilio G. Cota         if (offset > region.stride * (region.n - 1)) {
409be2cdc5eSEmilio G. Cota             region_idx = region.n - 1;
410be2cdc5eSEmilio G. Cota         } else {
411be2cdc5eSEmilio G. Cota             region_idx = offset / region.stride;
412be2cdc5eSEmilio G. Cota         }
413be2cdc5eSEmilio G. Cota     }
414be2cdc5eSEmilio G. Cota     return region_trees + region_idx * tree_size;
415be2cdc5eSEmilio G. Cota }
416be2cdc5eSEmilio G. Cota 
417be2cdc5eSEmilio G. Cota void tcg_tb_insert(TranslationBlock *tb)
418be2cdc5eSEmilio G. Cota {
419be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
420be2cdc5eSEmilio G. Cota 
421be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
422be2cdc5eSEmilio G. Cota     g_tree_insert(rt->tree, &tb->tc, tb);
423be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
424be2cdc5eSEmilio G. Cota }
425be2cdc5eSEmilio G. Cota 
426be2cdc5eSEmilio G. Cota void tcg_tb_remove(TranslationBlock *tb)
427be2cdc5eSEmilio G. Cota {
428be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
429be2cdc5eSEmilio G. Cota 
430be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
431be2cdc5eSEmilio G. Cota     g_tree_remove(rt->tree, &tb->tc);
432be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
433be2cdc5eSEmilio G. Cota }
434be2cdc5eSEmilio G. Cota 
435be2cdc5eSEmilio G. Cota /*
436be2cdc5eSEmilio G. Cota  * Find the TB 'tb' such that
437be2cdc5eSEmilio G. Cota  * tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size
438be2cdc5eSEmilio G. Cota  * Return NULL if not found.
439be2cdc5eSEmilio G. Cota  */
440be2cdc5eSEmilio G. Cota TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr)
441be2cdc5eSEmilio G. Cota {
442be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr);
443be2cdc5eSEmilio G. Cota     TranslationBlock *tb;
444be2cdc5eSEmilio G. Cota     struct tb_tc s = { .ptr = (void *)tc_ptr };
445be2cdc5eSEmilio G. Cota 
446be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
447be2cdc5eSEmilio G. Cota     tb = g_tree_lookup(rt->tree, &s);
448be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
449be2cdc5eSEmilio G. Cota     return tb;
450be2cdc5eSEmilio G. Cota }
451be2cdc5eSEmilio G. Cota 
452be2cdc5eSEmilio G. Cota static void tcg_region_tree_lock_all(void)
453be2cdc5eSEmilio G. Cota {
454be2cdc5eSEmilio G. Cota     size_t i;
455be2cdc5eSEmilio G. Cota 
456be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
457be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
458be2cdc5eSEmilio G. Cota 
459be2cdc5eSEmilio G. Cota         qemu_mutex_lock(&rt->lock);
460be2cdc5eSEmilio G. Cota     }
461be2cdc5eSEmilio G. Cota }
462be2cdc5eSEmilio G. Cota 
463be2cdc5eSEmilio G. Cota static void tcg_region_tree_unlock_all(void)
464be2cdc5eSEmilio G. Cota {
465be2cdc5eSEmilio G. Cota     size_t i;
466be2cdc5eSEmilio G. Cota 
467be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
468be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
469be2cdc5eSEmilio G. Cota 
470be2cdc5eSEmilio G. Cota         qemu_mutex_unlock(&rt->lock);
471be2cdc5eSEmilio G. Cota     }
472be2cdc5eSEmilio G. Cota }
473be2cdc5eSEmilio G. Cota 
474be2cdc5eSEmilio G. Cota void tcg_tb_foreach(GTraverseFunc func, gpointer user_data)
475be2cdc5eSEmilio G. Cota {
476be2cdc5eSEmilio G. Cota     size_t i;
477be2cdc5eSEmilio G. Cota 
478be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
479be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
480be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
481be2cdc5eSEmilio G. Cota 
482be2cdc5eSEmilio G. Cota         g_tree_foreach(rt->tree, func, user_data);
483be2cdc5eSEmilio G. Cota     }
484be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
485be2cdc5eSEmilio G. Cota }
486be2cdc5eSEmilio G. Cota 
487be2cdc5eSEmilio G. Cota size_t tcg_nb_tbs(void)
488be2cdc5eSEmilio G. Cota {
489be2cdc5eSEmilio G. Cota     size_t nb_tbs = 0;
490be2cdc5eSEmilio G. Cota     size_t i;
491be2cdc5eSEmilio G. Cota 
492be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
493be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
494be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
495be2cdc5eSEmilio G. Cota 
496be2cdc5eSEmilio G. Cota         nb_tbs += g_tree_nnodes(rt->tree);
497be2cdc5eSEmilio G. Cota     }
498be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
499be2cdc5eSEmilio G. Cota     return nb_tbs;
500be2cdc5eSEmilio G. Cota }
501be2cdc5eSEmilio G. Cota 
502be2cdc5eSEmilio G. Cota static void tcg_region_tree_reset_all(void)
503be2cdc5eSEmilio G. Cota {
504be2cdc5eSEmilio G. Cota     size_t i;
505be2cdc5eSEmilio G. Cota 
506be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
507be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
508be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
509be2cdc5eSEmilio G. Cota 
510be2cdc5eSEmilio G. Cota         /* Increment the refcount first so that destroy acts as a reset */
511be2cdc5eSEmilio G. Cota         g_tree_ref(rt->tree);
512be2cdc5eSEmilio G. Cota         g_tree_destroy(rt->tree);
513be2cdc5eSEmilio G. Cota     }
514be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
515be2cdc5eSEmilio G. Cota }
516be2cdc5eSEmilio G. Cota 
517e8feb96fSEmilio G. Cota static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend)
518e8feb96fSEmilio G. Cota {
519e8feb96fSEmilio G. Cota     void *start, *end;
520e8feb96fSEmilio G. Cota 
521e8feb96fSEmilio G. Cota     start = region.start_aligned + curr_region * region.stride;
522e8feb96fSEmilio G. Cota     end = start + region.size;
523e8feb96fSEmilio G. Cota 
524e8feb96fSEmilio G. Cota     if (curr_region == 0) {
525e8feb96fSEmilio G. Cota         start = region.start;
526e8feb96fSEmilio G. Cota     }
527e8feb96fSEmilio G. Cota     if (curr_region == region.n - 1) {
528e8feb96fSEmilio G. Cota         end = region.end;
529e8feb96fSEmilio G. Cota     }
530e8feb96fSEmilio G. Cota 
531e8feb96fSEmilio G. Cota     *pstart = start;
532e8feb96fSEmilio G. Cota     *pend = end;
533e8feb96fSEmilio G. Cota }
534e8feb96fSEmilio G. Cota 
535e8feb96fSEmilio G. Cota static void tcg_region_assign(TCGContext *s, size_t curr_region)
536e8feb96fSEmilio G. Cota {
537e8feb96fSEmilio G. Cota     void *start, *end;
538e8feb96fSEmilio G. Cota 
539e8feb96fSEmilio G. Cota     tcg_region_bounds(curr_region, &start, &end);
540e8feb96fSEmilio G. Cota 
541e8feb96fSEmilio G. Cota     s->code_gen_buffer = start;
542e8feb96fSEmilio G. Cota     s->code_gen_ptr = start;
543e8feb96fSEmilio G. Cota     s->code_gen_buffer_size = end - start;
544e8feb96fSEmilio G. Cota     s->code_gen_highwater = end - TCG_HIGHWATER;
545e8feb96fSEmilio G. Cota }
546e8feb96fSEmilio G. Cota 
547e8feb96fSEmilio G. Cota static bool tcg_region_alloc__locked(TCGContext *s)
548e8feb96fSEmilio G. Cota {
549e8feb96fSEmilio G. Cota     if (region.current == region.n) {
550e8feb96fSEmilio G. Cota         return true;
551e8feb96fSEmilio G. Cota     }
552e8feb96fSEmilio G. Cota     tcg_region_assign(s, region.current);
553e8feb96fSEmilio G. Cota     region.current++;
554e8feb96fSEmilio G. Cota     return false;
555e8feb96fSEmilio G. Cota }
556e8feb96fSEmilio G. Cota 
557e8feb96fSEmilio G. Cota /*
558e8feb96fSEmilio G. Cota  * Request a new region once the one in use has filled up.
559e8feb96fSEmilio G. Cota  * Returns true on error.
560e8feb96fSEmilio G. Cota  */
561e8feb96fSEmilio G. Cota static bool tcg_region_alloc(TCGContext *s)
562e8feb96fSEmilio G. Cota {
563e8feb96fSEmilio G. Cota     bool err;
564e8feb96fSEmilio G. Cota     /* read the region size now; alloc__locked will overwrite it on success */
565e8feb96fSEmilio G. Cota     size_t size_full = s->code_gen_buffer_size;
566e8feb96fSEmilio G. Cota 
567e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
568e8feb96fSEmilio G. Cota     err = tcg_region_alloc__locked(s);
569e8feb96fSEmilio G. Cota     if (!err) {
570e8feb96fSEmilio G. Cota         region.agg_size_full += size_full - TCG_HIGHWATER;
571e8feb96fSEmilio G. Cota     }
572e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
573e8feb96fSEmilio G. Cota     return err;
574e8feb96fSEmilio G. Cota }
575e8feb96fSEmilio G. Cota 
576e8feb96fSEmilio G. Cota /*
577e8feb96fSEmilio G. Cota  * Perform a context's first region allocation.
578e8feb96fSEmilio G. Cota  * This function does _not_ increment region.agg_size_full.
579e8feb96fSEmilio G. Cota  */
580e8feb96fSEmilio G. Cota static inline bool tcg_region_initial_alloc__locked(TCGContext *s)
581e8feb96fSEmilio G. Cota {
582e8feb96fSEmilio G. Cota     return tcg_region_alloc__locked(s);
583e8feb96fSEmilio G. Cota }
584e8feb96fSEmilio G. Cota 
585e8feb96fSEmilio G. Cota /* Call from a safe-work context */
586e8feb96fSEmilio G. Cota void tcg_region_reset_all(void)
587e8feb96fSEmilio G. Cota {
5883468b59eSEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
589e8feb96fSEmilio G. Cota     unsigned int i;
590e8feb96fSEmilio G. Cota 
591e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
592e8feb96fSEmilio G. Cota     region.current = 0;
593e8feb96fSEmilio G. Cota     region.agg_size_full = 0;
594e8feb96fSEmilio G. Cota 
5953468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
5963468b59eSEmilio G. Cota         TCGContext *s = atomic_read(&tcg_ctxs[i]);
5973468b59eSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(s);
598e8feb96fSEmilio G. Cota 
599e8feb96fSEmilio G. Cota         g_assert(!err);
600e8feb96fSEmilio G. Cota     }
601e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
602be2cdc5eSEmilio G. Cota 
603be2cdc5eSEmilio G. Cota     tcg_region_tree_reset_all();
604e8feb96fSEmilio G. Cota }
605e8feb96fSEmilio G. Cota 
6063468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
6073468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
6083468b59eSEmilio G. Cota {
6093468b59eSEmilio G. Cota     return 1;
6103468b59eSEmilio G. Cota }
6113468b59eSEmilio G. Cota #else
6123468b59eSEmilio G. Cota /*
6133468b59eSEmilio G. Cota  * It is likely that some vCPUs will translate more code than others, so we
6143468b59eSEmilio G. Cota  * first try to set more regions than max_cpus, with those regions being of
6153468b59eSEmilio G. Cota  * reasonable size. If that's not possible we make do by evenly dividing
6163468b59eSEmilio G. Cota  * the code_gen_buffer among the vCPUs.
6173468b59eSEmilio G. Cota  */
6183468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
6193468b59eSEmilio G. Cota {
6203468b59eSEmilio G. Cota     size_t i;
6213468b59eSEmilio G. Cota 
6223468b59eSEmilio G. Cota     /* Use a single region if all we have is one vCPU thread */
6233468b59eSEmilio G. Cota     if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) {
6243468b59eSEmilio G. Cota         return 1;
6253468b59eSEmilio G. Cota     }
6263468b59eSEmilio G. Cota 
6273468b59eSEmilio G. Cota     /* Try to have more regions than max_cpus, with each region being >= 2 MB */
6283468b59eSEmilio G. Cota     for (i = 8; i > 0; i--) {
6293468b59eSEmilio G. Cota         size_t regions_per_thread = i;
6303468b59eSEmilio G. Cota         size_t region_size;
6313468b59eSEmilio G. Cota 
6323468b59eSEmilio G. Cota         region_size = tcg_init_ctx.code_gen_buffer_size;
6333468b59eSEmilio G. Cota         region_size /= max_cpus * regions_per_thread;
6343468b59eSEmilio G. Cota 
6353468b59eSEmilio G. Cota         if (region_size >= 2 * 1024u * 1024) {
6363468b59eSEmilio G. Cota             return max_cpus * regions_per_thread;
6373468b59eSEmilio G. Cota         }
6383468b59eSEmilio G. Cota     }
6393468b59eSEmilio G. Cota     /* If we can't, then just allocate one region per vCPU thread */
6403468b59eSEmilio G. Cota     return max_cpus;
6413468b59eSEmilio G. Cota }
6423468b59eSEmilio G. Cota #endif
6433468b59eSEmilio G. Cota 
644e8feb96fSEmilio G. Cota /*
645e8feb96fSEmilio G. Cota  * Initializes region partitioning.
646e8feb96fSEmilio G. Cota  *
647e8feb96fSEmilio G. Cota  * Called at init time from the parent thread (i.e. the one calling
648e8feb96fSEmilio G. Cota  * tcg_context_init), after the target's TCG globals have been set.
6493468b59eSEmilio G. Cota  *
6503468b59eSEmilio G. Cota  * Region partitioning works by splitting code_gen_buffer into separate regions,
6513468b59eSEmilio G. Cota  * and then assigning regions to TCG threads so that the threads can translate
6523468b59eSEmilio G. Cota  * code in parallel without synchronization.
6533468b59eSEmilio G. Cota  *
6543468b59eSEmilio G. Cota  * In softmmu the number of TCG threads is bounded by max_cpus, so we use at
6553468b59eSEmilio G. Cota  * least max_cpus regions in MTTCG. In !MTTCG we use a single region.
6563468b59eSEmilio G. Cota  * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...])
6573468b59eSEmilio G. Cota  * must have been parsed before calling this function, since it calls
6583468b59eSEmilio G. Cota  * qemu_tcg_mttcg_enabled().
6593468b59eSEmilio G. Cota  *
6603468b59eSEmilio G. Cota  * In user-mode we use a single region.  Having multiple regions in user-mode
6613468b59eSEmilio G. Cota  * is not supported, because the number of vCPU threads (recall that each thread
6623468b59eSEmilio G. Cota  * spawned by the guest corresponds to a vCPU thread) is only bounded by the
6633468b59eSEmilio G. Cota  * OS, and usually this number is huge (tens of thousands is not uncommon).
6643468b59eSEmilio G. Cota  * Thus, given this large bound on the number of vCPU threads and the fact
6653468b59eSEmilio G. Cota  * that code_gen_buffer is allocated at compile-time, we cannot guarantee
6663468b59eSEmilio G. Cota  * that the availability of at least one region per vCPU thread.
6673468b59eSEmilio G. Cota  *
6683468b59eSEmilio G. Cota  * However, this user-mode limitation is unlikely to be a significant problem
6693468b59eSEmilio G. Cota  * in practice. Multi-threaded guests share most if not all of their translated
6703468b59eSEmilio G. Cota  * code, which makes parallel code generation less appealing than in softmmu.
671e8feb96fSEmilio G. Cota  */
672e8feb96fSEmilio G. Cota void tcg_region_init(void)
673e8feb96fSEmilio G. Cota {
674e8feb96fSEmilio G. Cota     void *buf = tcg_init_ctx.code_gen_buffer;
675e8feb96fSEmilio G. Cota     void *aligned;
676e8feb96fSEmilio G. Cota     size_t size = tcg_init_ctx.code_gen_buffer_size;
677e8feb96fSEmilio G. Cota     size_t page_size = qemu_real_host_page_size;
678e8feb96fSEmilio G. Cota     size_t region_size;
679e8feb96fSEmilio G. Cota     size_t n_regions;
680e8feb96fSEmilio G. Cota     size_t i;
681e8feb96fSEmilio G. Cota 
6823468b59eSEmilio G. Cota     n_regions = tcg_n_regions();
683e8feb96fSEmilio G. Cota 
684e8feb96fSEmilio G. Cota     /* The first region will be 'aligned - buf' bytes larger than the others */
685e8feb96fSEmilio G. Cota     aligned = QEMU_ALIGN_PTR_UP(buf, page_size);
686e8feb96fSEmilio G. Cota     g_assert(aligned < tcg_init_ctx.code_gen_buffer + size);
687e8feb96fSEmilio G. Cota     /*
688e8feb96fSEmilio G. Cota      * Make region_size a multiple of page_size, using aligned as the start.
689e8feb96fSEmilio G. Cota      * As a result of this we might end up with a few extra pages at the end of
690e8feb96fSEmilio G. Cota      * the buffer; we will assign those to the last region.
691e8feb96fSEmilio G. Cota      */
692e8feb96fSEmilio G. Cota     region_size = (size - (aligned - buf)) / n_regions;
693e8feb96fSEmilio G. Cota     region_size = QEMU_ALIGN_DOWN(region_size, page_size);
694e8feb96fSEmilio G. Cota 
695e8feb96fSEmilio G. Cota     /* A region must have at least 2 pages; one code, one guard */
696e8feb96fSEmilio G. Cota     g_assert(region_size >= 2 * page_size);
697e8feb96fSEmilio G. Cota 
698e8feb96fSEmilio G. Cota     /* init the region struct */
699e8feb96fSEmilio G. Cota     qemu_mutex_init(&region.lock);
700e8feb96fSEmilio G. Cota     region.n = n_regions;
701e8feb96fSEmilio G. Cota     region.size = region_size - page_size;
702e8feb96fSEmilio G. Cota     region.stride = region_size;
703e8feb96fSEmilio G. Cota     region.start = buf;
704e8feb96fSEmilio G. Cota     region.start_aligned = aligned;
705e8feb96fSEmilio G. Cota     /* page-align the end, since its last page will be a guard page */
706e8feb96fSEmilio G. Cota     region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size);
707e8feb96fSEmilio G. Cota     /* account for that last guard page */
708e8feb96fSEmilio G. Cota     region.end -= page_size;
709e8feb96fSEmilio G. Cota 
710e8feb96fSEmilio G. Cota     /* set guard pages */
711e8feb96fSEmilio G. Cota     for (i = 0; i < region.n; i++) {
712e8feb96fSEmilio G. Cota         void *start, *end;
713e8feb96fSEmilio G. Cota         int rc;
714e8feb96fSEmilio G. Cota 
715e8feb96fSEmilio G. Cota         tcg_region_bounds(i, &start, &end);
716e8feb96fSEmilio G. Cota         rc = qemu_mprotect_none(end, page_size);
717e8feb96fSEmilio G. Cota         g_assert(!rc);
718e8feb96fSEmilio G. Cota     }
719e8feb96fSEmilio G. Cota 
720be2cdc5eSEmilio G. Cota     tcg_region_trees_init();
721be2cdc5eSEmilio G. Cota 
7223468b59eSEmilio G. Cota     /* In user-mode we support only one ctx, so do the initial allocation now */
7233468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
724e8feb96fSEmilio G. Cota     {
725e8feb96fSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(tcg_ctx);
726e8feb96fSEmilio G. Cota 
727e8feb96fSEmilio G. Cota         g_assert(!err);
728e8feb96fSEmilio G. Cota     }
7293468b59eSEmilio G. Cota #endif
730e8feb96fSEmilio G. Cota }
731e8feb96fSEmilio G. Cota 
732e8feb96fSEmilio G. Cota /*
7333468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
7343468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
7353468b59eSEmilio G. Cota  * before initiating translation.
7363468b59eSEmilio G. Cota  *
7373468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
7383468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
7393468b59eSEmilio G. Cota  *
7403468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
7413468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
7423468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
7433468b59eSEmilio G. Cota  *
7443468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
7453468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
7463468b59eSEmilio G. Cota  */
7473468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
7483468b59eSEmilio G. Cota void tcg_register_thread(void)
7493468b59eSEmilio G. Cota {
7503468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
7513468b59eSEmilio G. Cota }
7523468b59eSEmilio G. Cota #else
7533468b59eSEmilio G. Cota void tcg_register_thread(void)
7543468b59eSEmilio G. Cota {
7553468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
7563468b59eSEmilio G. Cota     unsigned int i, n;
7573468b59eSEmilio G. Cota     bool err;
7583468b59eSEmilio G. Cota 
7593468b59eSEmilio G. Cota     *s = tcg_init_ctx;
7603468b59eSEmilio G. Cota 
7613468b59eSEmilio G. Cota     /* Relink mem_base.  */
7623468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
7633468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
7643468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
7653468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
7663468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
7673468b59eSEmilio G. Cota         }
7683468b59eSEmilio G. Cota     }
7693468b59eSEmilio G. Cota 
7703468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
7713468b59eSEmilio G. Cota     n = atomic_fetch_inc(&n_tcg_ctxs);
7723468b59eSEmilio G. Cota     g_assert(n < max_cpus);
7733468b59eSEmilio G. Cota     atomic_set(&tcg_ctxs[n], s);
7743468b59eSEmilio G. Cota 
7753468b59eSEmilio G. Cota     tcg_ctx = s;
7763468b59eSEmilio G. Cota     qemu_mutex_lock(&region.lock);
7773468b59eSEmilio G. Cota     err = tcg_region_initial_alloc__locked(tcg_ctx);
7783468b59eSEmilio G. Cota     g_assert(!err);
7793468b59eSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
7803468b59eSEmilio G. Cota }
7813468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
7823468b59eSEmilio G. Cota 
7833468b59eSEmilio G. Cota /*
784e8feb96fSEmilio G. Cota  * Returns the size (in bytes) of all translated code (i.e. from all regions)
785e8feb96fSEmilio G. Cota  * currently in the cache.
786e8feb96fSEmilio G. Cota  * See also: tcg_code_capacity()
787e8feb96fSEmilio G. Cota  * Do not confuse with tcg_current_code_size(); that one applies to a single
788e8feb96fSEmilio G. Cota  * TCG context.
789e8feb96fSEmilio G. Cota  */
790e8feb96fSEmilio G. Cota size_t tcg_code_size(void)
791e8feb96fSEmilio G. Cota {
7923468b59eSEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
793e8feb96fSEmilio G. Cota     unsigned int i;
794e8feb96fSEmilio G. Cota     size_t total;
795e8feb96fSEmilio G. Cota 
796e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
797e8feb96fSEmilio G. Cota     total = region.agg_size_full;
7983468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
7993468b59eSEmilio G. Cota         const TCGContext *s = atomic_read(&tcg_ctxs[i]);
800e8feb96fSEmilio G. Cota         size_t size;
801e8feb96fSEmilio G. Cota 
802e8feb96fSEmilio G. Cota         size = atomic_read(&s->code_gen_ptr) - s->code_gen_buffer;
803e8feb96fSEmilio G. Cota         g_assert(size <= s->code_gen_buffer_size);
804e8feb96fSEmilio G. Cota         total += size;
805e8feb96fSEmilio G. Cota     }
806e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
807e8feb96fSEmilio G. Cota     return total;
808e8feb96fSEmilio G. Cota }
809e8feb96fSEmilio G. Cota 
810e8feb96fSEmilio G. Cota /*
811e8feb96fSEmilio G. Cota  * Returns the code capacity (in bytes) of the entire cache, i.e. including all
812e8feb96fSEmilio G. Cota  * regions.
813e8feb96fSEmilio G. Cota  * See also: tcg_code_size()
814e8feb96fSEmilio G. Cota  */
815e8feb96fSEmilio G. Cota size_t tcg_code_capacity(void)
816e8feb96fSEmilio G. Cota {
817e8feb96fSEmilio G. Cota     size_t guard_size, capacity;
818e8feb96fSEmilio G. Cota 
819e8feb96fSEmilio G. Cota     /* no need for synchronization; these variables are set at init time */
820e8feb96fSEmilio G. Cota     guard_size = region.stride - region.size;
821e8feb96fSEmilio G. Cota     capacity = region.end + guard_size - region.start;
822e8feb96fSEmilio G. Cota     capacity -= region.n * (guard_size + TCG_HIGHWATER);
823e8feb96fSEmilio G. Cota     return capacity;
824e8feb96fSEmilio G. Cota }
825e8feb96fSEmilio G. Cota 
826128ed227SEmilio G. Cota size_t tcg_tb_phys_invalidate_count(void)
827128ed227SEmilio G. Cota {
828128ed227SEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
829128ed227SEmilio G. Cota     unsigned int i;
830128ed227SEmilio G. Cota     size_t total = 0;
831128ed227SEmilio G. Cota 
832128ed227SEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
833128ed227SEmilio G. Cota         const TCGContext *s = atomic_read(&tcg_ctxs[i]);
834128ed227SEmilio G. Cota 
835128ed227SEmilio G. Cota         total += atomic_read(&s->tb_phys_invalidate_count);
836128ed227SEmilio G. Cota     }
837128ed227SEmilio G. Cota     return total;
838128ed227SEmilio G. Cota }
839128ed227SEmilio G. Cota 
840c896fe29Sbellard /* pool based memory allocation */
841c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
842c896fe29Sbellard {
843c896fe29Sbellard     TCGPool *p;
844c896fe29Sbellard     int pool_size;
845c896fe29Sbellard 
846c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
847c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
8487267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
849c896fe29Sbellard         p->size = size;
8504055299eSKirill Batuzov         p->next = s->pool_first_large;
8514055299eSKirill Batuzov         s->pool_first_large = p;
8524055299eSKirill Batuzov         return p->data;
853c896fe29Sbellard     } else {
854c896fe29Sbellard         p = s->pool_current;
855c896fe29Sbellard         if (!p) {
856c896fe29Sbellard             p = s->pool_first;
857c896fe29Sbellard             if (!p)
858c896fe29Sbellard                 goto new_pool;
859c896fe29Sbellard         } else {
860c896fe29Sbellard             if (!p->next) {
861c896fe29Sbellard             new_pool:
862c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
8637267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
864c896fe29Sbellard                 p->size = pool_size;
865c896fe29Sbellard                 p->next = NULL;
866c896fe29Sbellard                 if (s->pool_current)
867c896fe29Sbellard                     s->pool_current->next = p;
868c896fe29Sbellard                 else
869c896fe29Sbellard                     s->pool_first = p;
870c896fe29Sbellard             } else {
871c896fe29Sbellard                 p = p->next;
872c896fe29Sbellard             }
873c896fe29Sbellard         }
874c896fe29Sbellard     }
875c896fe29Sbellard     s->pool_current = p;
876c896fe29Sbellard     s->pool_cur = p->data + size;
877c896fe29Sbellard     s->pool_end = p->data + p->size;
878c896fe29Sbellard     return p->data;
879c896fe29Sbellard }
880c896fe29Sbellard 
881c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
882c896fe29Sbellard {
8834055299eSKirill Batuzov     TCGPool *p, *t;
8844055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
8854055299eSKirill Batuzov         t = p->next;
8864055299eSKirill Batuzov         g_free(p);
8874055299eSKirill Batuzov     }
8884055299eSKirill Batuzov     s->pool_first_large = NULL;
889c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
890c896fe29Sbellard     s->pool_current = NULL;
891c896fe29Sbellard }
892c896fe29Sbellard 
893100b5e01SRichard Henderson typedef struct TCGHelperInfo {
894100b5e01SRichard Henderson     void *func;
895100b5e01SRichard Henderson     const char *name;
896afb49896SRichard Henderson     unsigned flags;
897afb49896SRichard Henderson     unsigned sizemask;
898100b5e01SRichard Henderson } TCGHelperInfo;
899100b5e01SRichard Henderson 
9002ef6175aSRichard Henderson #include "exec/helper-proto.h"
9012ef6175aSRichard Henderson 
902100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = {
9032ef6175aSRichard Henderson #include "exec/helper-tcg.h"
904100b5e01SRichard Henderson };
905619205fdSEmilio G. Cota static GHashTable *helper_table;
906100b5e01SRichard Henderson 
90791478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
908f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
9091c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
9101c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
91191478cefSRichard Henderson 
912c896fe29Sbellard void tcg_context_init(TCGContext *s)
913c896fe29Sbellard {
914100b5e01SRichard Henderson     int op, total_args, n, i;
915c896fe29Sbellard     TCGOpDef *def;
916c896fe29Sbellard     TCGArgConstraint *args_ct;
917c896fe29Sbellard     int *sorted_args;
9181c2adb95SRichard Henderson     TCGTemp *ts;
919c896fe29Sbellard 
920c896fe29Sbellard     memset(s, 0, sizeof(*s));
921c896fe29Sbellard     s->nb_globals = 0;
922c896fe29Sbellard 
923c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
924c896fe29Sbellard        space */
925c896fe29Sbellard     total_args = 0;
926c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
927c896fe29Sbellard         def = &tcg_op_defs[op];
928c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
929c896fe29Sbellard         total_args += n;
930c896fe29Sbellard     }
931c896fe29Sbellard 
9327267c094SAnthony Liguori     args_ct = g_malloc(sizeof(TCGArgConstraint) * total_args);
9337267c094SAnthony Liguori     sorted_args = g_malloc(sizeof(int) * total_args);
934c896fe29Sbellard 
935c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
936c896fe29Sbellard         def = &tcg_op_defs[op];
937c896fe29Sbellard         def->args_ct = args_ct;
938c896fe29Sbellard         def->sorted_args = sorted_args;
939c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
940c896fe29Sbellard         sorted_args += n;
941c896fe29Sbellard         args_ct += n;
942c896fe29Sbellard     }
943c896fe29Sbellard 
9445cd8f621SRichard Henderson     /* Register helpers.  */
94584fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
946619205fdSEmilio G. Cota     helper_table = g_hash_table_new(NULL, NULL);
94784fd9dd3SRichard Henderson 
948100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
94984fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
95072866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
951100b5e01SRichard Henderson     }
9525cd8f621SRichard Henderson 
953c896fe29Sbellard     tcg_target_init(s);
954f69d277eSRichard Henderson     process_op_defs(s);
95591478cefSRichard Henderson 
95691478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
95791478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
95891478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
95991478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
96091478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
96191478cefSRichard Henderson             break;
96291478cefSRichard Henderson         }
96391478cefSRichard Henderson     }
96491478cefSRichard Henderson     for (i = 0; i < n; ++i) {
96591478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
96691478cefSRichard Henderson     }
96791478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
96891478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
96991478cefSRichard Henderson     }
970b1311c4aSEmilio G. Cota 
971b1311c4aSEmilio G. Cota     tcg_ctx = s;
9723468b59eSEmilio G. Cota     /*
9733468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
9743468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
9753468b59eSEmilio G. Cota      * reasoning behind this.
9763468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
9773468b59eSEmilio G. Cota      */
9783468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
979df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
980df2cce29SEmilio G. Cota     n_tcg_ctxs = 1;
9813468b59eSEmilio G. Cota #else
9823468b59eSEmilio G. Cota     tcg_ctxs = g_new(TCGContext *, max_cpus);
9833468b59eSEmilio G. Cota #endif
9841c2adb95SRichard Henderson 
9851c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
9861c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
9871c2adb95SRichard Henderson     cpu_env = temp_tcgv_ptr(ts);
9889002ec79SRichard Henderson }
989b03cce8eSbellard 
9906e3b2bfdSEmilio G. Cota /*
9916e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
9926e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
9936e3b2bfdSEmilio G. Cota  */
9946e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
9956e3b2bfdSEmilio G. Cota {
9966e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
9976e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
9986e3b2bfdSEmilio G. Cota     void *next;
9996e3b2bfdSEmilio G. Cota 
1000e8feb96fSEmilio G. Cota  retry:
10016e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
10026e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
10036e3b2bfdSEmilio G. Cota 
10046e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
1005e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
10066e3b2bfdSEmilio G. Cota             return NULL;
10076e3b2bfdSEmilio G. Cota         }
1008e8feb96fSEmilio G. Cota         goto retry;
1009e8feb96fSEmilio G. Cota     }
1010e8feb96fSEmilio G. Cota     atomic_set(&s->code_gen_ptr, next);
101157a26946SRichard Henderson     s->data_gen_ptr = NULL;
10126e3b2bfdSEmilio G. Cota     return tb;
10136e3b2bfdSEmilio G. Cota }
10146e3b2bfdSEmilio G. Cota 
10159002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
10169002ec79SRichard Henderson {
10178163b749SRichard Henderson     size_t prologue_size, total_size;
10188163b749SRichard Henderson     void *buf0, *buf1;
10198163b749SRichard Henderson 
10208163b749SRichard Henderson     /* Put the prologue at the beginning of code_gen_buffer.  */
10218163b749SRichard Henderson     buf0 = s->code_gen_buffer;
10225b38ee31SRichard Henderson     total_size = s->code_gen_buffer_size;
10238163b749SRichard Henderson     s->code_ptr = buf0;
10248163b749SRichard Henderson     s->code_buf = buf0;
10255b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
10268163b749SRichard Henderson     s->code_gen_prologue = buf0;
10278163b749SRichard Henderson 
10285b38ee31SRichard Henderson     /* Compute a high-water mark, at which we voluntarily flush the buffer
10295b38ee31SRichard Henderson        and start over.  The size here is arbitrary, significantly larger
10305b38ee31SRichard Henderson        than we expect the code generation for any one opcode to require.  */
10315b38ee31SRichard Henderson     s->code_gen_highwater = s->code_gen_buffer + (total_size - TCG_HIGHWATER);
10325b38ee31SRichard Henderson 
10335b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
10345b38ee31SRichard Henderson     s->pool_labels = NULL;
10355b38ee31SRichard Henderson #endif
10365b38ee31SRichard Henderson 
10378163b749SRichard Henderson     /* Generate the prologue.  */
1038b03cce8eSbellard     tcg_target_qemu_prologue(s);
10395b38ee31SRichard Henderson 
10405b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
10415b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
10425b38ee31SRichard Henderson     {
10431768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
10441768987bSRichard Henderson         tcg_debug_assert(result == 0);
10455b38ee31SRichard Henderson     }
10465b38ee31SRichard Henderson #endif
10475b38ee31SRichard Henderson 
10488163b749SRichard Henderson     buf1 = s->code_ptr;
10498163b749SRichard Henderson     flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1);
10508163b749SRichard Henderson 
10518163b749SRichard Henderson     /* Deduct the prologue from the buffer.  */
10528163b749SRichard Henderson     prologue_size = tcg_current_code_size(s);
10538163b749SRichard Henderson     s->code_gen_ptr = buf1;
10548163b749SRichard Henderson     s->code_gen_buffer = buf1;
10558163b749SRichard Henderson     s->code_buf = buf1;
10565b38ee31SRichard Henderson     total_size -= prologue_size;
10578163b749SRichard Henderson     s->code_gen_buffer_size = total_size;
10588163b749SRichard Henderson 
10598163b749SRichard Henderson     tcg_register_jit(s->code_gen_buffer, total_size);
1060d6b64b2bSRichard Henderson 
1061d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
1062d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
10631ee73216SRichard Henderson         qemu_log_lock();
10648163b749SRichard Henderson         qemu_log("PROLOGUE: [size=%zu]\n", prologue_size);
10655b38ee31SRichard Henderson         if (s->data_gen_ptr) {
10665b38ee31SRichard Henderson             size_t code_size = s->data_gen_ptr - buf0;
10675b38ee31SRichard Henderson             size_t data_size = prologue_size - code_size;
10685b38ee31SRichard Henderson             size_t i;
10695b38ee31SRichard Henderson 
10705b38ee31SRichard Henderson             log_disas(buf0, code_size);
10715b38ee31SRichard Henderson 
10725b38ee31SRichard Henderson             for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
10735b38ee31SRichard Henderson                 if (sizeof(tcg_target_ulong) == 8) {
10745b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
10755b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
10765b38ee31SRichard Henderson                              *(uint64_t *)(s->data_gen_ptr + i));
10775b38ee31SRichard Henderson                 } else {
10785b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .long  0x%08x\n",
10795b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
10805b38ee31SRichard Henderson                              *(uint32_t *)(s->data_gen_ptr + i));
10815b38ee31SRichard Henderson                 }
10825b38ee31SRichard Henderson             }
10835b38ee31SRichard Henderson         } else {
10848163b749SRichard Henderson             log_disas(buf0, prologue_size);
10855b38ee31SRichard Henderson         }
1086d6b64b2bSRichard Henderson         qemu_log("\n");
1087d6b64b2bSRichard Henderson         qemu_log_flush();
10881ee73216SRichard Henderson         qemu_log_unlock();
1089d6b64b2bSRichard Henderson     }
1090d6b64b2bSRichard Henderson #endif
1091cedbcb01SEmilio G. Cota 
1092cedbcb01SEmilio G. Cota     /* Assert that goto_ptr is implemented completely.  */
1093cedbcb01SEmilio G. Cota     if (TCG_TARGET_HAS_goto_ptr) {
1094cedbcb01SEmilio G. Cota         tcg_debug_assert(s->code_gen_epilogue != NULL);
1095cedbcb01SEmilio G. Cota     }
1096c896fe29Sbellard }
1097c896fe29Sbellard 
1098c896fe29Sbellard void tcg_func_start(TCGContext *s)
1099c896fe29Sbellard {
1100c896fe29Sbellard     tcg_pool_reset(s);
1101c896fe29Sbellard     s->nb_temps = s->nb_globals;
11020ec9eabcSRichard Henderson 
11030ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
11040ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
11050ec9eabcSRichard Henderson 
1106abebf925SRichard Henderson     s->nb_ops = 0;
1107c896fe29Sbellard     s->nb_labels = 0;
1108c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1109c896fe29Sbellard 
11100a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
11110a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
11120a209d4bSRichard Henderson #endif
11130a209d4bSRichard Henderson 
111415fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
111515fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
1116bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
1117c896fe29Sbellard }
1118c896fe29Sbellard 
11197ca4b752SRichard Henderson static inline TCGTemp *tcg_temp_alloc(TCGContext *s)
11207ca4b752SRichard Henderson {
11217ca4b752SRichard Henderson     int n = s->nb_temps++;
11227ca4b752SRichard Henderson     tcg_debug_assert(n < TCG_MAX_TEMPS);
11237ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
11247ca4b752SRichard Henderson }
11257ca4b752SRichard Henderson 
11267ca4b752SRichard Henderson static inline TCGTemp *tcg_global_alloc(TCGContext *s)
11277ca4b752SRichard Henderson {
1128fa477d25SRichard Henderson     TCGTemp *ts;
1129fa477d25SRichard Henderson 
11307ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
11317ca4b752SRichard Henderson     s->nb_globals++;
1132fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1133fa477d25SRichard Henderson     ts->temp_global = 1;
1134fa477d25SRichard Henderson 
1135fa477d25SRichard Henderson     return ts;
1136c896fe29Sbellard }
1137c896fe29Sbellard 
1138085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1139b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1140c896fe29Sbellard {
1141c896fe29Sbellard     TCGTemp *ts;
1142c896fe29Sbellard 
1143b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
1144c896fe29Sbellard         tcg_abort();
1145b3a62939SRichard Henderson     }
11467ca4b752SRichard Henderson 
11477ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1148c896fe29Sbellard     ts->base_type = type;
1149c896fe29Sbellard     ts->type = type;
1150c896fe29Sbellard     ts->fixed_reg = 1;
1151c896fe29Sbellard     ts->reg = reg;
1152c896fe29Sbellard     ts->name = name;
1153c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
11547ca4b752SRichard Henderson 
1155085272b3SRichard Henderson     return ts;
1156a7812ae4Spbrook }
1157a7812ae4Spbrook 
1158b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1159a7812ae4Spbrook {
1160b3a62939SRichard Henderson     s->frame_start = start;
1161b3a62939SRichard Henderson     s->frame_end = start + size;
1162085272b3SRichard Henderson     s->frame_temp
1163085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1164b3a62939SRichard Henderson }
1165a7812ae4Spbrook 
1166085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
1167e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
1168c896fe29Sbellard {
1169b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1170dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
11717ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1172b3915dbbSRichard Henderson     int indirect_reg = 0, bigendian = 0;
11737ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
11747ca4b752SRichard Henderson     bigendian = 1;
11757ca4b752SRichard Henderson #endif
1176c896fe29Sbellard 
1177b3915dbbSRichard Henderson     if (!base_ts->fixed_reg) {
11785a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
11795a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1180b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
11815a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
11825a18407fSRichard Henderson                             ? 2 : 1);
11835a18407fSRichard Henderson         indirect_reg = 1;
1184b3915dbbSRichard Henderson     }
1185b3915dbbSRichard Henderson 
11867ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
11877ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1188c896fe29Sbellard         char buf[64];
11897ca4b752SRichard Henderson 
11907ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1191c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1192b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1193c896fe29Sbellard         ts->mem_allocated = 1;
1194b3a62939SRichard Henderson         ts->mem_base = base_ts;
11957ca4b752SRichard Henderson         ts->mem_offset = offset + bigendian * 4;
1196c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1197c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1198c896fe29Sbellard         ts->name = strdup(buf);
1199c896fe29Sbellard 
12007ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
12017ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
12027ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1203b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
12047ca4b752SRichard Henderson         ts2->mem_allocated = 1;
12057ca4b752SRichard Henderson         ts2->mem_base = base_ts;
12067ca4b752SRichard Henderson         ts2->mem_offset = offset + (1 - bigendian) * 4;
1207c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1208c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1209120c1084SRichard Henderson         ts2->name = strdup(buf);
12107ca4b752SRichard Henderson     } else {
1211c896fe29Sbellard         ts->base_type = type;
1212c896fe29Sbellard         ts->type = type;
1213b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1214c896fe29Sbellard         ts->mem_allocated = 1;
1215b3a62939SRichard Henderson         ts->mem_base = base_ts;
1216c896fe29Sbellard         ts->mem_offset = offset;
1217c896fe29Sbellard         ts->name = name;
1218c896fe29Sbellard     }
1219085272b3SRichard Henderson     return ts;
1220c896fe29Sbellard }
1221c896fe29Sbellard 
12225bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local)
1223c896fe29Sbellard {
1224b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1225c896fe29Sbellard     TCGTemp *ts;
1226641d5fbeSbellard     int idx, k;
1227c896fe29Sbellard 
12280ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
12290ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
12300ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
12310ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
12320ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
12330ec9eabcSRichard Henderson 
1234e8996ee0Sbellard         ts = &s->temps[idx];
1235e8996ee0Sbellard         ts->temp_allocated = 1;
12367ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
12377ca4b752SRichard Henderson         tcg_debug_assert(ts->temp_local == temp_local);
1238e8996ee0Sbellard     } else {
12397ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
12407ca4b752SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
12417ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
12427ca4b752SRichard Henderson 
1243c896fe29Sbellard             ts->base_type = type;
1244c896fe29Sbellard             ts->type = TCG_TYPE_I32;
1245e8996ee0Sbellard             ts->temp_allocated = 1;
1246641d5fbeSbellard             ts->temp_local = temp_local;
12477ca4b752SRichard Henderson 
12487ca4b752SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
12497ca4b752SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
12507ca4b752SRichard Henderson             ts2->type = TCG_TYPE_I32;
12517ca4b752SRichard Henderson             ts2->temp_allocated = 1;
12527ca4b752SRichard Henderson             ts2->temp_local = temp_local;
12537ca4b752SRichard Henderson         } else {
1254c896fe29Sbellard             ts->base_type = type;
1255c896fe29Sbellard             ts->type = type;
1256e8996ee0Sbellard             ts->temp_allocated = 1;
1257641d5fbeSbellard             ts->temp_local = temp_local;
1258c896fe29Sbellard         }
1259e8996ee0Sbellard     }
126027bfd83cSPeter Maydell 
126127bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
126227bfd83cSPeter Maydell     s->temps_in_use++;
126327bfd83cSPeter Maydell #endif
1264085272b3SRichard Henderson     return ts;
1265c896fe29Sbellard }
1266c896fe29Sbellard 
1267d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1268d2fd745fSRichard Henderson {
1269d2fd745fSRichard Henderson     TCGTemp *t;
1270d2fd745fSRichard Henderson 
1271d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1272d2fd745fSRichard Henderson     switch (type) {
1273d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1274d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1275d2fd745fSRichard Henderson         break;
1276d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1277d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1278d2fd745fSRichard Henderson         break;
1279d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1280d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1281d2fd745fSRichard Henderson         break;
1282d2fd745fSRichard Henderson     default:
1283d2fd745fSRichard Henderson         g_assert_not_reached();
1284d2fd745fSRichard Henderson     }
1285d2fd745fSRichard Henderson #endif
1286d2fd745fSRichard Henderson 
1287d2fd745fSRichard Henderson     t = tcg_temp_new_internal(type, 0);
1288d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1289d2fd745fSRichard Henderson }
1290d2fd745fSRichard Henderson 
1291d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1292d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1293d2fd745fSRichard Henderson {
1294d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1295d2fd745fSRichard Henderson 
1296d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1297d2fd745fSRichard Henderson 
1298d2fd745fSRichard Henderson     t = tcg_temp_new_internal(t->base_type, 0);
1299d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1300d2fd745fSRichard Henderson }
1301d2fd745fSRichard Henderson 
13025bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1303c896fe29Sbellard {
1304b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1305085272b3SRichard Henderson     int k, idx;
1306c896fe29Sbellard 
130727bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
130827bfd83cSPeter Maydell     s->temps_in_use--;
130927bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
131027bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
131127bfd83cSPeter Maydell     }
131227bfd83cSPeter Maydell #endif
131327bfd83cSPeter Maydell 
1314085272b3SRichard Henderson     tcg_debug_assert(ts->temp_global == 0);
1315eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
1316e8996ee0Sbellard     ts->temp_allocated = 0;
13170ec9eabcSRichard Henderson 
1318085272b3SRichard Henderson     idx = temp_idx(ts);
131918d13fa2SAlexander Graf     k = ts->base_type + (ts->temp_local ? TCG_TYPE_COUNT : 0);
13200ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
1321e8996ee0Sbellard }
1322e8996ee0Sbellard 
1323a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
1324a7812ae4Spbrook {
1325a7812ae4Spbrook     TCGv_i32 t0;
1326a7812ae4Spbrook     t0 = tcg_temp_new_i32();
1327e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
1328e8996ee0Sbellard     return t0;
1329c896fe29Sbellard }
1330c896fe29Sbellard 
1331a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
1332c896fe29Sbellard {
1333a7812ae4Spbrook     TCGv_i64 t0;
1334a7812ae4Spbrook     t0 = tcg_temp_new_i64();
1335e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
1336e8996ee0Sbellard     return t0;
1337c896fe29Sbellard }
1338c896fe29Sbellard 
1339a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
1340bdffd4a9Saurel32 {
1341a7812ae4Spbrook     TCGv_i32 t0;
1342a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
1343bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
1344bdffd4a9Saurel32     return t0;
1345bdffd4a9Saurel32 }
1346bdffd4a9Saurel32 
1347a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
1348bdffd4a9Saurel32 {
1349a7812ae4Spbrook     TCGv_i64 t0;
1350a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
1351bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
1352bdffd4a9Saurel32     return t0;
1353bdffd4a9Saurel32 }
1354bdffd4a9Saurel32 
135527bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
135627bfd83cSPeter Maydell void tcg_clear_temp_count(void)
135727bfd83cSPeter Maydell {
1358b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
135927bfd83cSPeter Maydell     s->temps_in_use = 0;
136027bfd83cSPeter Maydell }
136127bfd83cSPeter Maydell 
136227bfd83cSPeter Maydell int tcg_check_temp_count(void)
136327bfd83cSPeter Maydell {
1364b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
136527bfd83cSPeter Maydell     if (s->temps_in_use) {
136627bfd83cSPeter Maydell         /* Clear the count so that we don't give another
136727bfd83cSPeter Maydell          * warning immediately next time around.
136827bfd83cSPeter Maydell          */
136927bfd83cSPeter Maydell         s->temps_in_use = 0;
137027bfd83cSPeter Maydell         return 1;
137127bfd83cSPeter Maydell     }
137227bfd83cSPeter Maydell     return 0;
137327bfd83cSPeter Maydell }
137427bfd83cSPeter Maydell #endif
137527bfd83cSPeter Maydell 
1376be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1377be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1378be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1379be0f34b5SRichard Henderson {
1380d2fd745fSRichard Henderson     const bool have_vec
1381d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1382d2fd745fSRichard Henderson 
1383be0f34b5SRichard Henderson     switch (op) {
1384be0f34b5SRichard Henderson     case INDEX_op_discard:
1385be0f34b5SRichard Henderson     case INDEX_op_set_label:
1386be0f34b5SRichard Henderson     case INDEX_op_call:
1387be0f34b5SRichard Henderson     case INDEX_op_br:
1388be0f34b5SRichard Henderson     case INDEX_op_mb:
1389be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1390be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1391be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1392be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i32:
1393be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i32:
1394be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i64:
1395be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i64:
1396be0f34b5SRichard Henderson         return true;
1397be0f34b5SRichard Henderson 
1398be0f34b5SRichard Henderson     case INDEX_op_goto_ptr:
1399be0f34b5SRichard Henderson         return TCG_TARGET_HAS_goto_ptr;
1400be0f34b5SRichard Henderson 
1401be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1402be0f34b5SRichard Henderson     case INDEX_op_movi_i32:
1403be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1404be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1405be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1406be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1407be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1408be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1409be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1410be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1411be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1412be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1413be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1414be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1415be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1416be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1417be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1418be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1419be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1420be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1421be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1422be0f34b5SRichard Henderson         return true;
1423be0f34b5SRichard Henderson 
1424be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1425be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1426be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1427be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1428be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1429be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1430be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1431be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1432be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1433be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1434be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1435be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1436be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1437be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1438be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1439be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1440be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1441be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1442be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1443be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1444fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
1445fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
1446be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1447be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1448be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1449be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1450be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1451be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1452be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1453be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1454be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1455be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1456be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1457be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1458be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1459be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1460be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1461be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1462be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1463be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1464be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1465be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1466be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1467be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1468be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1469be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1470be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1471be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1472be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1473be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1474be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1475be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1476be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1477be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1478be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1479be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1480be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1481be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1482be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1483be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1484be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1485be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1486be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1487be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1488be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1489be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1490be0f34b5SRichard Henderson 
1491be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1492be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1493be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1494be0f34b5SRichard Henderson 
1495be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1496be0f34b5SRichard Henderson     case INDEX_op_movi_i64:
1497be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1498be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1499be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1500be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1501be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1502be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1503be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1504be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1505be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1506be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1507be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1508be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1509be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1510be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1511be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1512be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1513be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1514be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1515be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1516be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1517be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1518be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1519be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1520be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1521be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1522be0f34b5SRichard Henderson 
1523be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1524be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1525be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1526be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1527be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1528be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1529be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1530be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1531be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1532be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
1533be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
1534be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
1535be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
1536be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
1537be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
1538be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
1539be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
1540be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
1541be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
1542be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
1543fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
1544fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
1545be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
1546be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrl_i64_i32;
1547be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
1548be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrh_i64_i32;
1549be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
1550be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
1551be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
1552be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
1553be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
1554be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
1555be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
1556be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
1557be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
1558be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
1559be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
1560be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
1561be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
1562be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
1563be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
1564be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
1565be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
1566be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
1567be0f34b5SRichard Henderson     case INDEX_op_not_i64:
1568be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
1569be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
1570be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
1571be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
1572be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
1573be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
1574be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
1575be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
1576be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
1577be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
1578be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
1579be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
1580be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
1581be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
1582be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
1583be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
1584be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
1585be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
1586be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
1587be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
1588be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
1589be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
1590be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
1591be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
1592be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
1593be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
1594be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
1595be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
1596be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
1597be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
1598be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
1599be0f34b5SRichard Henderson 
1600d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
1601d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
1602d2fd745fSRichard Henderson     case INDEX_op_dupi_vec:
1603d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
1604d2fd745fSRichard Henderson     case INDEX_op_st_vec:
1605d2fd745fSRichard Henderson     case INDEX_op_add_vec:
1606d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
1607d2fd745fSRichard Henderson     case INDEX_op_and_vec:
1608d2fd745fSRichard Henderson     case INDEX_op_or_vec:
1609d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
1610212be173SRichard Henderson     case INDEX_op_cmp_vec:
1611d2fd745fSRichard Henderson         return have_vec;
1612d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
1613d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
1614d2fd745fSRichard Henderson     case INDEX_op_not_vec:
1615d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
1616d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
1617d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
1618d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
1619d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
1620d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
1621d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
16223774030aSRichard Henderson     case INDEX_op_mul_vec:
16233774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
1624d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
1625d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
1626d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
1627d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
1628d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
1629d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
1630d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
1631d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
1632d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
1633d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
1634d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
1635d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
16368afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
16378afaf050SRichard Henderson     case INDEX_op_usadd_vec:
16388afaf050SRichard Henderson     case INDEX_op_sssub_vec:
16398afaf050SRichard Henderson     case INDEX_op_ussub_vec:
16408afaf050SRichard Henderson         return have_vec && TCG_TARGET_HAS_sat_vec;
1641dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
1642dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
1643dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
1644dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
1645dd0a0fcdSRichard Henderson         return have_vec && TCG_TARGET_HAS_minmax_vec;
1646d2fd745fSRichard Henderson 
1647db432672SRichard Henderson     default:
1648db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
1649db432672SRichard Henderson         return true;
1650be0f34b5SRichard Henderson     }
1651be0f34b5SRichard Henderson }
1652be0f34b5SRichard Henderson 
165339cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment
165439cf05d3Sbellard    and endian swap. Maybe it would be better to do the alignment
165539cf05d3Sbellard    and endian swap in tcg_reg_alloc_call(). */
1656ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
1657c896fe29Sbellard {
165875e8b9b7SRichard Henderson     int i, real_args, nb_rets, pi;
1659bbb8a1b4SRichard Henderson     unsigned sizemask, flags;
1660afb49896SRichard Henderson     TCGHelperInfo *info;
166175e8b9b7SRichard Henderson     TCGOp *op;
1662afb49896SRichard Henderson 
1663619205fdSEmilio G. Cota     info = g_hash_table_lookup(helper_table, (gpointer)func);
1664bbb8a1b4SRichard Henderson     flags = info->flags;
1665bbb8a1b4SRichard Henderson     sizemask = info->sizemask;
16662bece2c8SRichard Henderson 
166734b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
166834b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
166934b1a49cSRichard Henderson     /* We have 64-bit values in one register, but need to pass as two
167034b1a49cSRichard Henderson        separate parameters.  Split them.  */
167134b1a49cSRichard Henderson     int orig_sizemask = sizemask;
167234b1a49cSRichard Henderson     int orig_nargs = nargs;
167334b1a49cSRichard Henderson     TCGv_i64 retl, reth;
1674ae8b75dcSRichard Henderson     TCGTemp *split_args[MAX_OPC_PARAM];
167534b1a49cSRichard Henderson 
1676f764718dSRichard Henderson     retl = NULL;
1677f764718dSRichard Henderson     reth = NULL;
167834b1a49cSRichard Henderson     if (sizemask != 0) {
167934b1a49cSRichard Henderson         for (i = real_args = 0; i < nargs; ++i) {
168034b1a49cSRichard Henderson             int is_64bit = sizemask & (1 << (i+1)*2);
168134b1a49cSRichard Henderson             if (is_64bit) {
1682085272b3SRichard Henderson                 TCGv_i64 orig = temp_tcgv_i64(args[i]);
168334b1a49cSRichard Henderson                 TCGv_i32 h = tcg_temp_new_i32();
168434b1a49cSRichard Henderson                 TCGv_i32 l = tcg_temp_new_i32();
168534b1a49cSRichard Henderson                 tcg_gen_extr_i64_i32(l, h, orig);
1686ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(h);
1687ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(l);
168834b1a49cSRichard Henderson             } else {
168934b1a49cSRichard Henderson                 split_args[real_args++] = args[i];
169034b1a49cSRichard Henderson             }
169134b1a49cSRichard Henderson         }
169234b1a49cSRichard Henderson         nargs = real_args;
169334b1a49cSRichard Henderson         args = split_args;
169434b1a49cSRichard Henderson         sizemask = 0;
169534b1a49cSRichard Henderson     }
169634b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
16972bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
16982bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
16992bece2c8SRichard Henderson         int is_signed = sizemask & (2 << (i+1)*2);
17002bece2c8SRichard Henderson         if (!is_64bit) {
17012bece2c8SRichard Henderson             TCGv_i64 temp = tcg_temp_new_i64();
1702085272b3SRichard Henderson             TCGv_i64 orig = temp_tcgv_i64(args[i]);
17032bece2c8SRichard Henderson             if (is_signed) {
17042bece2c8SRichard Henderson                 tcg_gen_ext32s_i64(temp, orig);
17052bece2c8SRichard Henderson             } else {
17062bece2c8SRichard Henderson                 tcg_gen_ext32u_i64(temp, orig);
17072bece2c8SRichard Henderson             }
1708ae8b75dcSRichard Henderson             args[i] = tcgv_i64_temp(temp);
17092bece2c8SRichard Henderson         }
17102bece2c8SRichard Henderson     }
17112bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
17122bece2c8SRichard Henderson 
171315fa08f8SRichard Henderson     op = tcg_emit_op(INDEX_op_call);
171475e8b9b7SRichard Henderson 
171575e8b9b7SRichard Henderson     pi = 0;
1716ae8b75dcSRichard Henderson     if (ret != NULL) {
171734b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
171834b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
171934b1a49cSRichard Henderson         if (orig_sizemask & 1) {
172034b1a49cSRichard Henderson             /* The 32-bit ABI is going to return the 64-bit value in
172134b1a49cSRichard Henderson                the %o0/%o1 register pair.  Prepare for this by using
172234b1a49cSRichard Henderson                two return temporaries, and reassemble below.  */
172334b1a49cSRichard Henderson             retl = tcg_temp_new_i64();
172434b1a49cSRichard Henderson             reth = tcg_temp_new_i64();
1725ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(reth);
1726ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(retl);
172734b1a49cSRichard Henderson             nb_rets = 2;
172834b1a49cSRichard Henderson         } else {
1729ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
173034b1a49cSRichard Henderson             nb_rets = 1;
173134b1a49cSRichard Henderson         }
173234b1a49cSRichard Henderson #else
173334b1a49cSRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) {
173402eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
1735ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1736ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1737a7812ae4Spbrook #else
1738ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1739ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1740a7812ae4Spbrook #endif
1741a7812ae4Spbrook             nb_rets = 2;
174234b1a49cSRichard Henderson         } else {
1743ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1744a7812ae4Spbrook             nb_rets = 1;
1745a7812ae4Spbrook         }
174634b1a49cSRichard Henderson #endif
1747a7812ae4Spbrook     } else {
1748a7812ae4Spbrook         nb_rets = 0;
1749a7812ae4Spbrook     }
1750cd9090aaSRichard Henderson     TCGOP_CALLO(op) = nb_rets;
175175e8b9b7SRichard Henderson 
1752a7812ae4Spbrook     real_args = 0;
1753a7812ae4Spbrook     for (i = 0; i < nargs; i++) {
17542bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
1755bbb8a1b4SRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
175639cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS
175739cf05d3Sbellard             /* some targets want aligned 64 bit args */
1758ebd486d5Smalc             if (real_args & 1) {
175975e8b9b7SRichard Henderson                 op->args[pi++] = TCG_CALL_DUMMY_ARG;
1760ebd486d5Smalc                 real_args++;
176139cf05d3Sbellard             }
176239cf05d3Sbellard #endif
17633f90f252SRichard Henderson            /* If stack grows up, then we will be placing successive
17643f90f252SRichard Henderson               arguments at lower addresses, which means we need to
17653f90f252SRichard Henderson               reverse the order compared to how we would normally
17663f90f252SRichard Henderson               treat either big or little-endian.  For those arguments
17673f90f252SRichard Henderson               that will wind up in registers, this still works for
17683f90f252SRichard Henderson               HPPA (the only current STACK_GROWSUP target) since the
17693f90f252SRichard Henderson               argument registers are *also* allocated in decreasing
17703f90f252SRichard Henderson               order.  If another such target is added, this logic may
17713f90f252SRichard Henderson               have to get more complicated to differentiate between
17723f90f252SRichard Henderson               stack arguments and register arguments.  */
177302eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
1774ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1775ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1776c896fe29Sbellard #else
1777ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1778ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1779c896fe29Sbellard #endif
1780a7812ae4Spbrook             real_args += 2;
17812bece2c8SRichard Henderson             continue;
17822bece2c8SRichard Henderson         }
17832bece2c8SRichard Henderson 
1784ae8b75dcSRichard Henderson         op->args[pi++] = temp_arg(args[i]);
1785a7812ae4Spbrook         real_args++;
1786c896fe29Sbellard     }
178775e8b9b7SRichard Henderson     op->args[pi++] = (uintptr_t)func;
178875e8b9b7SRichard Henderson     op->args[pi++] = flags;
1789cd9090aaSRichard Henderson     TCGOP_CALLI(op) = real_args;
1790a7812ae4Spbrook 
179175e8b9b7SRichard Henderson     /* Make sure the fields didn't overflow.  */
1792cd9090aaSRichard Henderson     tcg_debug_assert(TCGOP_CALLI(op) == real_args);
179375e8b9b7SRichard Henderson     tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
17942bece2c8SRichard Henderson 
179534b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
179634b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
179734b1a49cSRichard Henderson     /* Free all of the parts we allocated above.  */
179834b1a49cSRichard Henderson     for (i = real_args = 0; i < orig_nargs; ++i) {
179934b1a49cSRichard Henderson         int is_64bit = orig_sizemask & (1 << (i+1)*2);
180034b1a49cSRichard Henderson         if (is_64bit) {
1801085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
1802085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
180334b1a49cSRichard Henderson         } else {
180434b1a49cSRichard Henderson             real_args++;
180534b1a49cSRichard Henderson         }
180634b1a49cSRichard Henderson     }
180734b1a49cSRichard Henderson     if (orig_sizemask & 1) {
180834b1a49cSRichard Henderson         /* The 32-bit ABI returned two 32-bit pieces.  Re-assemble them.
180934b1a49cSRichard Henderson            Note that describing these as TCGv_i64 eliminates an unnecessary
181034b1a49cSRichard Henderson            zero-extension that tcg_gen_concat_i32_i64 would create.  */
1811085272b3SRichard Henderson         tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth);
181234b1a49cSRichard Henderson         tcg_temp_free_i64(retl);
181334b1a49cSRichard Henderson         tcg_temp_free_i64(reth);
181434b1a49cSRichard Henderson     }
181534b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
18162bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
18172bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
18182bece2c8SRichard Henderson         if (!is_64bit) {
1819085272b3SRichard Henderson             tcg_temp_free_internal(args[i]);
18202bece2c8SRichard Henderson         }
18212bece2c8SRichard Henderson     }
18222bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
1823a7812ae4Spbrook }
1824c896fe29Sbellard 
18258fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
1826c896fe29Sbellard {
1827ac3b8891SRichard Henderson     int i, n;
1828c896fe29Sbellard     TCGTemp *ts;
1829ac3b8891SRichard Henderson 
1830ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
1831c896fe29Sbellard         ts = &s->temps[i];
1832ac3b8891SRichard Henderson         ts->val_type = (ts->fixed_reg ? TEMP_VAL_REG : TEMP_VAL_MEM);
1833c896fe29Sbellard     }
1834ac3b8891SRichard Henderson     for (n = s->nb_temps; i < n; i++) {
1835e8996ee0Sbellard         ts = &s->temps[i];
1836ac3b8891SRichard Henderson         ts->val_type = (ts->temp_local ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
1837e8996ee0Sbellard         ts->mem_allocated = 0;
1838e8996ee0Sbellard         ts->fixed_reg = 0;
1839e8996ee0Sbellard     }
1840f8b2f202SRichard Henderson 
1841f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
1842c896fe29Sbellard }
1843c896fe29Sbellard 
1844f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
1845f8b2f202SRichard Henderson                                  TCGTemp *ts)
1846c896fe29Sbellard {
18471807f4c4SRichard Henderson     int idx = temp_idx(ts);
1848ac56dd48Spbrook 
1849fa477d25SRichard Henderson     if (ts->temp_global) {
1850ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
1851f8b2f202SRichard Henderson     } else if (ts->temp_local) {
1852641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
1853f8b2f202SRichard Henderson     } else {
1854ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
1855c896fe29Sbellard     }
1856c896fe29Sbellard     return buf;
1857c896fe29Sbellard }
1858c896fe29Sbellard 
185943439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
186043439139SRichard Henderson                              int buf_size, TCGArg arg)
1861f8b2f202SRichard Henderson {
186243439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
1863f8b2f202SRichard Henderson }
1864f8b2f202SRichard Henderson 
18656e085f72SRichard Henderson /* Find helper name.  */
18666e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val)
1867e8996ee0Sbellard {
18686e085f72SRichard Henderson     const char *ret = NULL;
1869619205fdSEmilio G. Cota     if (helper_table) {
1870619205fdSEmilio G. Cota         TCGHelperInfo *info = g_hash_table_lookup(helper_table, (gpointer)val);
187172866e82SRichard Henderson         if (info) {
187272866e82SRichard Henderson             ret = info->name;
187372866e82SRichard Henderson         }
1874e8996ee0Sbellard     }
18756e085f72SRichard Henderson     return ret;
18764dc81f28Sbellard }
18774dc81f28Sbellard 
1878f48f3edeSblueswir1 static const char * const cond_name[] =
1879f48f3edeSblueswir1 {
18800aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
18810aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
1882f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
1883f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
1884f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
1885f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
1886f48f3edeSblueswir1     [TCG_COND_LE] = "le",
1887f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
1888f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
1889f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
1890f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
1891f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
1892f48f3edeSblueswir1 };
1893f48f3edeSblueswir1 
1894f713d6adSRichard Henderson static const char * const ldst_name[] =
1895f713d6adSRichard Henderson {
1896f713d6adSRichard Henderson     [MO_UB]   = "ub",
1897f713d6adSRichard Henderson     [MO_SB]   = "sb",
1898f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
1899f713d6adSRichard Henderson     [MO_LESW] = "lesw",
1900f713d6adSRichard Henderson     [MO_LEUL] = "leul",
1901f713d6adSRichard Henderson     [MO_LESL] = "lesl",
1902f713d6adSRichard Henderson     [MO_LEQ]  = "leq",
1903f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
1904f713d6adSRichard Henderson     [MO_BESW] = "besw",
1905f713d6adSRichard Henderson     [MO_BEUL] = "beul",
1906f713d6adSRichard Henderson     [MO_BESL] = "besl",
1907f713d6adSRichard Henderson     [MO_BEQ]  = "beq",
1908f713d6adSRichard Henderson };
1909f713d6adSRichard Henderson 
19101f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
19111f00b27fSSergey Sorokin #ifdef ALIGNED_ONLY
19121f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
19131f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
19141f00b27fSSergey Sorokin #else
19151f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
19161f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
19171f00b27fSSergey Sorokin #endif
19181f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
19191f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
19201f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
19211f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
19221f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
19231f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
19241f00b27fSSergey Sorokin };
19251f00b27fSSergey Sorokin 
1926b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
1927b016486eSRichard Henderson {
1928b016486eSRichard Henderson     return (d & (d - 1)) == 0;
1929b016486eSRichard Henderson }
1930b016486eSRichard Henderson 
1931b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
1932b016486eSRichard Henderson {
1933b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
1934b016486eSRichard Henderson         return ctz32(d);
1935b016486eSRichard Henderson     } else {
1936b016486eSRichard Henderson         return ctz64(d);
1937b016486eSRichard Henderson     }
1938b016486eSRichard Henderson }
1939b016486eSRichard Henderson 
19401894f69aSRichard Henderson static void tcg_dump_ops(TCGContext *s, bool have_prefs)
1941c896fe29Sbellard {
1942c896fe29Sbellard     char buf[128];
1943c45cb8bbSRichard Henderson     TCGOp *op;
1944c896fe29Sbellard 
194515fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
1946c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
1947c45cb8bbSRichard Henderson         const TCGOpDef *def;
1948c45cb8bbSRichard Henderson         TCGOpcode c;
1949bdfb460eSRichard Henderson         int col = 0;
1950c45cb8bbSRichard Henderson 
1951c45cb8bbSRichard Henderson         c = op->opc;
1952c896fe29Sbellard         def = &tcg_op_defs[c];
1953c45cb8bbSRichard Henderson 
1954765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
1955b016486eSRichard Henderson             nb_oargs = 0;
195615fa08f8SRichard Henderson             col += qemu_log("\n ----");
19579aef40edSRichard Henderson 
19589aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
19599aef40edSRichard Henderson                 target_ulong a;
19607e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
1961efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
19627e4597d7Sbellard #else
1963efee3746SRichard Henderson                 a = op->args[i];
19647e4597d7Sbellard #endif
1965bdfb460eSRichard Henderson                 col += qemu_log(" " TARGET_FMT_lx, a);
1966eeacee4dSBlue Swirl             }
19677e4597d7Sbellard         } else if (c == INDEX_op_call) {
1968c896fe29Sbellard             /* variable number of arguments */
1969cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
1970cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
1971c896fe29Sbellard             nb_cargs = def->nb_cargs;
1972b03cce8eSbellard 
1973cf066674SRichard Henderson             /* function name, flags, out args */
1974bdfb460eSRichard Henderson             col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name,
1975efee3746SRichard Henderson                             tcg_find_helper(s, op->args[nb_oargs + nb_iargs]),
1976efee3746SRichard Henderson                             op->args[nb_oargs + nb_iargs + 1], nb_oargs);
1977b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
197843439139SRichard Henderson                 col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf),
1979efee3746SRichard Henderson                                                        op->args[i]));
1980b03cce8eSbellard             }
1981cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
1982efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
1983cf066674SRichard Henderson                 const char *t = "<dummy>";
1984cf066674SRichard Henderson                 if (arg != TCG_CALL_DUMMY_ARG) {
198543439139SRichard Henderson                     t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
1986b03cce8eSbellard                 }
1987bdfb460eSRichard Henderson                 col += qemu_log(",%s", t);
1988e8996ee0Sbellard             }
1989b03cce8eSbellard         } else {
1990bdfb460eSRichard Henderson             col += qemu_log(" %s ", def->name);
1991c45cb8bbSRichard Henderson 
1992c896fe29Sbellard             nb_oargs = def->nb_oargs;
1993c896fe29Sbellard             nb_iargs = def->nb_iargs;
1994c896fe29Sbellard             nb_cargs = def->nb_cargs;
1995c896fe29Sbellard 
1996d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
1997d2fd745fSRichard Henderson                 col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op),
1998d2fd745fSRichard Henderson                                 8 << TCGOP_VECE(op));
1999d2fd745fSRichard Henderson             }
2000d2fd745fSRichard Henderson 
2001c896fe29Sbellard             k = 0;
2002c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
2003eeacee4dSBlue Swirl                 if (k != 0) {
2004bdfb460eSRichard Henderson                     col += qemu_log(",");
2005eeacee4dSBlue Swirl                 }
200643439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2007efee3746SRichard Henderson                                                       op->args[k++]));
2008c896fe29Sbellard             }
2009c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
2010eeacee4dSBlue Swirl                 if (k != 0) {
2011bdfb460eSRichard Henderson                     col += qemu_log(",");
2012eeacee4dSBlue Swirl                 }
201343439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2014efee3746SRichard Henderson                                                       op->args[k++]));
2015c896fe29Sbellard             }
2016be210acbSRichard Henderson             switch (c) {
2017be210acbSRichard Henderson             case INDEX_op_brcond_i32:
2018ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
2019ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
2020be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
2021be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
2022ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
2023be210acbSRichard Henderson             case INDEX_op_setcond_i64:
2024ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
2025212be173SRichard Henderson             case INDEX_op_cmp_vec:
2026efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
2027efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
2028efee3746SRichard Henderson                     col += qemu_log(",%s", cond_name[op->args[k++]]);
2029eeacee4dSBlue Swirl                 } else {
2030efee3746SRichard Henderson                     col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]);
2031eeacee4dSBlue Swirl                 }
2032f48f3edeSblueswir1                 i = 1;
2033be210acbSRichard Henderson                 break;
2034f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
2035f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
2036f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
2037f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
203859227d5dSRichard Henderson                 {
2039efee3746SRichard Henderson                     TCGMemOpIdx oi = op->args[k++];
204059227d5dSRichard Henderson                     TCGMemOp op = get_memop(oi);
204159227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
204259227d5dSRichard Henderson 
204359c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
2044bdfb460eSRichard Henderson                         col += qemu_log(",$0x%x,%u", op, ix);
204559c4b7e8SRichard Henderson                     } else {
20461f00b27fSSergey Sorokin                         const char *s_al, *s_op;
20471f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
204859c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
2049bdfb460eSRichard Henderson                         col += qemu_log(",%s%s,%u", s_al, s_op, ix);
2050f713d6adSRichard Henderson                     }
2051f713d6adSRichard Henderson                     i = 1;
205259227d5dSRichard Henderson                 }
2053f713d6adSRichard Henderson                 break;
2054be210acbSRichard Henderson             default:
2055f48f3edeSblueswir1                 i = 0;
2056be210acbSRichard Henderson                 break;
2057be210acbSRichard Henderson             }
205851e3972cSRichard Henderson             switch (c) {
205951e3972cSRichard Henderson             case INDEX_op_set_label:
206051e3972cSRichard Henderson             case INDEX_op_br:
206151e3972cSRichard Henderson             case INDEX_op_brcond_i32:
206251e3972cSRichard Henderson             case INDEX_op_brcond_i64:
206351e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2064efee3746SRichard Henderson                 col += qemu_log("%s$L%d", k ? "," : "",
2065efee3746SRichard Henderson                                 arg_label(op->args[k])->id);
206651e3972cSRichard Henderson                 i++, k++;
206751e3972cSRichard Henderson                 break;
206851e3972cSRichard Henderson             default:
206951e3972cSRichard Henderson                 break;
2070eeacee4dSBlue Swirl             }
207151e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
2072efee3746SRichard Henderson                 col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]);
2073bdfb460eSRichard Henderson             }
2074bdfb460eSRichard Henderson         }
2075bdfb460eSRichard Henderson 
20761894f69aSRichard Henderson         if (have_prefs || op->life) {
20771894f69aSRichard Henderson             for (; col < 40; ++col) {
2078bdfb460eSRichard Henderson                 putc(' ', qemu_logfile);
2079bdfb460eSRichard Henderson             }
20801894f69aSRichard Henderson         }
20811894f69aSRichard Henderson 
20821894f69aSRichard Henderson         if (op->life) {
20831894f69aSRichard Henderson             unsigned life = op->life;
2084bdfb460eSRichard Henderson 
2085bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
2086bdfb460eSRichard Henderson                 qemu_log("  sync:");
2087bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
2088bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
2089bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2090bdfb460eSRichard Henderson                     }
2091bdfb460eSRichard Henderson                 }
2092bdfb460eSRichard Henderson             }
2093bdfb460eSRichard Henderson             life /= DEAD_ARG;
2094bdfb460eSRichard Henderson             if (life) {
2095bdfb460eSRichard Henderson                 qemu_log("  dead:");
2096bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
2097bdfb460eSRichard Henderson                     if (life & 1) {
2098bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2099bdfb460eSRichard Henderson                     }
2100bdfb460eSRichard Henderson                 }
2101c896fe29Sbellard             }
2102b03cce8eSbellard         }
21031894f69aSRichard Henderson 
21041894f69aSRichard Henderson         if (have_prefs) {
21051894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
21061894f69aSRichard Henderson                 TCGRegSet set = op->output_pref[i];
21071894f69aSRichard Henderson 
21081894f69aSRichard Henderson                 if (i == 0) {
21091894f69aSRichard Henderson                     qemu_log("  pref=");
21101894f69aSRichard Henderson                 } else {
21111894f69aSRichard Henderson                     qemu_log(",");
21121894f69aSRichard Henderson                 }
21131894f69aSRichard Henderson                 if (set == 0) {
21141894f69aSRichard Henderson                     qemu_log("none");
21151894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
21161894f69aSRichard Henderson                     qemu_log("all");
21171894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
21181894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
21191894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
21201894f69aSRichard Henderson                     qemu_log("%s", tcg_target_reg_names[reg]);
21211894f69aSRichard Henderson #endif
21221894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
21231894f69aSRichard Henderson                     qemu_log("%#x", (uint32_t)set);
21241894f69aSRichard Henderson                 } else {
21251894f69aSRichard Henderson                     qemu_log("%#" PRIx64, (uint64_t)set);
21261894f69aSRichard Henderson                 }
21271894f69aSRichard Henderson             }
21281894f69aSRichard Henderson         }
21291894f69aSRichard Henderson 
2130eeacee4dSBlue Swirl         qemu_log("\n");
2131c896fe29Sbellard     }
2132c896fe29Sbellard }
2133c896fe29Sbellard 
2134c896fe29Sbellard /* we give more priority to constraints with less registers */
2135c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2136c896fe29Sbellard {
2137c896fe29Sbellard     const TCGArgConstraint *arg_ct;
2138c896fe29Sbellard 
2139c896fe29Sbellard     int i, n;
2140c896fe29Sbellard     arg_ct = &def->args_ct[k];
2141c896fe29Sbellard     if (arg_ct->ct & TCG_CT_ALIAS) {
2142c896fe29Sbellard         /* an alias is equivalent to a single register */
2143c896fe29Sbellard         n = 1;
2144c896fe29Sbellard     } else {
2145c896fe29Sbellard         if (!(arg_ct->ct & TCG_CT_REG))
2146c896fe29Sbellard             return 0;
2147c896fe29Sbellard         n = 0;
2148c896fe29Sbellard         for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
2149c896fe29Sbellard             if (tcg_regset_test_reg(arg_ct->u.regs, i))
2150c896fe29Sbellard                 n++;
2151c896fe29Sbellard         }
2152c896fe29Sbellard     }
2153c896fe29Sbellard     return TCG_TARGET_NB_REGS - n + 1;
2154c896fe29Sbellard }
2155c896fe29Sbellard 
2156c896fe29Sbellard /* sort from highest priority to lowest */
2157c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2158c896fe29Sbellard {
2159c896fe29Sbellard     int i, j, p1, p2, tmp;
2160c896fe29Sbellard 
2161c896fe29Sbellard     for(i = 0; i < n; i++)
2162c896fe29Sbellard         def->sorted_args[start + i] = start + i;
2163c896fe29Sbellard     if (n <= 1)
2164c896fe29Sbellard         return;
2165c896fe29Sbellard     for(i = 0; i < n - 1; i++) {
2166c896fe29Sbellard         for(j = i + 1; j < n; j++) {
2167c896fe29Sbellard             p1 = get_constraint_priority(def, def->sorted_args[start + i]);
2168c896fe29Sbellard             p2 = get_constraint_priority(def, def->sorted_args[start + j]);
2169c896fe29Sbellard             if (p1 < p2) {
2170c896fe29Sbellard                 tmp = def->sorted_args[start + i];
2171c896fe29Sbellard                 def->sorted_args[start + i] = def->sorted_args[start + j];
2172c896fe29Sbellard                 def->sorted_args[start + j] = tmp;
2173c896fe29Sbellard             }
2174c896fe29Sbellard         }
2175c896fe29Sbellard     }
2176c896fe29Sbellard }
2177c896fe29Sbellard 
2178f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2179c896fe29Sbellard {
2180a9751609SRichard Henderson     TCGOpcode op;
2181c896fe29Sbellard 
2182f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
2183f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
2184f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
2185069ea736SRichard Henderson         TCGType type;
2186069ea736SRichard Henderson         int i, nb_args;
2187f69d277eSRichard Henderson 
2188f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
2189f69d277eSRichard Henderson             continue;
2190f69d277eSRichard Henderson         }
2191f69d277eSRichard Henderson 
2192c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
2193f69d277eSRichard Henderson         if (nb_args == 0) {
2194f69d277eSRichard Henderson             continue;
2195f69d277eSRichard Henderson         }
2196f69d277eSRichard Henderson 
2197f69d277eSRichard Henderson         tdefs = tcg_target_op_def(op);
2198f69d277eSRichard Henderson         /* Missing TCGTargetOpDef entry. */
2199f69d277eSRichard Henderson         tcg_debug_assert(tdefs != NULL);
2200f69d277eSRichard Henderson 
2201069ea736SRichard Henderson         type = (def->flags & TCG_OPF_64BIT ? TCG_TYPE_I64 : TCG_TYPE_I32);
2202c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2203f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
2204f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2205eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2206f69d277eSRichard Henderson 
2207ccb1bb66SRichard Henderson             def->args_ct[i].u.regs = 0;
2208c896fe29Sbellard             def->args_ct[i].ct = 0;
220917280ff4SRichard Henderson             while (*ct_str != '\0') {
221017280ff4SRichard Henderson                 switch(*ct_str) {
221117280ff4SRichard Henderson                 case '0' ... '9':
221217280ff4SRichard Henderson                     {
221317280ff4SRichard Henderson                         int oarg = *ct_str - '0';
221417280ff4SRichard Henderson                         tcg_debug_assert(ct_str == tdefs->args_ct_str[i]);
2215eabb7b91SAurelien Jarno                         tcg_debug_assert(oarg < def->nb_oargs);
2216eabb7b91SAurelien Jarno                         tcg_debug_assert(def->args_ct[oarg].ct & TCG_CT_REG);
221717280ff4SRichard Henderson                         /* TCG_CT_ALIAS is for the output arguments.
221817280ff4SRichard Henderson                            The input is tagged with TCG_CT_IALIAS. */
2219c896fe29Sbellard                         def->args_ct[i] = def->args_ct[oarg];
222017280ff4SRichard Henderson                         def->args_ct[oarg].ct |= TCG_CT_ALIAS;
22215ff9d6a4Sbellard                         def->args_ct[oarg].alias_index = i;
2222c896fe29Sbellard                         def->args_ct[i].ct |= TCG_CT_IALIAS;
22235ff9d6a4Sbellard                         def->args_ct[i].alias_index = oarg;
222417280ff4SRichard Henderson                     }
222517280ff4SRichard Henderson                     ct_str++;
2226c896fe29Sbellard                     break;
222782790a87SRichard Henderson                 case '&':
222882790a87SRichard Henderson                     def->args_ct[i].ct |= TCG_CT_NEWREG;
222982790a87SRichard Henderson                     ct_str++;
223082790a87SRichard Henderson                     break;
2231c896fe29Sbellard                 case 'i':
2232c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2233c896fe29Sbellard                     ct_str++;
2234c896fe29Sbellard                     break;
2235c896fe29Sbellard                 default:
2236069ea736SRichard Henderson                     ct_str = target_parse_constraint(&def->args_ct[i],
2237069ea736SRichard Henderson                                                      ct_str, type);
2238f69d277eSRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2239069ea736SRichard Henderson                     tcg_debug_assert(ct_str != NULL);
2240c896fe29Sbellard                 }
2241c896fe29Sbellard             }
2242c896fe29Sbellard         }
2243c896fe29Sbellard 
2244c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2245eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2246c68aaa18SStefan Weil 
2247c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
2248c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
2249c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
2250c896fe29Sbellard     }
2251c896fe29Sbellard }
2252c896fe29Sbellard 
22530c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
22540c627cdcSRichard Henderson {
2255d88a117eSRichard Henderson     TCGLabel *label;
2256d88a117eSRichard Henderson 
2257d88a117eSRichard Henderson     switch (op->opc) {
2258d88a117eSRichard Henderson     case INDEX_op_br:
2259d88a117eSRichard Henderson         label = arg_label(op->args[0]);
2260d88a117eSRichard Henderson         label->refs--;
2261d88a117eSRichard Henderson         break;
2262d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
2263d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
2264d88a117eSRichard Henderson         label = arg_label(op->args[3]);
2265d88a117eSRichard Henderson         label->refs--;
2266d88a117eSRichard Henderson         break;
2267d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
2268d88a117eSRichard Henderson         label = arg_label(op->args[5]);
2269d88a117eSRichard Henderson         label->refs--;
2270d88a117eSRichard Henderson         break;
2271d88a117eSRichard Henderson     default:
2272d88a117eSRichard Henderson         break;
2273d88a117eSRichard Henderson     }
2274d88a117eSRichard Henderson 
227515fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
227615fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
2277abebf925SRichard Henderson     s->nb_ops--;
22780c627cdcSRichard Henderson 
22790c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
2280c3fac113SEmilio G. Cota     atomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
22810c627cdcSRichard Henderson #endif
22820c627cdcSRichard Henderson }
22830c627cdcSRichard Henderson 
228415fa08f8SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc)
228515fa08f8SRichard Henderson {
228615fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
228715fa08f8SRichard Henderson     TCGOp *op;
228815fa08f8SRichard Henderson 
228915fa08f8SRichard Henderson     if (likely(QTAILQ_EMPTY(&s->free_ops))) {
229015fa08f8SRichard Henderson         op = tcg_malloc(sizeof(TCGOp));
229115fa08f8SRichard Henderson     } else {
229215fa08f8SRichard Henderson         op = QTAILQ_FIRST(&s->free_ops);
229315fa08f8SRichard Henderson         QTAILQ_REMOVE(&s->free_ops, op, link);
229415fa08f8SRichard Henderson     }
229515fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
229615fa08f8SRichard Henderson     op->opc = opc;
2297abebf925SRichard Henderson     s->nb_ops++;
229815fa08f8SRichard Henderson 
229915fa08f8SRichard Henderson     return op;
230015fa08f8SRichard Henderson }
230115fa08f8SRichard Henderson 
230215fa08f8SRichard Henderson TCGOp *tcg_emit_op(TCGOpcode opc)
230315fa08f8SRichard Henderson {
230415fa08f8SRichard Henderson     TCGOp *op = tcg_op_alloc(opc);
230515fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
230615fa08f8SRichard Henderson     return op;
230715fa08f8SRichard Henderson }
230815fa08f8SRichard Henderson 
2309ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
23105a18407fSRichard Henderson {
231115fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
231215fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
23135a18407fSRichard Henderson     return new_op;
23145a18407fSRichard Henderson }
23155a18407fSRichard Henderson 
2316ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
23175a18407fSRichard Henderson {
231815fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
231915fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
23205a18407fSRichard Henderson     return new_op;
23215a18407fSRichard Henderson }
23225a18407fSRichard Henderson 
2323b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
2324b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s)
2325b4fc67c7SRichard Henderson {
2326b4fc67c7SRichard Henderson     TCGOp *op, *op_next;
2327b4fc67c7SRichard Henderson     bool dead = false;
2328b4fc67c7SRichard Henderson 
2329b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
2330b4fc67c7SRichard Henderson         bool remove = dead;
2331b4fc67c7SRichard Henderson         TCGLabel *label;
2332b4fc67c7SRichard Henderson         int call_flags;
2333b4fc67c7SRichard Henderson 
2334b4fc67c7SRichard Henderson         switch (op->opc) {
2335b4fc67c7SRichard Henderson         case INDEX_op_set_label:
2336b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
2337b4fc67c7SRichard Henderson             if (label->refs == 0) {
2338b4fc67c7SRichard Henderson                 /*
2339b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
2340b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
2341b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
2342b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
2343b4fc67c7SRichard Henderson                  * little to be gained by iterating.
2344b4fc67c7SRichard Henderson                  */
2345b4fc67c7SRichard Henderson                 remove = true;
2346b4fc67c7SRichard Henderson             } else {
2347b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
2348b4fc67c7SRichard Henderson                 dead = false;
2349b4fc67c7SRichard Henderson                 remove = false;
2350b4fc67c7SRichard Henderson 
2351b4fc67c7SRichard Henderson                 /*
2352b4fc67c7SRichard Henderson                  * Optimization can fold conditional branches to unconditional.
2353b4fc67c7SRichard Henderson                  * If we find a label with one reference which is preceded by
2354b4fc67c7SRichard Henderson                  * an unconditional branch to it, remove both.  This needed to
2355b4fc67c7SRichard Henderson                  * wait until the dead code in between them was removed.
2356b4fc67c7SRichard Henderson                  */
2357b4fc67c7SRichard Henderson                 if (label->refs == 1) {
2358eae3eb3eSPaolo Bonzini                     TCGOp *op_prev = QTAILQ_PREV(op, link);
2359b4fc67c7SRichard Henderson                     if (op_prev->opc == INDEX_op_br &&
2360b4fc67c7SRichard Henderson                         label == arg_label(op_prev->args[0])) {
2361b4fc67c7SRichard Henderson                         tcg_op_remove(s, op_prev);
2362b4fc67c7SRichard Henderson                         remove = true;
2363b4fc67c7SRichard Henderson                     }
2364b4fc67c7SRichard Henderson                 }
2365b4fc67c7SRichard Henderson             }
2366b4fc67c7SRichard Henderson             break;
2367b4fc67c7SRichard Henderson 
2368b4fc67c7SRichard Henderson         case INDEX_op_br:
2369b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
2370b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
2371b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
2372b4fc67c7SRichard Henderson             dead = true;
2373b4fc67c7SRichard Henderson             break;
2374b4fc67c7SRichard Henderson 
2375b4fc67c7SRichard Henderson         case INDEX_op_call:
2376b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
2377b4fc67c7SRichard Henderson             call_flags = op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1];
2378b4fc67c7SRichard Henderson             if (call_flags & TCG_CALL_NO_RETURN) {
2379b4fc67c7SRichard Henderson                 dead = true;
2380b4fc67c7SRichard Henderson             }
2381b4fc67c7SRichard Henderson             break;
2382b4fc67c7SRichard Henderson 
2383b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
2384b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
2385b4fc67c7SRichard Henderson             remove = false;
2386b4fc67c7SRichard Henderson             break;
2387b4fc67c7SRichard Henderson 
2388b4fc67c7SRichard Henderson         default:
2389b4fc67c7SRichard Henderson             break;
2390b4fc67c7SRichard Henderson         }
2391b4fc67c7SRichard Henderson 
2392b4fc67c7SRichard Henderson         if (remove) {
2393b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
2394b4fc67c7SRichard Henderson         }
2395b4fc67c7SRichard Henderson     }
2396b4fc67c7SRichard Henderson }
2397b4fc67c7SRichard Henderson 
2398c70fbf0aSRichard Henderson #define TS_DEAD  1
2399c70fbf0aSRichard Henderson #define TS_MEM   2
2400c70fbf0aSRichard Henderson 
24015a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
24025a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
24035a18407fSRichard Henderson 
240425f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
240525f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
240625f49c5fSRichard Henderson {
240725f49c5fSRichard Henderson     return ts->state_ptr;
240825f49c5fSRichard Henderson }
240925f49c5fSRichard Henderson 
241025f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
241125f49c5fSRichard Henderson  * maximal regset for its type.
241225f49c5fSRichard Henderson  */
241325f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
241425f49c5fSRichard Henderson {
241525f49c5fSRichard Henderson     *la_temp_pref(ts)
241625f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
241725f49c5fSRichard Henderson }
241825f49c5fSRichard Henderson 
24199c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
24209c43b68dSAurelien Jarno    should be in memory. */
24212616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
2422c896fe29Sbellard {
2423b83eabeaSRichard Henderson     int i;
2424b83eabeaSRichard Henderson 
2425b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2426b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
242725f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2428b83eabeaSRichard Henderson     }
2429b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2430b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
243125f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2432b83eabeaSRichard Henderson     }
2433c896fe29Sbellard }
2434c896fe29Sbellard 
24359c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
24369c43b68dSAurelien Jarno    and local temps should be in memory. */
24372616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
2438641d5fbeSbellard {
2439b83eabeaSRichard Henderson     int i;
2440641d5fbeSbellard 
2441b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2442b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
244325f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2444c70fbf0aSRichard Henderson     }
2445b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2446b83eabeaSRichard Henderson         s->temps[i].state = (s->temps[i].temp_local
2447b83eabeaSRichard Henderson                              ? TS_DEAD | TS_MEM
2448b83eabeaSRichard Henderson                              : TS_DEAD);
244925f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2450641d5fbeSbellard     }
2451641d5fbeSbellard }
2452641d5fbeSbellard 
2453f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
2454f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
2455f65a061cSRichard Henderson {
2456f65a061cSRichard Henderson     int i;
2457f65a061cSRichard Henderson 
2458f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
245925f49c5fSRichard Henderson         int state = s->temps[i].state;
246025f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
246125f49c5fSRichard Henderson         if (state == TS_DEAD) {
246225f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
246325f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
246425f49c5fSRichard Henderson         }
2465f65a061cSRichard Henderson     }
2466f65a061cSRichard Henderson }
2467f65a061cSRichard Henderson 
2468f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
2469f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
2470f65a061cSRichard Henderson {
2471f65a061cSRichard Henderson     int i;
2472f65a061cSRichard Henderson 
2473f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
2474f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
247525f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
247625f49c5fSRichard Henderson     }
247725f49c5fSRichard Henderson }
247825f49c5fSRichard Henderson 
247925f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
248025f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
248125f49c5fSRichard Henderson {
248225f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
248325f49c5fSRichard Henderson     int i;
248425f49c5fSRichard Henderson 
248525f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
248625f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
248725f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
248825f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
248925f49c5fSRichard Henderson             TCGRegSet set = *pset;
249025f49c5fSRichard Henderson 
249125f49c5fSRichard Henderson             set &= mask;
249225f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
249325f49c5fSRichard Henderson             if (set == 0) {
249425f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
249525f49c5fSRichard Henderson             }
249625f49c5fSRichard Henderson             *pset = set;
249725f49c5fSRichard Henderson         }
2498f65a061cSRichard Henderson     }
2499f65a061cSRichard Henderson }
2500f65a061cSRichard Henderson 
2501a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
2502c896fe29Sbellard    given input arguments is dead. Instructions updating dead
2503c896fe29Sbellard    temporaries are removed. */
2504b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s)
2505c896fe29Sbellard {
2506c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
25072616c808SRichard Henderson     int nb_temps = s->nb_temps;
250815fa08f8SRichard Henderson     TCGOp *op, *op_prev;
250925f49c5fSRichard Henderson     TCGRegSet *prefs;
251025f49c5fSRichard Henderson     int i;
251125f49c5fSRichard Henderson 
251225f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
251325f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
251425f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
251525f49c5fSRichard Henderson     }
2516c896fe29Sbellard 
2517ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
25182616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
2519c896fe29Sbellard 
2520eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
252125f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
2522c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
2523c45cb8bbSRichard Henderson         bool have_opc_new2;
2524a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
252525f49c5fSRichard Henderson         TCGTemp *ts;
2526c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2527c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2528c45cb8bbSRichard Henderson 
2529c45cb8bbSRichard Henderson         switch (opc) {
2530c896fe29Sbellard         case INDEX_op_call:
2531c6e113f5Sbellard             {
2532c6e113f5Sbellard                 int call_flags;
253325f49c5fSRichard Henderson                 int nb_call_regs;
2534c6e113f5Sbellard 
2535cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
2536cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
2537efee3746SRichard Henderson                 call_flags = op->args[nb_oargs + nb_iargs + 1];
2538c6e113f5Sbellard 
2539c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
254078505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
2541c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
254225f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
254325f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
2544c6e113f5Sbellard                             goto do_not_remove_call;
2545c6e113f5Sbellard                         }
25469c43b68dSAurelien Jarno                     }
2547c45cb8bbSRichard Henderson                     goto do_remove;
2548152c35aaSRichard Henderson                 }
2549c6e113f5Sbellard             do_not_remove_call:
2550c896fe29Sbellard 
255125f49c5fSRichard Henderson                 /* Output args are dead.  */
2552c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
255325f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
255425f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
2555a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
25566b64b624SAurelien Jarno                     }
255725f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
2558a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
25599c43b68dSAurelien Jarno                     }
256025f49c5fSRichard Henderson                     ts->state = TS_DEAD;
256125f49c5fSRichard Henderson                     la_reset_pref(ts);
256225f49c5fSRichard Henderson 
256325f49c5fSRichard Henderson                     /* Not used -- it will be tcg_target_call_oarg_regs[i].  */
256425f49c5fSRichard Henderson                     op->output_pref[i] = 0;
2565c896fe29Sbellard                 }
2566c896fe29Sbellard 
256778505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
256878505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
2569f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
2570c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
2571f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
2572b9c18f56Saurel32                 }
2573c896fe29Sbellard 
257425f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
2575866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
257625f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
257725f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
2578a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
2579c896fe29Sbellard                     }
2580c896fe29Sbellard                 }
258125f49c5fSRichard Henderson 
258225f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
258325f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
258425f49c5fSRichard Henderson 
258525f49c5fSRichard Henderson                 nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
258625f49c5fSRichard Henderson 
258725f49c5fSRichard Henderson                 /* Input arguments are live for preceding opcodes.  */
258825f49c5fSRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
258925f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
259025f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
259125f49c5fSRichard Henderson                         /* For those arguments that die, and will be allocated
259225f49c5fSRichard Henderson                          * in registers, clear the register set for that arg,
259325f49c5fSRichard Henderson                          * to be filled in below.  For args that will be on
259425f49c5fSRichard Henderson                          * the stack, reset to any available reg.
259525f49c5fSRichard Henderson                          */
259625f49c5fSRichard Henderson                         *la_temp_pref(ts)
259725f49c5fSRichard Henderson                             = (i < nb_call_regs ? 0 :
259825f49c5fSRichard Henderson                                tcg_target_available_regs[ts->type]);
259925f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
260025f49c5fSRichard Henderson                     }
260125f49c5fSRichard Henderson                 }
260225f49c5fSRichard Henderson 
260325f49c5fSRichard Henderson                 /* For each input argument, add its input register to prefs.
260425f49c5fSRichard Henderson                    If a temp is used once, this produces a single set bit.  */
260525f49c5fSRichard Henderson                 for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) {
260625f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
260725f49c5fSRichard Henderson                     if (ts) {
260825f49c5fSRichard Henderson                         tcg_regset_set_reg(*la_temp_pref(ts),
260925f49c5fSRichard Henderson                                            tcg_target_call_iarg_regs[i]);
2610c70fbf0aSRichard Henderson                     }
2611c19f47bfSAurelien Jarno                 }
2612c6e113f5Sbellard             }
2613c896fe29Sbellard             break;
2614765b842aSRichard Henderson         case INDEX_op_insn_start:
2615c896fe29Sbellard             break;
26165ff9d6a4Sbellard         case INDEX_op_discard:
26175ff9d6a4Sbellard             /* mark the temporary as dead */
261825f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
261925f49c5fSRichard Henderson             ts->state = TS_DEAD;
262025f49c5fSRichard Henderson             la_reset_pref(ts);
26215ff9d6a4Sbellard             break;
26221305c451SRichard Henderson 
26231305c451SRichard Henderson         case INDEX_op_add2_i32:
2624c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
2625f1fae40cSRichard Henderson             goto do_addsub2;
26261305c451SRichard Henderson         case INDEX_op_sub2_i32:
2627c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
2628f1fae40cSRichard Henderson             goto do_addsub2;
2629f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
2630c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
2631f1fae40cSRichard Henderson             goto do_addsub2;
2632f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
2633c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
2634f1fae40cSRichard Henderson         do_addsub2:
26351305c451SRichard Henderson             nb_iargs = 4;
26361305c451SRichard Henderson             nb_oargs = 2;
26371305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
26381305c451SRichard Henderson                the low part.  The result can be optimized to a simple
26391305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
26401305c451SRichard Henderson                cpu mode is set to 32 bit.  */
2641b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2642b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
26431305c451SRichard Henderson                     goto do_remove;
26441305c451SRichard Henderson                 }
2645c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
2646c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
2647c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2648efee3746SRichard Henderson                 op->args[1] = op->args[2];
2649efee3746SRichard Henderson                 op->args[2] = op->args[4];
26501305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
26511305c451SRichard Henderson                 nb_iargs = 2;
26521305c451SRichard Henderson                 nb_oargs = 1;
26531305c451SRichard Henderson             }
26541305c451SRichard Henderson             goto do_not_remove;
26551305c451SRichard Henderson 
26561414968aSRichard Henderson         case INDEX_op_mulu2_i32:
2657c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2658c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
2659c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
266003271524SRichard Henderson             goto do_mul2;
2661f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
2662c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2663c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
2664c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
2665f1fae40cSRichard Henderson             goto do_mul2;
2666f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
2667c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2668c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
2669c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
267003271524SRichard Henderson             goto do_mul2;
2671f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
2672c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2673c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
2674c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
267503271524SRichard Henderson             goto do_mul2;
2676f1fae40cSRichard Henderson         do_mul2:
26771414968aSRichard Henderson             nb_iargs = 2;
26781414968aSRichard Henderson             nb_oargs = 2;
2679b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2680b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
268103271524SRichard Henderson                     /* Both parts of the operation are dead.  */
26821414968aSRichard Henderson                     goto do_remove;
26831414968aSRichard Henderson                 }
268403271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
2685c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2686efee3746SRichard Henderson                 op->args[1] = op->args[2];
2687efee3746SRichard Henderson                 op->args[2] = op->args[3];
2688b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
268903271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
2690c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
2691efee3746SRichard Henderson                 op->args[0] = op->args[1];
2692efee3746SRichard Henderson                 op->args[1] = op->args[2];
2693efee3746SRichard Henderson                 op->args[2] = op->args[3];
269403271524SRichard Henderson             } else {
269503271524SRichard Henderson                 goto do_not_remove;
269603271524SRichard Henderson             }
269703271524SRichard Henderson             /* Mark the single-word operation live.  */
26981414968aSRichard Henderson             nb_oargs = 1;
26991414968aSRichard Henderson             goto do_not_remove;
27001414968aSRichard Henderson 
2701c896fe29Sbellard         default:
27021305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
2703c896fe29Sbellard             nb_iargs = def->nb_iargs;
2704c896fe29Sbellard             nb_oargs = def->nb_oargs;
2705c896fe29Sbellard 
2706c896fe29Sbellard             /* Test if the operation can be removed because all
27075ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
27085ff9d6a4Sbellard                implies side effects */
27095ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
2710c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
2711b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
2712c896fe29Sbellard                         goto do_not_remove;
2713c896fe29Sbellard                     }
27149c43b68dSAurelien Jarno                 }
2715152c35aaSRichard Henderson                 goto do_remove;
2716152c35aaSRichard Henderson             }
2717152c35aaSRichard Henderson             goto do_not_remove;
2718152c35aaSRichard Henderson 
27191305c451SRichard Henderson         do_remove:
27200c627cdcSRichard Henderson             tcg_op_remove(s, op);
2721152c35aaSRichard Henderson             break;
2722152c35aaSRichard Henderson 
2723c896fe29Sbellard         do_not_remove:
2724c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
272525f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
272625f49c5fSRichard Henderson 
272725f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
272825f49c5fSRichard Henderson                 op->output_pref[i] = *la_temp_pref(ts);
272925f49c5fSRichard Henderson 
273025f49c5fSRichard Henderson                 /* Output args are dead.  */
273125f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2732a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
27336b64b624SAurelien Jarno                 }
273425f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
2735a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
27369c43b68dSAurelien Jarno                 }
273725f49c5fSRichard Henderson                 ts->state = TS_DEAD;
273825f49c5fSRichard Henderson                 la_reset_pref(ts);
2739c896fe29Sbellard             }
2740c896fe29Sbellard 
274125f49c5fSRichard Henderson             /* If end of basic block, update.  */
2742ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
2743ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
2744ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
27452616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
27463d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
2747f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
274825f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
274925f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
275025f49c5fSRichard Henderson                 }
2751c896fe29Sbellard             }
2752c896fe29Sbellard 
275325f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
2754866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
275525f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
275625f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2757a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
2758c896fe29Sbellard                 }
2759c19f47bfSAurelien Jarno             }
276025f49c5fSRichard Henderson 
276125f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
2762c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
276325f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
276425f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
276525f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
276625f49c5fSRichard Henderson                        all regs for the type.  */
276725f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
276825f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
276925f49c5fSRichard Henderson                 }
277025f49c5fSRichard Henderson             }
277125f49c5fSRichard Henderson 
277225f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
277325f49c5fSRichard Henderson             switch (opc) {
277425f49c5fSRichard Henderson             case INDEX_op_mov_i32:
277525f49c5fSRichard Henderson             case INDEX_op_mov_i64:
277625f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
277725f49c5fSRichard Henderson                    have proper constraints.  That said, special case
277825f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
277925f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
278025f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
278125f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
278225f49c5fSRichard Henderson                 }
278325f49c5fSRichard Henderson                 break;
278425f49c5fSRichard Henderson 
278525f49c5fSRichard Henderson             default:
278625f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
278725f49c5fSRichard Henderson                     const TCGArgConstraint *ct = &def->args_ct[i];
278825f49c5fSRichard Henderson                     TCGRegSet set, *pset;
278925f49c5fSRichard Henderson 
279025f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
279125f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
279225f49c5fSRichard Henderson                     set = *pset;
279325f49c5fSRichard Henderson 
279425f49c5fSRichard Henderson                     set &= ct->u.regs;
279525f49c5fSRichard Henderson                     if (ct->ct & TCG_CT_IALIAS) {
279625f49c5fSRichard Henderson                         set &= op->output_pref[ct->alias_index];
279725f49c5fSRichard Henderson                     }
279825f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
279925f49c5fSRichard Henderson                     if (set == 0) {
280025f49c5fSRichard Henderson                         set = ct->u.regs;
280125f49c5fSRichard Henderson                     }
280225f49c5fSRichard Henderson                     *pset = set;
280325f49c5fSRichard Henderson                 }
280425f49c5fSRichard Henderson                 break;
2805c896fe29Sbellard             }
2806c896fe29Sbellard             break;
2807c896fe29Sbellard         }
2808bee158cbSRichard Henderson         op->life = arg_life;
2809c896fe29Sbellard     }
28101ff0a2c5SEvgeny Voevodin }
2811c896fe29Sbellard 
28125a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
2813b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s)
28145a18407fSRichard Henderson {
28155a18407fSRichard Henderson     int nb_globals = s->nb_globals;
281615fa08f8SRichard Henderson     int nb_temps, i;
28175a18407fSRichard Henderson     bool changes = false;
281815fa08f8SRichard Henderson     TCGOp *op, *op_next;
28195a18407fSRichard Henderson 
28205a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
28215a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
28225a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
28235a18407fSRichard Henderson         if (its->indirect_reg) {
28245a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
28255a18407fSRichard Henderson             dts->type = its->type;
28265a18407fSRichard Henderson             dts->base_type = its->base_type;
2827b83eabeaSRichard Henderson             its->state_ptr = dts;
2828b83eabeaSRichard Henderson         } else {
2829b83eabeaSRichard Henderson             its->state_ptr = NULL;
28305a18407fSRichard Henderson         }
2831b83eabeaSRichard Henderson         /* All globals begin dead.  */
2832b83eabeaSRichard Henderson         its->state = TS_DEAD;
28335a18407fSRichard Henderson     }
2834b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
2835b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
2836b83eabeaSRichard Henderson         its->state_ptr = NULL;
2837b83eabeaSRichard Henderson         its->state = TS_DEAD;
2838b83eabeaSRichard Henderson     }
28395a18407fSRichard Henderson 
284015fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
28415a18407fSRichard Henderson         TCGOpcode opc = op->opc;
28425a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
28435a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
28445a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
2845b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
28465a18407fSRichard Henderson 
28475a18407fSRichard Henderson         if (opc == INDEX_op_call) {
2848cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2849cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2850efee3746SRichard Henderson             call_flags = op->args[nb_oargs + nb_iargs + 1];
28515a18407fSRichard Henderson         } else {
28525a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
28535a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
28545a18407fSRichard Henderson 
28555a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
28565a18407fSRichard Henderson             if (def->flags & TCG_OPF_BB_END) {
28575a18407fSRichard Henderson                 /* Like writing globals: save_globals */
28585a18407fSRichard Henderson                 call_flags = 0;
28595a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
28605a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
28615a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
28625a18407fSRichard Henderson             } else {
28635a18407fSRichard Henderson                 /* No effect on globals.  */
28645a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
28655a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
28665a18407fSRichard Henderson             }
28675a18407fSRichard Henderson         }
28685a18407fSRichard Henderson 
28695a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
28705a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2871b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2872b83eabeaSRichard Henderson             if (arg_ts) {
2873b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
2874b83eabeaSRichard Henderson                 if (dir_ts && arg_ts->state == TS_DEAD) {
2875b83eabeaSRichard Henderson                     TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
28765a18407fSRichard Henderson                                       ? INDEX_op_ld_i32
28775a18407fSRichard Henderson                                       : INDEX_op_ld_i64);
2878ac1043f6SEmilio G. Cota                     TCGOp *lop = tcg_op_insert_before(s, op, lopc);
28795a18407fSRichard Henderson 
2880b83eabeaSRichard Henderson                     lop->args[0] = temp_arg(dir_ts);
2881b83eabeaSRichard Henderson                     lop->args[1] = temp_arg(arg_ts->mem_base);
2882b83eabeaSRichard Henderson                     lop->args[2] = arg_ts->mem_offset;
28835a18407fSRichard Henderson 
28845a18407fSRichard Henderson                     /* Loaded, but synced with memory.  */
2885b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
28865a18407fSRichard Henderson                 }
28875a18407fSRichard Henderson             }
28885a18407fSRichard Henderson         }
28895a18407fSRichard Henderson 
28905a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
28915a18407fSRichard Henderson            No action is required except keeping temp_state up to date
28925a18407fSRichard Henderson            so that we reload when needed.  */
28935a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2894b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2895b83eabeaSRichard Henderson             if (arg_ts) {
2896b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
2897b83eabeaSRichard Henderson                 if (dir_ts) {
2898b83eabeaSRichard Henderson                     op->args[i] = temp_arg(dir_ts);
28995a18407fSRichard Henderson                     changes = true;
29005a18407fSRichard Henderson                     if (IS_DEAD_ARG(i)) {
2901b83eabeaSRichard Henderson                         arg_ts->state = TS_DEAD;
29025a18407fSRichard Henderson                     }
29035a18407fSRichard Henderson                 }
29045a18407fSRichard Henderson             }
29055a18407fSRichard Henderson         }
29065a18407fSRichard Henderson 
29075a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
29085a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
29095a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
29105a18407fSRichard Henderson             /* Nothing to do */
29115a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
29125a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
29135a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
29145a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
2915b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
2916b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
2917b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
29185a18407fSRichard Henderson             }
29195a18407fSRichard Henderson         } else {
29205a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
29215a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
29225a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
2923b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
2924b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
2925b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
29265a18407fSRichard Henderson             }
29275a18407fSRichard Henderson         }
29285a18407fSRichard Henderson 
29295a18407fSRichard Henderson         /* Outputs become available.  */
29305a18407fSRichard Henderson         for (i = 0; i < nb_oargs; i++) {
2931b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2932b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
2933b83eabeaSRichard Henderson             if (!dir_ts) {
29345a18407fSRichard Henderson                 continue;
29355a18407fSRichard Henderson             }
2936b83eabeaSRichard Henderson             op->args[i] = temp_arg(dir_ts);
29375a18407fSRichard Henderson             changes = true;
29385a18407fSRichard Henderson 
29395a18407fSRichard Henderson             /* The output is now live and modified.  */
2940b83eabeaSRichard Henderson             arg_ts->state = 0;
29415a18407fSRichard Henderson 
29425a18407fSRichard Henderson             /* Sync outputs upon their last write.  */
29435a18407fSRichard Henderson             if (NEED_SYNC_ARG(i)) {
2944b83eabeaSRichard Henderson                 TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
29455a18407fSRichard Henderson                                   ? INDEX_op_st_i32
29465a18407fSRichard Henderson                                   : INDEX_op_st_i64);
2947ac1043f6SEmilio G. Cota                 TCGOp *sop = tcg_op_insert_after(s, op, sopc);
29485a18407fSRichard Henderson 
2949b83eabeaSRichard Henderson                 sop->args[0] = temp_arg(dir_ts);
2950b83eabeaSRichard Henderson                 sop->args[1] = temp_arg(arg_ts->mem_base);
2951b83eabeaSRichard Henderson                 sop->args[2] = arg_ts->mem_offset;
29525a18407fSRichard Henderson 
2953b83eabeaSRichard Henderson                 arg_ts->state = TS_MEM;
29545a18407fSRichard Henderson             }
29555a18407fSRichard Henderson             /* Drop outputs that are dead.  */
29565a18407fSRichard Henderson             if (IS_DEAD_ARG(i)) {
2957b83eabeaSRichard Henderson                 arg_ts->state = TS_DEAD;
29585a18407fSRichard Henderson             }
29595a18407fSRichard Henderson         }
29605a18407fSRichard Henderson     }
29615a18407fSRichard Henderson 
29625a18407fSRichard Henderson     return changes;
29635a18407fSRichard Henderson }
29645a18407fSRichard Henderson 
29658d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
2966c896fe29Sbellard static void dump_regs(TCGContext *s)
2967c896fe29Sbellard {
2968c896fe29Sbellard     TCGTemp *ts;
2969c896fe29Sbellard     int i;
2970c896fe29Sbellard     char buf[64];
2971c896fe29Sbellard 
2972c896fe29Sbellard     for(i = 0; i < s->nb_temps; i++) {
2973c896fe29Sbellard         ts = &s->temps[i];
297443439139SRichard Henderson         printf("  %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
2975c896fe29Sbellard         switch(ts->val_type) {
2976c896fe29Sbellard         case TEMP_VAL_REG:
2977c896fe29Sbellard             printf("%s", tcg_target_reg_names[ts->reg]);
2978c896fe29Sbellard             break;
2979c896fe29Sbellard         case TEMP_VAL_MEM:
2980b3a62939SRichard Henderson             printf("%d(%s)", (int)ts->mem_offset,
2981b3a62939SRichard Henderson                    tcg_target_reg_names[ts->mem_base->reg]);
2982c896fe29Sbellard             break;
2983c896fe29Sbellard         case TEMP_VAL_CONST:
2984c896fe29Sbellard             printf("$0x%" TCG_PRIlx, ts->val);
2985c896fe29Sbellard             break;
2986c896fe29Sbellard         case TEMP_VAL_DEAD:
2987c896fe29Sbellard             printf("D");
2988c896fe29Sbellard             break;
2989c896fe29Sbellard         default:
2990c896fe29Sbellard             printf("???");
2991c896fe29Sbellard             break;
2992c896fe29Sbellard         }
2993c896fe29Sbellard         printf("\n");
2994c896fe29Sbellard     }
2995c896fe29Sbellard 
2996c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
2997f8b2f202SRichard Henderson         if (s->reg_to_temp[i] != NULL) {
2998c896fe29Sbellard             printf("%s: %s\n",
2999c896fe29Sbellard                    tcg_target_reg_names[i],
3000f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i]));
3001c896fe29Sbellard         }
3002c896fe29Sbellard     }
3003c896fe29Sbellard }
3004c896fe29Sbellard 
3005c896fe29Sbellard static void check_regs(TCGContext *s)
3006c896fe29Sbellard {
3007869938aeSRichard Henderson     int reg;
3008b6638662SRichard Henderson     int k;
3009c896fe29Sbellard     TCGTemp *ts;
3010c896fe29Sbellard     char buf[64];
3011c896fe29Sbellard 
3012c896fe29Sbellard     for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
3013f8b2f202SRichard Henderson         ts = s->reg_to_temp[reg];
3014f8b2f202SRichard Henderson         if (ts != NULL) {
3015f8b2f202SRichard Henderson             if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) {
3016c896fe29Sbellard                 printf("Inconsistency for register %s:\n",
3017c896fe29Sbellard                        tcg_target_reg_names[reg]);
3018b03cce8eSbellard                 goto fail;
3019c896fe29Sbellard             }
3020c896fe29Sbellard         }
3021c896fe29Sbellard     }
3022c896fe29Sbellard     for (k = 0; k < s->nb_temps; k++) {
3023c896fe29Sbellard         ts = &s->temps[k];
3024f8b2f202SRichard Henderson         if (ts->val_type == TEMP_VAL_REG && !ts->fixed_reg
3025f8b2f202SRichard Henderson             && s->reg_to_temp[ts->reg] != ts) {
3026c896fe29Sbellard             printf("Inconsistency for temp %s:\n",
3027f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3028b03cce8eSbellard         fail:
3029c896fe29Sbellard             printf("reg state:\n");
3030c896fe29Sbellard             dump_regs(s);
3031c896fe29Sbellard             tcg_abort();
3032c896fe29Sbellard         }
3033c896fe29Sbellard     }
3034c896fe29Sbellard }
3035c896fe29Sbellard #endif
3036c896fe29Sbellard 
30372272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
3038c896fe29Sbellard {
30399b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64)
30409b9c37c3SRichard Henderson     /* Sparc64 stack is accessed with offset of 2047 */
3041b591dc59SBlue Swirl     s->current_frame_offset = (s->current_frame_offset +
3042b591dc59SBlue Swirl                                (tcg_target_long)sizeof(tcg_target_long) - 1) &
3043b591dc59SBlue Swirl         ~(sizeof(tcg_target_long) - 1);
3044f44c9960SBlue Swirl #endif
3045b591dc59SBlue Swirl     if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
3046b591dc59SBlue Swirl         s->frame_end) {
30475ff9d6a4Sbellard         tcg_abort();
3048b591dc59SBlue Swirl     }
3049c896fe29Sbellard     ts->mem_offset = s->current_frame_offset;
3050b3a62939SRichard Henderson     ts->mem_base = s->frame_temp;
3051c896fe29Sbellard     ts->mem_allocated = 1;
3052e2c6d1b4SRichard Henderson     s->current_frame_offset += sizeof(tcg_target_long);
3053c896fe29Sbellard }
3054c896fe29Sbellard 
3055b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
3056b3915dbbSRichard Henderson 
305759d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
305859d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
305959d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
3060c896fe29Sbellard {
306159d7c14eSRichard Henderson     if (ts->fixed_reg) {
306259d7c14eSRichard Henderson         return;
306359d7c14eSRichard Henderson     }
306459d7c14eSRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
306559d7c14eSRichard Henderson         s->reg_to_temp[ts->reg] = NULL;
306659d7c14eSRichard Henderson     }
306759d7c14eSRichard Henderson     ts->val_type = (free_or_dead < 0
306859d7c14eSRichard Henderson                     || ts->temp_local
3069fa477d25SRichard Henderson                     || ts->temp_global
307059d7c14eSRichard Henderson                     ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
307159d7c14eSRichard Henderson }
3072c896fe29Sbellard 
307359d7c14eSRichard Henderson /* Mark a temporary as dead.  */
307459d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
307559d7c14eSRichard Henderson {
307659d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
307759d7c14eSRichard Henderson }
307859d7c14eSRichard Henderson 
307959d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
308059d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
308159d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
308259d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
308398b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
308498b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
308559d7c14eSRichard Henderson {
308659d7c14eSRichard Henderson     if (ts->fixed_reg) {
308759d7c14eSRichard Henderson         return;
308859d7c14eSRichard Henderson     }
308959d7c14eSRichard Henderson     if (!ts->mem_coherent) {
30907f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
30912272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
309259d7c14eSRichard Henderson         }
309359d7c14eSRichard Henderson         switch (ts->val_type) {
309459d7c14eSRichard Henderson         case TEMP_VAL_CONST:
309559d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
309659d7c14eSRichard Henderson                require it later in a register, so attempt to store the
309759d7c14eSRichard Henderson                constant to memory directly.  */
309859d7c14eSRichard Henderson             if (free_or_dead
309959d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
310059d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
310159d7c14eSRichard Henderson                 break;
310259d7c14eSRichard Henderson             }
310359d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
310498b4e186SRichard Henderson                       allocated_regs, preferred_regs);
310559d7c14eSRichard Henderson             /* fallthrough */
310659d7c14eSRichard Henderson 
310759d7c14eSRichard Henderson         case TEMP_VAL_REG:
310859d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
310959d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
311059d7c14eSRichard Henderson             break;
311159d7c14eSRichard Henderson 
311259d7c14eSRichard Henderson         case TEMP_VAL_MEM:
311359d7c14eSRichard Henderson             break;
311459d7c14eSRichard Henderson 
311559d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
311659d7c14eSRichard Henderson         default:
311759d7c14eSRichard Henderson             tcg_abort();
3118c896fe29Sbellard         }
31197f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
31207f6ceedfSAurelien Jarno     }
312159d7c14eSRichard Henderson     if (free_or_dead) {
312259d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
312359d7c14eSRichard Henderson     }
312459d7c14eSRichard Henderson }
31257f6ceedfSAurelien Jarno 
31267f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
3127b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
31287f6ceedfSAurelien Jarno {
3129f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
3130f8b2f202SRichard Henderson     if (ts != NULL) {
313198b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
3132c896fe29Sbellard     }
3133c896fe29Sbellard }
3134c896fe29Sbellard 
3135b016486eSRichard Henderson /**
3136b016486eSRichard Henderson  * tcg_reg_alloc:
3137b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
3138b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
3139b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
3140b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
3141b016486eSRichard Henderson  *
3142b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
3143b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
3144b016486eSRichard Henderson  */
3145b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
3146b016486eSRichard Henderson                             TCGRegSet allocated_regs,
3147b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
3148c896fe29Sbellard {
3149b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
3150b016486eSRichard Henderson     TCGRegSet reg_ct[2];
315191478cefSRichard Henderson     const int *order;
3152c896fe29Sbellard 
3153b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
3154b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
3155b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
3156b016486eSRichard Henderson 
3157b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
3158b016486eSRichard Henderson        or if the preference made no difference.  */
3159b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
3160b016486eSRichard Henderson 
316191478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
3162c896fe29Sbellard 
3163b016486eSRichard Henderson     /* Try free registers, preferences first.  */
3164b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3165b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3166b016486eSRichard Henderson 
3167b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3168b016486eSRichard Henderson             /* One register in the set.  */
3169b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3170b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
3171c896fe29Sbellard                 return reg;
3172c896fe29Sbellard             }
3173b016486eSRichard Henderson         } else {
317491478cefSRichard Henderson             for (i = 0; i < n; i++) {
3175b016486eSRichard Henderson                 TCGReg reg = order[i];
3176b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
3177b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
3178b016486eSRichard Henderson                     return reg;
3179b016486eSRichard Henderson                 }
3180b016486eSRichard Henderson             }
3181b016486eSRichard Henderson         }
3182b016486eSRichard Henderson     }
3183b016486eSRichard Henderson 
3184b016486eSRichard Henderson     /* We must spill something.  */
3185b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3186b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3187b016486eSRichard Henderson 
3188b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3189b016486eSRichard Henderson             /* One register in the set.  */
3190b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3191b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
3192c896fe29Sbellard             return reg;
3193b016486eSRichard Henderson         } else {
3194b016486eSRichard Henderson             for (i = 0; i < n; i++) {
3195b016486eSRichard Henderson                 TCGReg reg = order[i];
3196b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
3197b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
3198b016486eSRichard Henderson                     return reg;
3199b016486eSRichard Henderson                 }
3200b016486eSRichard Henderson             }
3201c896fe29Sbellard         }
3202c896fe29Sbellard     }
3203c896fe29Sbellard 
3204c896fe29Sbellard     tcg_abort();
3205c896fe29Sbellard }
3206c896fe29Sbellard 
320740ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
320840ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
320940ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
3210b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
321140ae5c62SRichard Henderson {
321240ae5c62SRichard Henderson     TCGReg reg;
321340ae5c62SRichard Henderson 
321440ae5c62SRichard Henderson     switch (ts->val_type) {
321540ae5c62SRichard Henderson     case TEMP_VAL_REG:
321640ae5c62SRichard Henderson         return;
321740ae5c62SRichard Henderson     case TEMP_VAL_CONST:
3218b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3219b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
322040ae5c62SRichard Henderson         tcg_out_movi(s, ts->type, reg, ts->val);
322140ae5c62SRichard Henderson         ts->mem_coherent = 0;
322240ae5c62SRichard Henderson         break;
322340ae5c62SRichard Henderson     case TEMP_VAL_MEM:
3224b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3225b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
322640ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
322740ae5c62SRichard Henderson         ts->mem_coherent = 1;
322840ae5c62SRichard Henderson         break;
322940ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
323040ae5c62SRichard Henderson     default:
323140ae5c62SRichard Henderson         tcg_abort();
323240ae5c62SRichard Henderson     }
323340ae5c62SRichard Henderson     ts->reg = reg;
323440ae5c62SRichard Henderson     ts->val_type = TEMP_VAL_REG;
323540ae5c62SRichard Henderson     s->reg_to_temp[reg] = ts;
323640ae5c62SRichard Henderson }
323740ae5c62SRichard Henderson 
323859d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
3239e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
324059d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
32411ad80729SAurelien Jarno {
32422c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
3243eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
3244f8bf00f1SRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg);
32451ad80729SAurelien Jarno }
32461ad80729SAurelien Jarno 
32479814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
3248641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
3249641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
3250641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
3251641d5fbeSbellard {
3252ac3b8891SRichard Henderson     int i, n;
3253641d5fbeSbellard 
3254ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
3255b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
3256641d5fbeSbellard     }
3257e5097dc8Sbellard }
3258e5097dc8Sbellard 
32593d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
32603d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
32613d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
32623d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
32633d5c5f87SAurelien Jarno {
3264ac3b8891SRichard Henderson     int i, n;
32653d5c5f87SAurelien Jarno 
3266ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
326712b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
326812b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
326912b9b11aSRichard Henderson                          || ts->fixed_reg
327012b9b11aSRichard Henderson                          || ts->mem_coherent);
32713d5c5f87SAurelien Jarno     }
32723d5c5f87SAurelien Jarno }
32733d5c5f87SAurelien Jarno 
3274e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
3275e8996ee0Sbellard    all globals are stored at their canonical location. */
3276e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
3277e5097dc8Sbellard {
3278e5097dc8Sbellard     int i;
3279e5097dc8Sbellard 
3280c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
3281b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
3282641d5fbeSbellard         if (ts->temp_local) {
3283b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
3284641d5fbeSbellard         } else {
32852c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
3286eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
3287eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3288c896fe29Sbellard         }
3289641d5fbeSbellard     }
3290e8996ee0Sbellard 
3291e8996ee0Sbellard     save_globals(s, allocated_regs);
3292c896fe29Sbellard }
3293c896fe29Sbellard 
3294bab1671fSRichard Henderson /*
3295bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_movi_*.
3296bab1671fSRichard Henderson  */
32970fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
3298ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
3299ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
3300e8996ee0Sbellard {
3301d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3302d63e3b6eSRichard Henderson     tcg_debug_assert(!ots->fixed_reg);
330359d7c14eSRichard Henderson 
330459d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
3305f8b2f202SRichard Henderson     if (ots->val_type == TEMP_VAL_REG) {
3306f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = NULL;
3307f8b2f202SRichard Henderson     }
3308e8996ee0Sbellard     ots->val_type = TEMP_VAL_CONST;
3309e8996ee0Sbellard     ots->val = val;
331059d7c14eSRichard Henderson     ots->mem_coherent = 0;
3311ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
3312ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
331359d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
3314f8bf00f1SRichard Henderson         temp_dead(s, ots);
33154c4e1ab2SAurelien Jarno     }
3316e8996ee0Sbellard }
3317e8996ee0Sbellard 
3318dd186292SRichard Henderson static void tcg_reg_alloc_movi(TCGContext *s, const TCGOp *op)
33190fe4fca4SPaolo Bonzini {
332043439139SRichard Henderson     TCGTemp *ots = arg_temp(op->args[0]);
3321dd186292SRichard Henderson     tcg_target_ulong val = op->args[1];
33220fe4fca4SPaolo Bonzini 
332369e3706dSRichard Henderson     tcg_reg_alloc_do_movi(s, ots, val, op->life, op->output_pref[0]);
33240fe4fca4SPaolo Bonzini }
33250fe4fca4SPaolo Bonzini 
3326bab1671fSRichard Henderson /*
3327bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
3328bab1671fSRichard Henderson  */
3329dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
3330c896fe29Sbellard {
3331dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
333269e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
3333c896fe29Sbellard     TCGTemp *ts, *ots;
3334450445d5SRichard Henderson     TCGType otype, itype;
3335c896fe29Sbellard 
3336d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
333769e3706dSRichard Henderson     preferred_regs = op->output_pref[0];
333843439139SRichard Henderson     ots = arg_temp(op->args[0]);
333943439139SRichard Henderson     ts = arg_temp(op->args[1]);
3340450445d5SRichard Henderson 
3341d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3342d63e3b6eSRichard Henderson     tcg_debug_assert(!ots->fixed_reg);
3343d63e3b6eSRichard Henderson 
3344450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
3345450445d5SRichard Henderson     otype = ots->type;
3346450445d5SRichard Henderson     itype = ts->type;
3347c896fe29Sbellard 
33480fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
33490fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
33500fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
33510fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
33520fe4fca4SPaolo Bonzini             temp_dead(s, ts);
33530fe4fca4SPaolo Bonzini         }
335469e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
33550fe4fca4SPaolo Bonzini         return;
33560fe4fca4SPaolo Bonzini     }
33570fe4fca4SPaolo Bonzini 
33580fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
33590fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
33600fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
33610fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
33620fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
336369e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
336469e3706dSRichard Henderson                   allocated_regs, preferred_regs);
3365c29c1d7eSAurelien Jarno     }
3366c29c1d7eSAurelien Jarno 
33670fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
3368d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
3369c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
3370c29c1d7eSAurelien Jarno            liveness analysis disabled). */
3371eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
3372c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
33732272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
3374c29c1d7eSAurelien Jarno         }
3375b3a62939SRichard Henderson         tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset);
3376c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
3377f8bf00f1SRichard Henderson             temp_dead(s, ts);
3378c29c1d7eSAurelien Jarno         }
3379f8bf00f1SRichard Henderson         temp_dead(s, ots);
3380e8996ee0Sbellard     } else {
3381d63e3b6eSRichard Henderson         if (IS_DEAD_ARG(1) && !ts->fixed_reg) {
3382c29c1d7eSAurelien Jarno             /* the mov can be suppressed */
3383c29c1d7eSAurelien Jarno             if (ots->val_type == TEMP_VAL_REG) {
3384f8b2f202SRichard Henderson                 s->reg_to_temp[ots->reg] = NULL;
3385c896fe29Sbellard             }
3386c29c1d7eSAurelien Jarno             ots->reg = ts->reg;
3387f8bf00f1SRichard Henderson             temp_dead(s, ts);
3388c29c1d7eSAurelien Jarno         } else {
3389c29c1d7eSAurelien Jarno             if (ots->val_type != TEMP_VAL_REG) {
3390c29c1d7eSAurelien Jarno                 /* When allocating a new register, make sure to not spill the
3391c29c1d7eSAurelien Jarno                    input one. */
3392c29c1d7eSAurelien Jarno                 tcg_regset_set_reg(allocated_regs, ts->reg);
3393450445d5SRichard Henderson                 ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
339469e3706dSRichard Henderson                                          allocated_regs, preferred_regs,
3395b016486eSRichard Henderson                                          ots->indirect_base);
3396c29c1d7eSAurelien Jarno             }
339778113e83SRichard Henderson             if (!tcg_out_mov(s, otype, ots->reg, ts->reg)) {
3398240c08d0SRichard Henderson                 /*
3399240c08d0SRichard Henderson                  * Cross register class move not supported.
3400240c08d0SRichard Henderson                  * Store the source register into the destination slot
3401240c08d0SRichard Henderson                  * and leave the destination temp as TEMP_VAL_MEM.
3402240c08d0SRichard Henderson                  */
3403240c08d0SRichard Henderson                 assert(!ots->fixed_reg);
3404240c08d0SRichard Henderson                 if (!ts->mem_allocated) {
3405240c08d0SRichard Henderson                     temp_allocate_frame(s, ots);
3406240c08d0SRichard Henderson                 }
3407240c08d0SRichard Henderson                 tcg_out_st(s, ts->type, ts->reg,
3408240c08d0SRichard Henderson                            ots->mem_base->reg, ots->mem_offset);
3409240c08d0SRichard Henderson                 ots->mem_coherent = 1;
3410240c08d0SRichard Henderson                 temp_free_or_dead(s, ots, -1);
3411240c08d0SRichard Henderson                 return;
341278113e83SRichard Henderson             }
3413c29c1d7eSAurelien Jarno         }
3414c896fe29Sbellard         ots->val_type = TEMP_VAL_REG;
3415c896fe29Sbellard         ots->mem_coherent = 0;
3416f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3417ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(0)) {
341898b4e186SRichard Henderson             temp_sync(s, ots, allocated_regs, 0, 0);
3419c29c1d7eSAurelien Jarno         }
3420ec7a869dSAurelien Jarno     }
3421c896fe29Sbellard }
3422c896fe29Sbellard 
3423bab1671fSRichard Henderson /*
3424bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
3425bab1671fSRichard Henderson  */
3426bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
3427bab1671fSRichard Henderson {
3428bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
3429bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
3430bab1671fSRichard Henderson     TCGTemp *its, *ots;
3431bab1671fSRichard Henderson     TCGType itype, vtype;
3432*d6ecb4a9SRichard Henderson     intptr_t endian_fixup;
3433bab1671fSRichard Henderson     unsigned vece;
3434bab1671fSRichard Henderson     bool ok;
3435bab1671fSRichard Henderson 
3436bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
3437bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
3438bab1671fSRichard Henderson 
3439bab1671fSRichard Henderson     /* ENV should not be modified.  */
3440bab1671fSRichard Henderson     tcg_debug_assert(!ots->fixed_reg);
3441bab1671fSRichard Henderson 
3442bab1671fSRichard Henderson     itype = its->type;
3443bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
3444bab1671fSRichard Henderson     vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
3445bab1671fSRichard Henderson 
3446bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
3447bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
3448bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
3449bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
3450bab1671fSRichard Henderson             temp_dead(s, its);
3451bab1671fSRichard Henderson         }
3452bab1671fSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, op->output_pref[0]);
3453bab1671fSRichard Henderson         return;
3454bab1671fSRichard Henderson     }
3455bab1671fSRichard Henderson 
3456bab1671fSRichard Henderson     dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].u.regs;
3457bab1671fSRichard Henderson     dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].u.regs;
3458bab1671fSRichard Henderson 
3459bab1671fSRichard Henderson     /* Allocate the output register now.  */
3460bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
3461bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
3462bab1671fSRichard Henderson 
3463bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
3464bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
3465bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
3466bab1671fSRichard Henderson         }
3467bab1671fSRichard Henderson         ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
3468bab1671fSRichard Henderson                                  op->output_pref[0], ots->indirect_base);
3469bab1671fSRichard Henderson         ots->val_type = TEMP_VAL_REG;
3470bab1671fSRichard Henderson         ots->mem_coherent = 0;
3471bab1671fSRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3472bab1671fSRichard Henderson     }
3473bab1671fSRichard Henderson 
3474bab1671fSRichard Henderson     switch (its->val_type) {
3475bab1671fSRichard Henderson     case TEMP_VAL_REG:
3476bab1671fSRichard Henderson         /*
3477bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
3478bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
3479bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
3480bab1671fSRichard Henderson          */
3481bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
3482bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
3483bab1671fSRichard Henderson                 goto done;
3484bab1671fSRichard Henderson             }
3485bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
3486bab1671fSRichard Henderson         }
3487bab1671fSRichard Henderson         if (!its->mem_coherent) {
3488bab1671fSRichard Henderson             /*
3489bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
3490bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
3491bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
3492bab1671fSRichard Henderson              */
3493bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
3494bab1671fSRichard Henderson                 break;
3495bab1671fSRichard Henderson             }
3496bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
3497bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
3498bab1671fSRichard Henderson         }
3499bab1671fSRichard Henderson         /* fall through */
3500bab1671fSRichard Henderson 
3501bab1671fSRichard Henderson     case TEMP_VAL_MEM:
3502*d6ecb4a9SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
3503*d6ecb4a9SRichard Henderson         endian_fixup = itype == TCG_TYPE_I32 ? 4 : 8;
3504*d6ecb4a9SRichard Henderson         endian_fixup -= 1 << vece;
3505*d6ecb4a9SRichard Henderson #else
3506*d6ecb4a9SRichard Henderson         endian_fixup = 0;
3507*d6ecb4a9SRichard Henderson #endif
3508*d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
3509*d6ecb4a9SRichard Henderson                              its->mem_offset + endian_fixup)) {
3510*d6ecb4a9SRichard Henderson             goto done;
3511*d6ecb4a9SRichard Henderson         }
3512bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
3513bab1671fSRichard Henderson         break;
3514bab1671fSRichard Henderson 
3515bab1671fSRichard Henderson     default:
3516bab1671fSRichard Henderson         g_assert_not_reached();
3517bab1671fSRichard Henderson     }
3518bab1671fSRichard Henderson 
3519bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
3520bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
3521bab1671fSRichard Henderson     tcg_debug_assert(ok);
3522bab1671fSRichard Henderson 
3523bab1671fSRichard Henderson  done:
3524bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
3525bab1671fSRichard Henderson         temp_dead(s, its);
3526bab1671fSRichard Henderson     }
3527bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
3528bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
3529bab1671fSRichard Henderson     }
3530bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
3531bab1671fSRichard Henderson         temp_dead(s, ots);
3532bab1671fSRichard Henderson     }
3533bab1671fSRichard Henderson }
3534bab1671fSRichard Henderson 
3535dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
3536c896fe29Sbellard {
3537dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3538dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
353982790a87SRichard Henderson     TCGRegSet i_allocated_regs;
354082790a87SRichard Henderson     TCGRegSet o_allocated_regs;
3541b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
3542b6638662SRichard Henderson     TCGReg reg;
3543c896fe29Sbellard     TCGArg arg;
3544c896fe29Sbellard     const TCGArgConstraint *arg_ct;
3545c896fe29Sbellard     TCGTemp *ts;
3546c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
3547c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
3548c896fe29Sbellard 
3549c896fe29Sbellard     nb_oargs = def->nb_oargs;
3550c896fe29Sbellard     nb_iargs = def->nb_iargs;
3551c896fe29Sbellard 
3552c896fe29Sbellard     /* copy constants */
3553c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
3554dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
3555c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
3556c896fe29Sbellard 
3557d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
3558d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
355982790a87SRichard Henderson 
3560c896fe29Sbellard     /* satisfy input constraints */
3561c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
3562d62816f2SRichard Henderson         TCGRegSet i_preferred_regs, o_preferred_regs;
3563d62816f2SRichard Henderson 
3564c896fe29Sbellard         i = def->sorted_args[nb_oargs + k];
3565dd186292SRichard Henderson         arg = op->args[i];
3566c896fe29Sbellard         arg_ct = &def->args_ct[i];
356743439139SRichard Henderson         ts = arg_temp(arg);
356840ae5c62SRichard Henderson 
356940ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
357040ae5c62SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct)) {
3571c896fe29Sbellard             /* constant is OK for instruction */
3572c896fe29Sbellard             const_args[i] = 1;
3573c896fe29Sbellard             new_args[i] = ts->val;
3574d62816f2SRichard Henderson             continue;
3575c896fe29Sbellard         }
357640ae5c62SRichard Henderson 
3577d62816f2SRichard Henderson         i_preferred_regs = o_preferred_regs = 0;
35785ff9d6a4Sbellard         if (arg_ct->ct & TCG_CT_IALIAS) {
3579d62816f2SRichard Henderson             o_preferred_regs = op->output_pref[arg_ct->alias_index];
35805ff9d6a4Sbellard             if (ts->fixed_reg) {
35815ff9d6a4Sbellard                 /* if fixed register, we must allocate a new register
35825ff9d6a4Sbellard                    if the alias is not the same register */
3583d62816f2SRichard Henderson                 if (arg != op->args[arg_ct->alias_index]) {
35845ff9d6a4Sbellard                     goto allocate_in_reg;
3585d62816f2SRichard Henderson                 }
35865ff9d6a4Sbellard             } else {
3587c896fe29Sbellard                 /* if the input is aliased to an output and if it is
3588c896fe29Sbellard                    not dead after the instruction, we must allocate
3589c896fe29Sbellard                    a new register and move it */
3590866cb6cbSAurelien Jarno                 if (!IS_DEAD_ARG(i)) {
3591c896fe29Sbellard                     goto allocate_in_reg;
3592c896fe29Sbellard                 }
3593d62816f2SRichard Henderson 
35947e1df267SAurelien Jarno                 /* check if the current register has already been allocated
35957e1df267SAurelien Jarno                    for another input aliased to an output */
3596d62816f2SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG) {
35977e1df267SAurelien Jarno                     int k2, i2;
3598d62816f2SRichard Henderson                     reg = ts->reg;
35997e1df267SAurelien Jarno                     for (k2 = 0 ; k2 < k ; k2++) {
36007e1df267SAurelien Jarno                         i2 = def->sorted_args[nb_oargs + k2];
36017e1df267SAurelien Jarno                         if ((def->args_ct[i2].ct & TCG_CT_IALIAS) &&
3602d62816f2SRichard Henderson                             reg == new_args[i2]) {
36037e1df267SAurelien Jarno                             goto allocate_in_reg;
36047e1df267SAurelien Jarno                         }
36057e1df267SAurelien Jarno                     }
36065ff9d6a4Sbellard                 }
3607d62816f2SRichard Henderson                 i_preferred_regs = o_preferred_regs;
3608866cb6cbSAurelien Jarno             }
3609d62816f2SRichard Henderson         }
3610d62816f2SRichard Henderson 
3611d62816f2SRichard Henderson         temp_load(s, ts, arg_ct->u.regs, i_allocated_regs, i_preferred_regs);
3612c896fe29Sbellard         reg = ts->reg;
3613d62816f2SRichard Henderson 
3614c896fe29Sbellard         if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
3615c896fe29Sbellard             /* nothing to do : the constraint is satisfied */
3616c896fe29Sbellard         } else {
3617c896fe29Sbellard         allocate_in_reg:
3618c896fe29Sbellard             /* allocate a new register matching the constraint
3619c896fe29Sbellard                and move the temporary register into it */
3620d62816f2SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
3621d62816f2SRichard Henderson                       i_allocated_regs, 0);
362282790a87SRichard Henderson             reg = tcg_reg_alloc(s, arg_ct->u.regs, i_allocated_regs,
3623d62816f2SRichard Henderson                                 o_preferred_regs, ts->indirect_base);
362478113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
3625240c08d0SRichard Henderson                 /*
3626240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
3627240c08d0SRichard Henderson                  * temp back to its slot and load from there.
3628240c08d0SRichard Henderson                  */
3629240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
3630240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
3631240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
363278113e83SRichard Henderson             }
3633c896fe29Sbellard         }
3634c896fe29Sbellard         new_args[i] = reg;
3635c896fe29Sbellard         const_args[i] = 0;
363682790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
3637c896fe29Sbellard     }
3638c896fe29Sbellard 
3639c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
3640866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
3641866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
364243439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
3643c896fe29Sbellard         }
3644c896fe29Sbellard     }
3645c896fe29Sbellard 
3646a52ad07eSAurelien Jarno     if (def->flags & TCG_OPF_BB_END) {
364782790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
3648a52ad07eSAurelien Jarno     } else {
3649c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
3650b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
3651c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
3652c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
365382790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
3654c896fe29Sbellard                 }
3655c896fe29Sbellard             }
36563d5c5f87SAurelien Jarno         }
36573d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
36583d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
36593d5c5f87SAurelien Jarno                an exception. */
366082790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
3661c896fe29Sbellard         }
3662c896fe29Sbellard 
3663c896fe29Sbellard         /* satisfy the output constraints */
3664c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
3665c896fe29Sbellard             i = def->sorted_args[k];
3666dd186292SRichard Henderson             arg = op->args[i];
3667c896fe29Sbellard             arg_ct = &def->args_ct[i];
366843439139SRichard Henderson             ts = arg_temp(arg);
3669d63e3b6eSRichard Henderson 
3670d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
3671d63e3b6eSRichard Henderson             tcg_debug_assert(!ts->fixed_reg);
3672d63e3b6eSRichard Henderson 
367317280ff4SRichard Henderson             if ((arg_ct->ct & TCG_CT_ALIAS)
367417280ff4SRichard Henderson                 && !const_args[arg_ct->alias_index]) {
36755ff9d6a4Sbellard                 reg = new_args[arg_ct->alias_index];
367682790a87SRichard Henderson             } else if (arg_ct->ct & TCG_CT_NEWREG) {
367782790a87SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->u.regs,
367882790a87SRichard Henderson                                     i_allocated_regs | o_allocated_regs,
367969e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
3680c896fe29Sbellard             } else {
368182790a87SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->u.regs, o_allocated_regs,
368269e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
3683c896fe29Sbellard             }
368482790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
3685639368ddSAurelien Jarno             if (ts->val_type == TEMP_VAL_REG) {
3686f8b2f202SRichard Henderson                 s->reg_to_temp[ts->reg] = NULL;
3687639368ddSAurelien Jarno             }
3688c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
3689c896fe29Sbellard             ts->reg = reg;
3690d63e3b6eSRichard Henderson             /*
3691d63e3b6eSRichard Henderson              * Temp value is modified, so the value kept in memory is
3692d63e3b6eSRichard Henderson              * potentially not the same.
3693d63e3b6eSRichard Henderson              */
3694c896fe29Sbellard             ts->mem_coherent = 0;
3695f8b2f202SRichard Henderson             s->reg_to_temp[reg] = ts;
3696c896fe29Sbellard             new_args[i] = reg;
3697c896fe29Sbellard         }
3698e8996ee0Sbellard     }
3699c896fe29Sbellard 
3700c896fe29Sbellard     /* emit instruction */
3701d2fd745fSRichard Henderson     if (def->flags & TCG_OPF_VECTOR) {
3702d2fd745fSRichard Henderson         tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
3703d2fd745fSRichard Henderson                        new_args, const_args);
3704d2fd745fSRichard Henderson     } else {
3705dd186292SRichard Henderson         tcg_out_op(s, op->opc, new_args, const_args);
3706d2fd745fSRichard Henderson     }
3707c896fe29Sbellard 
3708c896fe29Sbellard     /* move the outputs in the correct register if needed */
3709c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
371043439139SRichard Henderson         ts = arg_temp(op->args[i]);
3711d63e3b6eSRichard Henderson 
3712d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
3713d63e3b6eSRichard Henderson         tcg_debug_assert(!ts->fixed_reg);
3714d63e3b6eSRichard Henderson 
3715ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
371698b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
371759d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
3718f8bf00f1SRichard Henderson             temp_dead(s, ts);
3719ec7a869dSAurelien Jarno         }
3720c896fe29Sbellard     }
3721c896fe29Sbellard }
3722c896fe29Sbellard 
3723b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP
3724b03cce8eSbellard #define STACK_DIR(x) (-(x))
3725b03cce8eSbellard #else
3726b03cce8eSbellard #define STACK_DIR(x) (x)
3727b03cce8eSbellard #endif
3728b03cce8eSbellard 
3729dd186292SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
3730c896fe29Sbellard {
3731cd9090aaSRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
3732cd9090aaSRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
3733dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3734b6638662SRichard Henderson     int flags, nb_regs, i;
3735b6638662SRichard Henderson     TCGReg reg;
3736cf066674SRichard Henderson     TCGArg arg;
3737c896fe29Sbellard     TCGTemp *ts;
3738d3452f1fSRichard Henderson     intptr_t stack_offset;
3739d3452f1fSRichard Henderson     size_t call_stack_size;
3740cf066674SRichard Henderson     tcg_insn_unit *func_addr;
3741cf066674SRichard Henderson     int allocate_args;
3742c896fe29Sbellard     TCGRegSet allocated_regs;
3743c896fe29Sbellard 
3744dd186292SRichard Henderson     func_addr = (tcg_insn_unit *)(intptr_t)op->args[nb_oargs + nb_iargs];
3745dd186292SRichard Henderson     flags = op->args[nb_oargs + nb_iargs + 1];
3746c896fe29Sbellard 
37476e17d0c5SStefan Weil     nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
3748c45cb8bbSRichard Henderson     if (nb_regs > nb_iargs) {
3749c45cb8bbSRichard Henderson         nb_regs = nb_iargs;
3750cf066674SRichard Henderson     }
3751c896fe29Sbellard 
3752c896fe29Sbellard     /* assign stack slots first */
3753c45cb8bbSRichard Henderson     call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long);
3754c896fe29Sbellard     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
3755c896fe29Sbellard         ~(TCG_TARGET_STACK_ALIGN - 1);
3756b03cce8eSbellard     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
3757b03cce8eSbellard     if (allocate_args) {
3758345649c0SBlue Swirl         /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
3759345649c0SBlue Swirl            preallocate call stack */
3760345649c0SBlue Swirl         tcg_abort();
3761b03cce8eSbellard     }
376239cf05d3Sbellard 
376339cf05d3Sbellard     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
3764c45cb8bbSRichard Henderson     for (i = nb_regs; i < nb_iargs; i++) {
3765dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
376639cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP
376739cf05d3Sbellard         stack_offset -= sizeof(tcg_target_long);
376839cf05d3Sbellard #endif
376939cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
377043439139SRichard Henderson             ts = arg_temp(arg);
377140ae5c62SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
3772b722452aSRichard Henderson                       s->reserved_regs, 0);
3773e4d5434cSblueswir1             tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
377439cf05d3Sbellard         }
377539cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP
377639cf05d3Sbellard         stack_offset += sizeof(tcg_target_long);
377739cf05d3Sbellard #endif
3778c896fe29Sbellard     }
3779c896fe29Sbellard 
3780c896fe29Sbellard     /* assign input registers */
3781d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
3782c896fe29Sbellard     for (i = 0; i < nb_regs; i++) {
3783dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
378439cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
378543439139SRichard Henderson             ts = arg_temp(arg);
3786c896fe29Sbellard             reg = tcg_target_call_iarg_regs[i];
378740ae5c62SRichard Henderson 
3788c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
3789c896fe29Sbellard                 if (ts->reg != reg) {
37904250da10SRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
379178113e83SRichard Henderson                     if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
3792240c08d0SRichard Henderson                         /*
3793240c08d0SRichard Henderson                          * Cross register class move not supported.  Sync the
3794240c08d0SRichard Henderson                          * temp back to its slot and load from there.
3795240c08d0SRichard Henderson                          */
3796240c08d0SRichard Henderson                         temp_sync(s, ts, allocated_regs, 0, 0);
3797240c08d0SRichard Henderson                         tcg_out_ld(s, ts->type, reg,
3798240c08d0SRichard Henderson                                    ts->mem_base->reg, ts->mem_offset);
379978113e83SRichard Henderson                     }
3800c896fe29Sbellard                 }
3801c896fe29Sbellard             } else {
3802ccb1bb66SRichard Henderson                 TCGRegSet arg_set = 0;
380340ae5c62SRichard Henderson 
38044250da10SRichard Henderson                 tcg_reg_free(s, reg, allocated_regs);
380540ae5c62SRichard Henderson                 tcg_regset_set_reg(arg_set, reg);
3806b722452aSRichard Henderson                 temp_load(s, ts, arg_set, allocated_regs, 0);
3807c896fe29Sbellard             }
380840ae5c62SRichard Henderson 
3809c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
3810c896fe29Sbellard         }
381139cf05d3Sbellard     }
3812c896fe29Sbellard 
3813c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
3814866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3815866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
381643439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
3817c896fe29Sbellard         }
3818c896fe29Sbellard     }
3819c896fe29Sbellard 
3820c896fe29Sbellard     /* clobber call registers */
3821c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
3822c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
3823b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
3824c896fe29Sbellard         }
3825c896fe29Sbellard     }
3826c896fe29Sbellard 
382778505279SAurelien Jarno     /* Save globals if they might be written by the helper, sync them if
382878505279SAurelien Jarno        they might be read. */
382978505279SAurelien Jarno     if (flags & TCG_CALL_NO_READ_GLOBALS) {
383078505279SAurelien Jarno         /* Nothing to do */
383178505279SAurelien Jarno     } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) {
383278505279SAurelien Jarno         sync_globals(s, allocated_regs);
383378505279SAurelien Jarno     } else {
3834e8996ee0Sbellard         save_globals(s, allocated_regs);
3835b9c18f56Saurel32     }
3836c896fe29Sbellard 
3837cf066674SRichard Henderson     tcg_out_call(s, func_addr);
3838c896fe29Sbellard 
3839c896fe29Sbellard     /* assign output registers and emit moves if needed */
3840c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
3841dd186292SRichard Henderson         arg = op->args[i];
384243439139SRichard Henderson         ts = arg_temp(arg);
3843d63e3b6eSRichard Henderson 
3844d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
3845d63e3b6eSRichard Henderson         tcg_debug_assert(!ts->fixed_reg);
3846d63e3b6eSRichard Henderson 
3847c896fe29Sbellard         reg = tcg_target_call_oarg_regs[i];
3848eabb7b91SAurelien Jarno         tcg_debug_assert(s->reg_to_temp[reg] == NULL);
3849639368ddSAurelien Jarno         if (ts->val_type == TEMP_VAL_REG) {
3850f8b2f202SRichard Henderson             s->reg_to_temp[ts->reg] = NULL;
3851639368ddSAurelien Jarno         }
3852c896fe29Sbellard         ts->val_type = TEMP_VAL_REG;
3853c896fe29Sbellard         ts->reg = reg;
3854c896fe29Sbellard         ts->mem_coherent = 0;
3855f8b2f202SRichard Henderson         s->reg_to_temp[reg] = ts;
3856ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
385798b4e186SRichard Henderson             temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i));
385859d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
3859f8bf00f1SRichard Henderson             temp_dead(s, ts);
3860c896fe29Sbellard         }
3861c896fe29Sbellard     }
38628c11ad25SAurelien Jarno }
3863c896fe29Sbellard 
3864c896fe29Sbellard #ifdef CONFIG_PROFILER
3865c896fe29Sbellard 
3866c3fac113SEmilio G. Cota /* avoid copy/paste errors */
3867c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field)                       \
3868c3fac113SEmilio G. Cota     do {                                                \
3869c3fac113SEmilio G. Cota         (to)->field += atomic_read(&((from)->field));   \
3870c3fac113SEmilio G. Cota     } while (0)
3871c896fe29Sbellard 
3872c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field)                                       \
3873c3fac113SEmilio G. Cota     do {                                                                \
3874c3fac113SEmilio G. Cota         typeof((from)->field) val__ = atomic_read(&((from)->field));    \
3875c3fac113SEmilio G. Cota         if (val__ > (to)->field) {                                      \
3876c3fac113SEmilio G. Cota             (to)->field = val__;                                        \
3877c3fac113SEmilio G. Cota         }                                                               \
3878c3fac113SEmilio G. Cota     } while (0)
3879c3fac113SEmilio G. Cota 
3880c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */
3881c3fac113SEmilio G. Cota static inline
3882c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
3883c896fe29Sbellard {
38843468b59eSEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
3885c3fac113SEmilio G. Cota     unsigned int i;
3886c3fac113SEmilio G. Cota 
38873468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
38883468b59eSEmilio G. Cota         TCGContext *s = atomic_read(&tcg_ctxs[i]);
38893468b59eSEmilio G. Cota         const TCGProfile *orig = &s->prof;
3890c3fac113SEmilio G. Cota 
3891c3fac113SEmilio G. Cota         if (counters) {
389272fd2efbSEmilio G. Cota             PROF_ADD(prof, orig, cpu_exec_time);
3893c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count1);
3894c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count);
3895c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, op_count);
3896c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, op_count_max);
3897c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, temp_count);
3898c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, temp_count_max);
3899c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, del_op_count);
3900c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_in_len);
3901c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_out_len);
3902c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, search_out_len);
3903c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, interm_time);
3904c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_time);
3905c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, la_time);
3906c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, opt_time);
3907c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_count);
3908c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_time);
3909c3fac113SEmilio G. Cota         }
3910c3fac113SEmilio G. Cota         if (table) {
3911c896fe29Sbellard             int i;
3912d70724ceSzhanghailiang 
391315fc7daaSRichard Henderson             for (i = 0; i < NB_OPS; i++) {
3914c3fac113SEmilio G. Cota                 PROF_ADD(prof, orig, table_op_count[i]);
3915c3fac113SEmilio G. Cota             }
3916c3fac113SEmilio G. Cota         }
3917c3fac113SEmilio G. Cota     }
3918c3fac113SEmilio G. Cota }
3919c3fac113SEmilio G. Cota 
3920c3fac113SEmilio G. Cota #undef PROF_ADD
3921c3fac113SEmilio G. Cota #undef PROF_MAX
3922c3fac113SEmilio G. Cota 
3923c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof)
3924c3fac113SEmilio G. Cota {
3925c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, true, false);
3926c3fac113SEmilio G. Cota }
3927c3fac113SEmilio G. Cota 
3928c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof)
3929c3fac113SEmilio G. Cota {
3930c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, false, true);
3931c3fac113SEmilio G. Cota }
3932c3fac113SEmilio G. Cota 
3933d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
3934c3fac113SEmilio G. Cota {
3935c3fac113SEmilio G. Cota     TCGProfile prof = {};
3936c3fac113SEmilio G. Cota     int i;
3937c3fac113SEmilio G. Cota 
3938c3fac113SEmilio G. Cota     tcg_profile_snapshot_table(&prof);
3939c3fac113SEmilio G. Cota     for (i = 0; i < NB_OPS; i++) {
3940d4c51a0aSMarkus Armbruster         qemu_printf("%s %" PRId64 "\n", tcg_op_defs[i].name,
3941c3fac113SEmilio G. Cota                     prof.table_op_count[i]);
3942c896fe29Sbellard     }
3943c896fe29Sbellard }
394472fd2efbSEmilio G. Cota 
394572fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
394672fd2efbSEmilio G. Cota {
394772fd2efbSEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
394872fd2efbSEmilio G. Cota     unsigned int i;
394972fd2efbSEmilio G. Cota     int64_t ret = 0;
395072fd2efbSEmilio G. Cota 
395172fd2efbSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
395272fd2efbSEmilio G. Cota         const TCGContext *s = atomic_read(&tcg_ctxs[i]);
395372fd2efbSEmilio G. Cota         const TCGProfile *prof = &s->prof;
395472fd2efbSEmilio G. Cota 
395572fd2efbSEmilio G. Cota         ret += atomic_read(&prof->cpu_exec_time);
395672fd2efbSEmilio G. Cota     }
395772fd2efbSEmilio G. Cota     return ret;
395872fd2efbSEmilio G. Cota }
3959246ae24dSMax Filippov #else
3960d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
3961246ae24dSMax Filippov {
3962d4c51a0aSMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
3963246ae24dSMax Filippov }
396472fd2efbSEmilio G. Cota 
396572fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
396672fd2efbSEmilio G. Cota {
396772fd2efbSEmilio G. Cota     error_report("%s: TCG profiler not compiled", __func__);
396872fd2efbSEmilio G. Cota     exit(EXIT_FAILURE);
396972fd2efbSEmilio G. Cota }
3970c896fe29Sbellard #endif
3971c896fe29Sbellard 
3972c896fe29Sbellard 
39735bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
3974c896fe29Sbellard {
3975c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER
3976c3fac113SEmilio G. Cota     TCGProfile *prof = &s->prof;
3977c3fac113SEmilio G. Cota #endif
397815fa08f8SRichard Henderson     int i, num_insns;
397915fa08f8SRichard Henderson     TCGOp *op;
3980c896fe29Sbellard 
398104fe6400SRichard Henderson #ifdef CONFIG_PROFILER
398204fe6400SRichard Henderson     {
3983c1f543b7SEmilio G. Cota         int n = 0;
398404fe6400SRichard Henderson 
398515fa08f8SRichard Henderson         QTAILQ_FOREACH(op, &s->ops, link) {
398615fa08f8SRichard Henderson             n++;
398715fa08f8SRichard Henderson         }
3988c3fac113SEmilio G. Cota         atomic_set(&prof->op_count, prof->op_count + n);
3989c3fac113SEmilio G. Cota         if (n > prof->op_count_max) {
3990c3fac113SEmilio G. Cota             atomic_set(&prof->op_count_max, n);
399104fe6400SRichard Henderson         }
399204fe6400SRichard Henderson 
399304fe6400SRichard Henderson         n = s->nb_temps;
3994c3fac113SEmilio G. Cota         atomic_set(&prof->temp_count, prof->temp_count + n);
3995c3fac113SEmilio G. Cota         if (n > prof->temp_count_max) {
3996c3fac113SEmilio G. Cota             atomic_set(&prof->temp_count_max, n);
399704fe6400SRichard Henderson         }
399804fe6400SRichard Henderson     }
399904fe6400SRichard Henderson #endif
400004fe6400SRichard Henderson 
4001c896fe29Sbellard #ifdef DEBUG_DISAS
4002d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
4003d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
40041ee73216SRichard Henderson         qemu_log_lock();
400593fcfe39Saliguori         qemu_log("OP:\n");
40061894f69aSRichard Henderson         tcg_dump_ops(s, false);
400793fcfe39Saliguori         qemu_log("\n");
40081ee73216SRichard Henderson         qemu_log_unlock();
4009c896fe29Sbellard     }
4010c896fe29Sbellard #endif
4011c896fe29Sbellard 
4012bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
4013bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
4014bef16ab4SRichard Henderson     {
4015bef16ab4SRichard Henderson         TCGLabel *l;
4016bef16ab4SRichard Henderson         bool error = false;
4017bef16ab4SRichard Henderson 
4018bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
4019bef16ab4SRichard Henderson             if (unlikely(!l->present) && l->refs) {
4020bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
4021bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
4022bef16ab4SRichard Henderson                 error = true;
4023bef16ab4SRichard Henderson             }
4024bef16ab4SRichard Henderson         }
4025bef16ab4SRichard Henderson         assert(!error);
4026bef16ab4SRichard Henderson     }
4027bef16ab4SRichard Henderson #endif
4028bef16ab4SRichard Henderson 
4029c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
4030c3fac113SEmilio G. Cota     atomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
4031c5cc28ffSAurelien Jarno #endif
4032c5cc28ffSAurelien Jarno 
40338f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
4034c45cb8bbSRichard Henderson     tcg_optimize(s);
40358f2e8c07SKirill Batuzov #endif
40368f2e8c07SKirill Batuzov 
4037a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4038c3fac113SEmilio G. Cota     atomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
4039c3fac113SEmilio G. Cota     atomic_set(&prof->la_time, prof->la_time - profile_getclock());
4040a23a9ec6Sbellard #endif
4041c5cc28ffSAurelien Jarno 
4042b4fc67c7SRichard Henderson     reachable_code_pass(s);
4043b83eabeaSRichard Henderson     liveness_pass_1(s);
40445a18407fSRichard Henderson 
40455a18407fSRichard Henderson     if (s->nb_indirects > 0) {
40465a18407fSRichard Henderson #ifdef DEBUG_DISAS
40475a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
40485a18407fSRichard Henderson                      && qemu_log_in_addr_range(tb->pc))) {
40491ee73216SRichard Henderson             qemu_log_lock();
40505a18407fSRichard Henderson             qemu_log("OP before indirect lowering:\n");
40511894f69aSRichard Henderson             tcg_dump_ops(s, false);
40525a18407fSRichard Henderson             qemu_log("\n");
40531ee73216SRichard Henderson             qemu_log_unlock();
40545a18407fSRichard Henderson         }
40555a18407fSRichard Henderson #endif
40565a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
4057b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
40585a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
4059b83eabeaSRichard Henderson             liveness_pass_1(s);
40605a18407fSRichard Henderson         }
40615a18407fSRichard Henderson     }
4062c5cc28ffSAurelien Jarno 
4063a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4064c3fac113SEmilio G. Cota     atomic_set(&prof->la_time, prof->la_time + profile_getclock());
4065a23a9ec6Sbellard #endif
4066c896fe29Sbellard 
4067c896fe29Sbellard #ifdef DEBUG_DISAS
4068d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
4069d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
40701ee73216SRichard Henderson         qemu_log_lock();
4071c5cc28ffSAurelien Jarno         qemu_log("OP after optimization and liveness analysis:\n");
40721894f69aSRichard Henderson         tcg_dump_ops(s, true);
407393fcfe39Saliguori         qemu_log("\n");
40741ee73216SRichard Henderson         qemu_log_unlock();
4075c896fe29Sbellard     }
4076c896fe29Sbellard #endif
4077c896fe29Sbellard 
4078c896fe29Sbellard     tcg_reg_alloc_start(s);
4079c896fe29Sbellard 
4080e7e168f4SEmilio G. Cota     s->code_buf = tb->tc.ptr;
4081e7e168f4SEmilio G. Cota     s->code_ptr = tb->tc.ptr;
4082c896fe29Sbellard 
4083659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
40846001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
4085659ef5cbSRichard Henderson #endif
408657a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
408757a26946SRichard Henderson     s->pool_labels = NULL;
408857a26946SRichard Henderson #endif
40899ecefc84SRichard Henderson 
4090fca8a500SRichard Henderson     num_insns = -1;
409115fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
4092c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
4093b3db8758Sblueswir1 
4094c896fe29Sbellard #ifdef CONFIG_PROFILER
4095c3fac113SEmilio G. Cota         atomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
4096c896fe29Sbellard #endif
4097c45cb8bbSRichard Henderson 
4098c896fe29Sbellard         switch (opc) {
4099c896fe29Sbellard         case INDEX_op_mov_i32:
4100c896fe29Sbellard         case INDEX_op_mov_i64:
4101d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
4102dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
4103c896fe29Sbellard             break;
4104e8996ee0Sbellard         case INDEX_op_movi_i32:
4105e8996ee0Sbellard         case INDEX_op_movi_i64:
4106d2fd745fSRichard Henderson         case INDEX_op_dupi_vec:
4107dd186292SRichard Henderson             tcg_reg_alloc_movi(s, op);
4108e8996ee0Sbellard             break;
4109bab1671fSRichard Henderson         case INDEX_op_dup_vec:
4110bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
4111bab1671fSRichard Henderson             break;
4112765b842aSRichard Henderson         case INDEX_op_insn_start:
4113fca8a500SRichard Henderson             if (num_insns >= 0) {
41149f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
41159f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
41169f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
41179f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
4118fca8a500SRichard Henderson             }
4119fca8a500SRichard Henderson             num_insns++;
4120bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
4121bad729e2SRichard Henderson                 target_ulong a;
4122bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
4123efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
4124bad729e2SRichard Henderson #else
4125efee3746SRichard Henderson                 a = op->args[i];
4126bad729e2SRichard Henderson #endif
4127fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
4128bad729e2SRichard Henderson             }
4129c896fe29Sbellard             break;
41305ff9d6a4Sbellard         case INDEX_op_discard:
413143439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
41325ff9d6a4Sbellard             break;
4133c896fe29Sbellard         case INDEX_op_set_label:
4134e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
4135efee3746SRichard Henderson             tcg_out_label(s, arg_label(op->args[0]), s->code_ptr);
4136c896fe29Sbellard             break;
4137c896fe29Sbellard         case INDEX_op_call:
4138dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
4139c45cb8bbSRichard Henderson             break;
4140c896fe29Sbellard         default:
414125c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
4142be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
4143c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
4144c896fe29Sbellard                faster to have specialized register allocator functions for
4145c896fe29Sbellard                some common argument patterns */
4146dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
4147c896fe29Sbellard             break;
4148c896fe29Sbellard         }
41498d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
4150c896fe29Sbellard         check_regs(s);
4151c896fe29Sbellard #endif
4152b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
4153b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
4154b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
4155b125f9dcSRichard Henderson            generating code without having to check during generation.  */
4156644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
4157b125f9dcSRichard Henderson             return -1;
4158b125f9dcSRichard Henderson         }
41596e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
41606e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
41616e6c4efeSRichard Henderson             return -2;
41626e6c4efeSRichard Henderson         }
4163c896fe29Sbellard     }
4164fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
4165fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
4166c45cb8bbSRichard Henderson 
4167b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
4168659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
4169aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
4170aeee05f5SRichard Henderson     if (i < 0) {
4171aeee05f5SRichard Henderson         return i;
417223dceda6SRichard Henderson     }
4173659ef5cbSRichard Henderson #endif
417457a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
41751768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
41761768987bSRichard Henderson     if (i < 0) {
41771768987bSRichard Henderson         return i;
417857a26946SRichard Henderson     }
417957a26946SRichard Henderson #endif
41807ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
41817ecd02a0SRichard Henderson         return -2;
41827ecd02a0SRichard Henderson     }
4183c896fe29Sbellard 
4184c896fe29Sbellard     /* flush instruction cache */
41851813e175SRichard Henderson     flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr);
41862aeabc08SStefan Weil 
41871813e175SRichard Henderson     return tcg_current_code_size(s);
4188c896fe29Sbellard }
4189c896fe29Sbellard 
4190a23a9ec6Sbellard #ifdef CONFIG_PROFILER
41913de2faa9SMarkus Armbruster void tcg_dump_info(void)
4192a23a9ec6Sbellard {
4193c3fac113SEmilio G. Cota     TCGProfile prof = {};
4194c3fac113SEmilio G. Cota     const TCGProfile *s;
4195c3fac113SEmilio G. Cota     int64_t tb_count;
4196c3fac113SEmilio G. Cota     int64_t tb_div_count;
4197c3fac113SEmilio G. Cota     int64_t tot;
4198c3fac113SEmilio G. Cota 
4199c3fac113SEmilio G. Cota     tcg_profile_snapshot_counters(&prof);
4200c3fac113SEmilio G. Cota     s = &prof;
4201c3fac113SEmilio G. Cota     tb_count = s->tb_count;
4202c3fac113SEmilio G. Cota     tb_div_count = tb_count ? tb_count : 1;
4203c3fac113SEmilio G. Cota     tot = s->interm_time + s->code_time;
4204a23a9ec6Sbellard 
42053de2faa9SMarkus Armbruster     qemu_printf("JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
4206a23a9ec6Sbellard                 tot, tot / 2.4e9);
42073de2faa9SMarkus Armbruster     qemu_printf("translated TBs      %" PRId64 " (aborted=%" PRId64
42083de2faa9SMarkus Armbruster                 " %0.1f%%)\n",
4209fca8a500SRichard Henderson                 tb_count, s->tb_count1 - tb_count,
4210fca8a500SRichard Henderson                 (double)(s->tb_count1 - s->tb_count)
4211fca8a500SRichard Henderson                 / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
42123de2faa9SMarkus Armbruster     qemu_printf("avg ops/TB          %0.1f max=%d\n",
4213fca8a500SRichard Henderson                 (double)s->op_count / tb_div_count, s->op_count_max);
42143de2faa9SMarkus Armbruster     qemu_printf("deleted ops/TB      %0.2f\n",
4215fca8a500SRichard Henderson                 (double)s->del_op_count / tb_div_count);
42163de2faa9SMarkus Armbruster     qemu_printf("avg temps/TB        %0.2f max=%d\n",
4217fca8a500SRichard Henderson                 (double)s->temp_count / tb_div_count, s->temp_count_max);
42183de2faa9SMarkus Armbruster     qemu_printf("avg host code/TB    %0.1f\n",
4219fca8a500SRichard Henderson                 (double)s->code_out_len / tb_div_count);
42203de2faa9SMarkus Armbruster     qemu_printf("avg search data/TB  %0.1f\n",
4221fca8a500SRichard Henderson                 (double)s->search_out_len / tb_div_count);
4222a23a9ec6Sbellard 
42233de2faa9SMarkus Armbruster     qemu_printf("cycles/op           %0.1f\n",
4224a23a9ec6Sbellard                 s->op_count ? (double)tot / s->op_count : 0);
42253de2faa9SMarkus Armbruster     qemu_printf("cycles/in byte      %0.1f\n",
4226a23a9ec6Sbellard                 s->code_in_len ? (double)tot / s->code_in_len : 0);
42273de2faa9SMarkus Armbruster     qemu_printf("cycles/out byte     %0.1f\n",
4228a23a9ec6Sbellard                 s->code_out_len ? (double)tot / s->code_out_len : 0);
42293de2faa9SMarkus Armbruster     qemu_printf("cycles/search byte     %0.1f\n",
4230fca8a500SRichard Henderson                 s->search_out_len ? (double)tot / s->search_out_len : 0);
4231fca8a500SRichard Henderson     if (tot == 0) {
4232a23a9ec6Sbellard         tot = 1;
4233fca8a500SRichard Henderson     }
42343de2faa9SMarkus Armbruster     qemu_printf("  gen_interm time   %0.1f%%\n",
4235a23a9ec6Sbellard                 (double)s->interm_time / tot * 100.0);
42363de2faa9SMarkus Armbruster     qemu_printf("  gen_code time     %0.1f%%\n",
4237a23a9ec6Sbellard                 (double)s->code_time / tot * 100.0);
42383de2faa9SMarkus Armbruster     qemu_printf("optim./code time    %0.1f%%\n",
4239c5cc28ffSAurelien Jarno                 (double)s->opt_time / (s->code_time ? s->code_time : 1)
4240c5cc28ffSAurelien Jarno                 * 100.0);
42413de2faa9SMarkus Armbruster     qemu_printf("liveness/code time  %0.1f%%\n",
4242a23a9ec6Sbellard                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
42433de2faa9SMarkus Armbruster     qemu_printf("cpu_restore count   %" PRId64 "\n",
4244a23a9ec6Sbellard                 s->restore_count);
42453de2faa9SMarkus Armbruster     qemu_printf("  avg cycles        %0.1f\n",
4246a23a9ec6Sbellard                 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
4247a23a9ec6Sbellard }
4248a23a9ec6Sbellard #else
42493de2faa9SMarkus Armbruster void tcg_dump_info(void)
4250a23a9ec6Sbellard {
42513de2faa9SMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4252a23a9ec6Sbellard }
4253a23a9ec6Sbellard #endif
4254813da627SRichard Henderson 
4255813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
42565872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
42575872bbf2SRichard Henderson 
42585872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
42595872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
42605872bbf2SRichard Henderson 
42615872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
42625872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
42635872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
42645872bbf2SRichard Henderson 
42655872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
42665872bbf2SRichard Henderson */
4267813da627SRichard Henderson 
4268813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
4269813da627SRichard Henderson typedef enum {
4270813da627SRichard Henderson     JIT_NOACTION = 0,
4271813da627SRichard Henderson     JIT_REGISTER_FN,
4272813da627SRichard Henderson     JIT_UNREGISTER_FN
4273813da627SRichard Henderson } jit_actions_t;
4274813da627SRichard Henderson 
4275813da627SRichard Henderson struct jit_code_entry {
4276813da627SRichard Henderson     struct jit_code_entry *next_entry;
4277813da627SRichard Henderson     struct jit_code_entry *prev_entry;
4278813da627SRichard Henderson     const void *symfile_addr;
4279813da627SRichard Henderson     uint64_t symfile_size;
4280813da627SRichard Henderson };
4281813da627SRichard Henderson 
4282813da627SRichard Henderson struct jit_descriptor {
4283813da627SRichard Henderson     uint32_t version;
4284813da627SRichard Henderson     uint32_t action_flag;
4285813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
4286813da627SRichard Henderson     struct jit_code_entry *first_entry;
4287813da627SRichard Henderson };
4288813da627SRichard Henderson 
4289813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
4290813da627SRichard Henderson void __jit_debug_register_code(void)
4291813da627SRichard Henderson {
4292813da627SRichard Henderson     asm("");
4293813da627SRichard Henderson }
4294813da627SRichard Henderson 
4295813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
4296813da627SRichard Henderson    the version before we can set it.  */
4297813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
4298813da627SRichard Henderson 
4299813da627SRichard Henderson /* End GDB interface.  */
4300813da627SRichard Henderson 
4301813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
4302813da627SRichard Henderson {
4303813da627SRichard Henderson     const char *p = strtab + 1;
4304813da627SRichard Henderson 
4305813da627SRichard Henderson     while (1) {
4306813da627SRichard Henderson         if (strcmp(p, str) == 0) {
4307813da627SRichard Henderson             return p - strtab;
4308813da627SRichard Henderson         }
4309813da627SRichard Henderson         p += strlen(p) + 1;
4310813da627SRichard Henderson     }
4311813da627SRichard Henderson }
4312813da627SRichard Henderson 
43135872bbf2SRichard Henderson static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
43142c90784aSRichard Henderson                                  const void *debug_frame,
43152c90784aSRichard Henderson                                  size_t debug_frame_size)
4316813da627SRichard Henderson {
43175872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
43185872bbf2SRichard Henderson         uint32_t  len;
43195872bbf2SRichard Henderson         uint16_t  version;
43205872bbf2SRichard Henderson         uint32_t  abbrev;
43215872bbf2SRichard Henderson         uint8_t   ptr_size;
43225872bbf2SRichard Henderson         uint8_t   cu_die;
43235872bbf2SRichard Henderson         uint16_t  cu_lang;
43245872bbf2SRichard Henderson         uintptr_t cu_low_pc;
43255872bbf2SRichard Henderson         uintptr_t cu_high_pc;
43265872bbf2SRichard Henderson         uint8_t   fn_die;
43275872bbf2SRichard Henderson         char      fn_name[16];
43285872bbf2SRichard Henderson         uintptr_t fn_low_pc;
43295872bbf2SRichard Henderson         uintptr_t fn_high_pc;
43305872bbf2SRichard Henderson         uint8_t   cu_eoc;
43315872bbf2SRichard Henderson     };
4332813da627SRichard Henderson 
4333813da627SRichard Henderson     struct ElfImage {
4334813da627SRichard Henderson         ElfW(Ehdr) ehdr;
4335813da627SRichard Henderson         ElfW(Phdr) phdr;
43365872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
43375872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
43385872bbf2SRichard Henderson         struct DebugInfo di;
43395872bbf2SRichard Henderson         uint8_t    da[24];
43405872bbf2SRichard Henderson         char       str[80];
43415872bbf2SRichard Henderson     };
43425872bbf2SRichard Henderson 
43435872bbf2SRichard Henderson     struct ElfImage *img;
43445872bbf2SRichard Henderson 
43455872bbf2SRichard Henderson     static const struct ElfImage img_template = {
43465872bbf2SRichard Henderson         .ehdr = {
43475872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
43485872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
43495872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
43505872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
43515872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
43525872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
43535872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
43545872bbf2SRichard Henderson             .e_type = ET_EXEC,
43555872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
43565872bbf2SRichard Henderson             .e_version = EV_CURRENT,
43575872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
43585872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
43595872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
43605872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
43615872bbf2SRichard Henderson             .e_phnum = 1,
43625872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
43635872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
43645872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
4365abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
4366abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
4367abbb3eaeSRichard Henderson #endif
4368abbb3eaeSRichard Henderson #ifdef ELF_OSABI
4369abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
4370abbb3eaeSRichard Henderson #endif
43715872bbf2SRichard Henderson         },
43725872bbf2SRichard Henderson         .phdr = {
43735872bbf2SRichard Henderson             .p_type = PT_LOAD,
43745872bbf2SRichard Henderson             .p_flags = PF_X,
43755872bbf2SRichard Henderson         },
43765872bbf2SRichard Henderson         .shdr = {
43775872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
43785872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
43795872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
43805872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
43815872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
43825872bbf2SRichard Henderson             [1] = { /* .text */
43835872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
43845872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
43855872bbf2SRichard Henderson             },
43865872bbf2SRichard Henderson             [2] = { /* .debug_info */
43875872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
43885872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
43895872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
43905872bbf2SRichard Henderson             },
43915872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
43925872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
43935872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
43945872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
43955872bbf2SRichard Henderson             },
43965872bbf2SRichard Henderson             [4] = { /* .debug_frame */
43975872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
43985872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
43995872bbf2SRichard Henderson             },
44005872bbf2SRichard Henderson             [5] = { /* .symtab */
44015872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
44025872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
44035872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
44045872bbf2SRichard Henderson                 .sh_info = 1,
44055872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
44065872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
44075872bbf2SRichard Henderson             },
44085872bbf2SRichard Henderson             [6] = { /* .strtab */
44095872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
44105872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
44115872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
44125872bbf2SRichard Henderson             }
44135872bbf2SRichard Henderson         },
44145872bbf2SRichard Henderson         .sym = {
44155872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
44165872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
44175872bbf2SRichard Henderson                 .st_shndx = 1,
44185872bbf2SRichard Henderson             }
44195872bbf2SRichard Henderson         },
44205872bbf2SRichard Henderson         .di = {
44215872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
44225872bbf2SRichard Henderson             .version = 2,
44235872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
44245872bbf2SRichard Henderson             .cu_die = 1,
44255872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
44265872bbf2SRichard Henderson             .fn_die = 2,
44275872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
44285872bbf2SRichard Henderson         },
44295872bbf2SRichard Henderson         .da = {
44305872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
44315872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
44325872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
44335872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
44345872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
44355872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
44365872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
44375872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
44385872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
44395872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
44405872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
44415872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
44425872bbf2SRichard Henderson             0           /* no more abbrev */
44435872bbf2SRichard Henderson         },
44445872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
44455872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
4446813da627SRichard Henderson     };
4447813da627SRichard Henderson 
4448813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
4449813da627SRichard Henderson     static struct jit_code_entry one_entry;
4450813da627SRichard Henderson 
44515872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
4452813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
44532c90784aSRichard Henderson     DebugFrameHeader *dfh;
4454813da627SRichard Henderson 
44555872bbf2SRichard Henderson     img = g_malloc(img_size);
44565872bbf2SRichard Henderson     *img = img_template;
4457813da627SRichard Henderson 
44585872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
44595872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
44605872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
4461813da627SRichard Henderson 
44625872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
44635872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
44645872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
4465813da627SRichard Henderson 
44665872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
44675872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
44685872bbf2SRichard Henderson 
44695872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
44705872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
44715872bbf2SRichard Henderson 
44725872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
44735872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
44745872bbf2SRichard Henderson 
44755872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
44765872bbf2SRichard Henderson     img->sym[1].st_value = buf;
44775872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
44785872bbf2SRichard Henderson 
44795872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
448045aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
44815872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
448245aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
4483813da627SRichard Henderson 
44842c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
44852c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
44862c90784aSRichard Henderson     dfh->fde.func_start = buf;
44872c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
44882c90784aSRichard Henderson 
4489813da627SRichard Henderson #ifdef DEBUG_JIT
4490813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
4491813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
4492813da627SRichard Henderson     {
4493813da627SRichard Henderson         FILE *f = fopen("/tmp/qemu.jit", "w+b");
4494813da627SRichard Henderson         if (f) {
44955872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
4496813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
4497813da627SRichard Henderson             }
4498813da627SRichard Henderson             fclose(f);
4499813da627SRichard Henderson         }
4500813da627SRichard Henderson     }
4501813da627SRichard Henderson #endif
4502813da627SRichard Henderson 
4503813da627SRichard Henderson     one_entry.symfile_addr = img;
4504813da627SRichard Henderson     one_entry.symfile_size = img_size;
4505813da627SRichard Henderson 
4506813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
4507813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
4508813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
4509813da627SRichard Henderson     __jit_debug_register_code();
4510813da627SRichard Henderson }
4511813da627SRichard Henderson #else
45125872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
45135872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
4514813da627SRichard Henderson 
4515813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size,
45162c90784aSRichard Henderson                                  const void *debug_frame,
45172c90784aSRichard Henderson                                  size_t debug_frame_size)
4518813da627SRichard Henderson {
4519813da627SRichard Henderson }
4520813da627SRichard Henderson 
4521813da627SRichard Henderson void tcg_register_jit(void *buf, size_t buf_size)
4522813da627SRichard Henderson {
4523813da627SRichard Henderson }
4524813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
4525db432672SRichard Henderson 
4526db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
4527db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
4528db432672SRichard Henderson {
4529db432672SRichard Henderson     g_assert_not_reached();
4530db432672SRichard Henderson }
4531db432672SRichard Henderson #endif
4532