xref: /qemu/tcg/tcg.c (revision e01fa97dea857a35be5bb8cce0d632a62e72c689)
1c896fe29Sbellard /*
2c896fe29Sbellard  * Tiny Code Generator for QEMU
3c896fe29Sbellard  *
4c896fe29Sbellard  * Copyright (c) 2008 Fabrice Bellard
5c896fe29Sbellard  *
6c896fe29Sbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
7c896fe29Sbellard  * of this software and associated documentation files (the "Software"), to deal
8c896fe29Sbellard  * in the Software without restriction, including without limitation the rights
9c896fe29Sbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10c896fe29Sbellard  * copies of the Software, and to permit persons to whom the Software is
11c896fe29Sbellard  * furnished to do so, subject to the following conditions:
12c896fe29Sbellard  *
13c896fe29Sbellard  * The above copyright notice and this permission notice shall be included in
14c896fe29Sbellard  * all copies or substantial portions of the Software.
15c896fe29Sbellard  *
16c896fe29Sbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17c896fe29Sbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18c896fe29Sbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19c896fe29Sbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20c896fe29Sbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21c896fe29Sbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22c896fe29Sbellard  * THE SOFTWARE.
23c896fe29Sbellard  */
24c896fe29Sbellard 
25c896fe29Sbellard /* define it to use liveness analysis (better code) */
268f2e8c07SKirill Batuzov #define USE_TCG_OPTIMIZATIONS
27c896fe29Sbellard 
28757e725bSPeter Maydell #include "qemu/osdep.h"
29cca82982Saurel32 
30813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB.  */
31813da627SRichard Henderson #undef DEBUG_JIT
32813da627SRichard Henderson 
3372fd2efbSEmilio G. Cota #include "qemu/error-report.h"
34f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
351de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
36d4c51a0aSMarkus Armbruster #include "qemu/qemu-print.h"
371de7afc9SPaolo Bonzini #include "qemu/timer.h"
38084cfca1SRichard Henderson #include "qemu/cacheflush.h"
39c896fe29Sbellard 
40c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU
41c896fe29Sbellard    CPU definitions. Currently they are used for qemu_ld/st
42c896fe29Sbellard    instructions */
43c896fe29Sbellard #define NO_CPU_IO_DEFS
44c896fe29Sbellard #include "cpu.h"
45c896fe29Sbellard 
4663c91552SPaolo Bonzini #include "exec/exec-all.h"
4763c91552SPaolo Bonzini 
485cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY)
495cc8767dSLike Xu #include "hw/boards.h"
505cc8767dSLike Xu #endif
515cc8767dSLike Xu 
52dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
53813da627SRichard Henderson 
54edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX
55813da627SRichard Henderson # define ELF_CLASS  ELFCLASS32
56edee2579SRichard Henderson #else
57edee2579SRichard Henderson # define ELF_CLASS  ELFCLASS64
58813da627SRichard Henderson #endif
59813da627SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
60813da627SRichard Henderson # define ELF_DATA   ELFDATA2MSB
61813da627SRichard Henderson #else
62813da627SRichard Henderson # define ELF_DATA   ELFDATA2LSB
63813da627SRichard Henderson #endif
64813da627SRichard Henderson 
65c896fe29Sbellard #include "elf.h"
66508127e2SPaolo Bonzini #include "exec/log.h"
673468b59eSEmilio G. Cota #include "sysemu/sysemu.h"
68c896fe29Sbellard 
69139c1837SPaolo Bonzini /* Forward declarations for functions declared in tcg-target.c.inc and
70ce151109SPeter Maydell    used here. */
71e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s);
72f69d277eSRichard Henderson static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode);
73e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
746ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
752ba7fae2SRichard Henderson                         intptr_t value, intptr_t addend);
76c896fe29Sbellard 
77497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts.  */
78497a22ebSRichard Henderson typedef struct {
79497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
80497a22ebSRichard Henderson     uint32_t id;
81497a22ebSRichard Henderson     uint8_t version;
82497a22ebSRichard Henderson     char augmentation[1];
83497a22ebSRichard Henderson     uint8_t code_align;
84497a22ebSRichard Henderson     uint8_t data_align;
85497a22ebSRichard Henderson     uint8_t return_column;
86497a22ebSRichard Henderson } DebugFrameCIE;
87497a22ebSRichard Henderson 
88497a22ebSRichard Henderson typedef struct QEMU_PACKED {
89497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
90497a22ebSRichard Henderson     uint32_t cie_offset;
91edee2579SRichard Henderson     uintptr_t func_start;
92edee2579SRichard Henderson     uintptr_t func_len;
93497a22ebSRichard Henderson } DebugFrameFDEHeader;
94497a22ebSRichard Henderson 
952c90784aSRichard Henderson typedef struct QEMU_PACKED {
962c90784aSRichard Henderson     DebugFrameCIE cie;
972c90784aSRichard Henderson     DebugFrameFDEHeader fde;
982c90784aSRichard Henderson } DebugFrameHeader;
992c90784aSRichard Henderson 
100755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
1012c90784aSRichard Henderson                                  const void *debug_frame,
1022c90784aSRichard Henderson                                  size_t debug_frame_size)
103813da627SRichard Henderson     __attribute__((unused));
104813da627SRichard Henderson 
105139c1837SPaolo Bonzini /* Forward declarations for functions declared and used in tcg-target.c.inc. */
106069ea736SRichard Henderson static const char *target_parse_constraint(TCGArgConstraint *ct,
107069ea736SRichard Henderson                                            const char *ct_str, TCGType type);
1082a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
109a05b5b9bSRichard Henderson                        intptr_t arg2);
11078113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
111c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1122a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
113c0ad3001SStefan Weil static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
114c0ad3001SStefan Weil                        const int *const_args);
115d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec
116e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
117e7632cfaSRichard Henderson                             TCGReg dst, TCGReg src);
118d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
119d6ecb4a9SRichard Henderson                              TCGReg dst, TCGReg base, intptr_t offset);
1204e186175SRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1214e186175SRichard Henderson                              TCGReg dst, int64_t arg);
122d2fd745fSRichard Henderson static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl,
123d2fd745fSRichard Henderson                            unsigned vece, const TCGArg *args,
124d2fd745fSRichard Henderson                            const int *const_args);
125d2fd745fSRichard Henderson #else
126e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
127e7632cfaSRichard Henderson                                    TCGReg dst, TCGReg src)
128e7632cfaSRichard Henderson {
129e7632cfaSRichard Henderson     g_assert_not_reached();
130e7632cfaSRichard Henderson }
131d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
132d6ecb4a9SRichard Henderson                                     TCGReg dst, TCGReg base, intptr_t offset)
133d6ecb4a9SRichard Henderson {
134d6ecb4a9SRichard Henderson     g_assert_not_reached();
135d6ecb4a9SRichard Henderson }
1364e186175SRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
1374e186175SRichard Henderson                                     TCGReg dst, int64_t arg)
138e7632cfaSRichard Henderson {
139e7632cfaSRichard Henderson     g_assert_not_reached();
140e7632cfaSRichard Henderson }
141d2fd745fSRichard Henderson static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl,
142d2fd745fSRichard Henderson                                   unsigned vece, const TCGArg *args,
143d2fd745fSRichard Henderson                                   const int *const_args)
144d2fd745fSRichard Henderson {
145d2fd745fSRichard Henderson     g_assert_not_reached();
146d2fd745fSRichard Henderson }
147d2fd745fSRichard Henderson #endif
1482a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
149a05b5b9bSRichard Henderson                        intptr_t arg2);
15059d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
15159d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
1522be7d76bSRichard Henderson static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target);
153f6c6afc1SRichard Henderson static int tcg_target_const_match(tcg_target_long val, TCGType type,
154c0ad3001SStefan Weil                                   const TCGArgConstraint *arg_ct);
155659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
156aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s);
157659ef5cbSRichard Henderson #endif
158c896fe29Sbellard 
159a505785cSEmilio G. Cota #define TCG_HIGHWATER 1024
160a505785cSEmilio G. Cota 
161df2cce29SEmilio G. Cota static TCGContext **tcg_ctxs;
162df2cce29SEmilio G. Cota static unsigned int n_tcg_ctxs;
1631c2adb95SRichard Henderson TCGv_env cpu_env = 0;
164c8bc1168SRichard Henderson const void *tcg_code_gen_epilogue;
165db0c51a3SRichard Henderson uintptr_t tcg_splitwx_diff;
166df2cce29SEmilio G. Cota 
167b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
168b91ccb31SRichard Henderson tcg_prologue_fn *tcg_qemu_tb_exec;
169b91ccb31SRichard Henderson #endif
170b91ccb31SRichard Henderson 
171be2cdc5eSEmilio G. Cota struct tcg_region_tree {
172be2cdc5eSEmilio G. Cota     QemuMutex lock;
173be2cdc5eSEmilio G. Cota     GTree *tree;
174be2cdc5eSEmilio G. Cota     /* padding to avoid false sharing is computed at run-time */
175be2cdc5eSEmilio G. Cota };
176be2cdc5eSEmilio G. Cota 
177e8feb96fSEmilio G. Cota /*
178e8feb96fSEmilio G. Cota  * We divide code_gen_buffer into equally-sized "regions" that TCG threads
179e8feb96fSEmilio G. Cota  * dynamically allocate from as demand dictates. Given appropriate region
180e8feb96fSEmilio G. Cota  * sizing, this minimizes flushes even when some TCG threads generate a lot
181e8feb96fSEmilio G. Cota  * more code than others.
182e8feb96fSEmilio G. Cota  */
183e8feb96fSEmilio G. Cota struct tcg_region_state {
184e8feb96fSEmilio G. Cota     QemuMutex lock;
185e8feb96fSEmilio G. Cota 
186e8feb96fSEmilio G. Cota     /* fields set at init time */
187e8feb96fSEmilio G. Cota     void *start;
188e8feb96fSEmilio G. Cota     void *start_aligned;
189e8feb96fSEmilio G. Cota     void *end;
190e8feb96fSEmilio G. Cota     size_t n;
191e8feb96fSEmilio G. Cota     size_t size; /* size of one region */
192e8feb96fSEmilio G. Cota     size_t stride; /* .size + guard size */
193e8feb96fSEmilio G. Cota 
194e8feb96fSEmilio G. Cota     /* fields protected by the lock */
195e8feb96fSEmilio G. Cota     size_t current; /* current region index */
196e8feb96fSEmilio G. Cota     size_t agg_size_full; /* aggregate size of full regions */
197e8feb96fSEmilio G. Cota };
198e8feb96fSEmilio G. Cota 
199e8feb96fSEmilio G. Cota static struct tcg_region_state region;
200be2cdc5eSEmilio G. Cota /*
201be2cdc5eSEmilio G. Cota  * This is an array of struct tcg_region_tree's, with padding.
202be2cdc5eSEmilio G. Cota  * We use void * to simplify the computation of region_trees[i]; each
203be2cdc5eSEmilio G. Cota  * struct is found every tree_size bytes.
204be2cdc5eSEmilio G. Cota  */
205be2cdc5eSEmilio G. Cota static void *region_trees;
206be2cdc5eSEmilio G. Cota static size_t tree_size;
207d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
208b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
209c896fe29Sbellard 
2101813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
2114196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
212c896fe29Sbellard {
213c896fe29Sbellard     *s->code_ptr++ = v;
214c896fe29Sbellard }
215c896fe29Sbellard 
2164196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
2174196dca6SPeter Maydell                                                       uint8_t v)
2185c53bb81SPeter Maydell {
2191813e175SRichard Henderson     *p = v;
2205c53bb81SPeter Maydell }
2211813e175SRichard Henderson #endif
2225c53bb81SPeter Maydell 
2231813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
2244196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
225c896fe29Sbellard {
2261813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2271813e175SRichard Henderson         *s->code_ptr++ = v;
2281813e175SRichard Henderson     } else {
2291813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2304387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2311813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
2321813e175SRichard Henderson     }
233c896fe29Sbellard }
234c896fe29Sbellard 
2354196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2364196dca6SPeter Maydell                                                        uint16_t v)
2375c53bb81SPeter Maydell {
2381813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2391813e175SRichard Henderson         *p = v;
2401813e175SRichard Henderson     } else {
2415c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2425c53bb81SPeter Maydell     }
2431813e175SRichard Henderson }
2441813e175SRichard Henderson #endif
2455c53bb81SPeter Maydell 
2461813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
2474196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
248c896fe29Sbellard {
2491813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2501813e175SRichard Henderson         *s->code_ptr++ = v;
2511813e175SRichard Henderson     } else {
2521813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2534387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2541813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
2551813e175SRichard Henderson     }
256c896fe29Sbellard }
257c896fe29Sbellard 
2584196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
2594196dca6SPeter Maydell                                                        uint32_t v)
2605c53bb81SPeter Maydell {
2611813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2621813e175SRichard Henderson         *p = v;
2631813e175SRichard Henderson     } else {
2645c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2655c53bb81SPeter Maydell     }
2661813e175SRichard Henderson }
2671813e175SRichard Henderson #endif
2685c53bb81SPeter Maydell 
2691813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
2704196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
271ac26eb69SRichard Henderson {
2721813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2731813e175SRichard Henderson         *s->code_ptr++ = v;
2741813e175SRichard Henderson     } else {
2751813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2764387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2771813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
2781813e175SRichard Henderson     }
279ac26eb69SRichard Henderson }
280ac26eb69SRichard Henderson 
2814196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
2824196dca6SPeter Maydell                                                        uint64_t v)
2835c53bb81SPeter Maydell {
2841813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2851813e175SRichard Henderson         *p = v;
2861813e175SRichard Henderson     } else {
2875c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2885c53bb81SPeter Maydell     }
2891813e175SRichard Henderson }
2901813e175SRichard Henderson #endif
2915c53bb81SPeter Maydell 
292c896fe29Sbellard /* label relocation processing */
293c896fe29Sbellard 
2941813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
295bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
296c896fe29Sbellard {
2977ecd02a0SRichard Henderson     TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation));
298c896fe29Sbellard 
299c896fe29Sbellard     r->type = type;
300c896fe29Sbellard     r->ptr = code_ptr;
301c896fe29Sbellard     r->addend = addend;
3027ecd02a0SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
303c896fe29Sbellard }
304c896fe29Sbellard 
30592ab8e7dSRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l)
306c896fe29Sbellard {
307eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
308c896fe29Sbellard     l->has_value = 1;
30992ab8e7dSRichard Henderson     l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr);
310c896fe29Sbellard }
311c896fe29Sbellard 
31242a268c2SRichard Henderson TCGLabel *gen_new_label(void)
313c896fe29Sbellard {
314b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
31551e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
316c896fe29Sbellard 
3177ecd02a0SRichard Henderson     memset(l, 0, sizeof(TCGLabel));
3187ecd02a0SRichard Henderson     l->id = s->nb_labels++;
3197ecd02a0SRichard Henderson     QSIMPLEQ_INIT(&l->relocs);
3207ecd02a0SRichard Henderson 
321bef16ab4SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
32242a268c2SRichard Henderson 
32342a268c2SRichard Henderson     return l;
324c896fe29Sbellard }
325c896fe29Sbellard 
3267ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s)
3277ecd02a0SRichard Henderson {
3287ecd02a0SRichard Henderson     TCGLabel *l;
3297ecd02a0SRichard Henderson 
3307ecd02a0SRichard Henderson     QSIMPLEQ_FOREACH(l, &s->labels, next) {
3317ecd02a0SRichard Henderson         TCGRelocation *r;
3327ecd02a0SRichard Henderson         uintptr_t value = l->u.value;
3337ecd02a0SRichard Henderson 
3347ecd02a0SRichard Henderson         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
3357ecd02a0SRichard Henderson             if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
3367ecd02a0SRichard Henderson                 return false;
3377ecd02a0SRichard Henderson             }
3387ecd02a0SRichard Henderson         }
3397ecd02a0SRichard Henderson     }
3407ecd02a0SRichard Henderson     return true;
3417ecd02a0SRichard Henderson }
3427ecd02a0SRichard Henderson 
3439f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3449f754620SRichard Henderson {
345f14bed3fSRichard Henderson     /*
346f14bed3fSRichard Henderson      * We will check for overflow at the end of the opcode loop in
347f14bed3fSRichard Henderson      * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
348f14bed3fSRichard Henderson      */
349f14bed3fSRichard Henderson     s->tb_jmp_reset_offset[which] = tcg_current_code_size(s);
3509f754620SRichard Henderson }
3519f754620SRichard Henderson 
352139c1837SPaolo Bonzini #include "tcg-target.c.inc"
353c896fe29Sbellard 
354be2cdc5eSEmilio G. Cota /* compare a pointer @ptr and a tb_tc @s */
355be2cdc5eSEmilio G. Cota static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s)
356be2cdc5eSEmilio G. Cota {
357be2cdc5eSEmilio G. Cota     if (ptr >= s->ptr + s->size) {
358be2cdc5eSEmilio G. Cota         return 1;
359be2cdc5eSEmilio G. Cota     } else if (ptr < s->ptr) {
360be2cdc5eSEmilio G. Cota         return -1;
361be2cdc5eSEmilio G. Cota     }
362be2cdc5eSEmilio G. Cota     return 0;
363be2cdc5eSEmilio G. Cota }
364be2cdc5eSEmilio G. Cota 
365be2cdc5eSEmilio G. Cota static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp)
366be2cdc5eSEmilio G. Cota {
367be2cdc5eSEmilio G. Cota     const struct tb_tc *a = ap;
368be2cdc5eSEmilio G. Cota     const struct tb_tc *b = bp;
369be2cdc5eSEmilio G. Cota 
370be2cdc5eSEmilio G. Cota     /*
371be2cdc5eSEmilio G. Cota      * When both sizes are set, we know this isn't a lookup.
372be2cdc5eSEmilio G. Cota      * This is the most likely case: every TB must be inserted; lookups
373be2cdc5eSEmilio G. Cota      * are a lot less frequent.
374be2cdc5eSEmilio G. Cota      */
375be2cdc5eSEmilio G. Cota     if (likely(a->size && b->size)) {
376be2cdc5eSEmilio G. Cota         if (a->ptr > b->ptr) {
377be2cdc5eSEmilio G. Cota             return 1;
378be2cdc5eSEmilio G. Cota         } else if (a->ptr < b->ptr) {
379be2cdc5eSEmilio G. Cota             return -1;
380be2cdc5eSEmilio G. Cota         }
381be2cdc5eSEmilio G. Cota         /* a->ptr == b->ptr should happen only on deletions */
382be2cdc5eSEmilio G. Cota         g_assert(a->size == b->size);
383be2cdc5eSEmilio G. Cota         return 0;
384be2cdc5eSEmilio G. Cota     }
385be2cdc5eSEmilio G. Cota     /*
386be2cdc5eSEmilio G. Cota      * All lookups have either .size field set to 0.
387be2cdc5eSEmilio G. Cota      * From the glib sources we see that @ap is always the lookup key. However
388be2cdc5eSEmilio G. Cota      * the docs provide no guarantee, so we just mark this case as likely.
389be2cdc5eSEmilio G. Cota      */
390be2cdc5eSEmilio G. Cota     if (likely(a->size == 0)) {
391be2cdc5eSEmilio G. Cota         return ptr_cmp_tb_tc(a->ptr, b);
392be2cdc5eSEmilio G. Cota     }
393be2cdc5eSEmilio G. Cota     return ptr_cmp_tb_tc(b->ptr, a);
394be2cdc5eSEmilio G. Cota }
395be2cdc5eSEmilio G. Cota 
396be2cdc5eSEmilio G. Cota static void tcg_region_trees_init(void)
397be2cdc5eSEmilio G. Cota {
398be2cdc5eSEmilio G. Cota     size_t i;
399be2cdc5eSEmilio G. Cota 
400be2cdc5eSEmilio G. Cota     tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize);
401be2cdc5eSEmilio G. Cota     region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size);
402be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
403be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
404be2cdc5eSEmilio G. Cota 
405be2cdc5eSEmilio G. Cota         qemu_mutex_init(&rt->lock);
406be2cdc5eSEmilio G. Cota         rt->tree = g_tree_new(tb_tc_cmp);
407be2cdc5eSEmilio G. Cota     }
408be2cdc5eSEmilio G. Cota }
409be2cdc5eSEmilio G. Cota 
410db0c51a3SRichard Henderson static struct tcg_region_tree *tc_ptr_to_region_tree(const void *cp)
411be2cdc5eSEmilio G. Cota {
412db0c51a3SRichard Henderson     void *p = tcg_splitwx_to_rw(cp);
413be2cdc5eSEmilio G. Cota     size_t region_idx;
414be2cdc5eSEmilio G. Cota 
415be2cdc5eSEmilio G. Cota     if (p < region.start_aligned) {
416be2cdc5eSEmilio G. Cota         region_idx = 0;
417be2cdc5eSEmilio G. Cota     } else {
418be2cdc5eSEmilio G. Cota         ptrdiff_t offset = p - region.start_aligned;
419be2cdc5eSEmilio G. Cota 
420be2cdc5eSEmilio G. Cota         if (offset > region.stride * (region.n - 1)) {
421be2cdc5eSEmilio G. Cota             region_idx = region.n - 1;
422be2cdc5eSEmilio G. Cota         } else {
423be2cdc5eSEmilio G. Cota             region_idx = offset / region.stride;
424be2cdc5eSEmilio G. Cota         }
425be2cdc5eSEmilio G. Cota     }
426be2cdc5eSEmilio G. Cota     return region_trees + region_idx * tree_size;
427be2cdc5eSEmilio G. Cota }
428be2cdc5eSEmilio G. Cota 
429be2cdc5eSEmilio G. Cota void tcg_tb_insert(TranslationBlock *tb)
430be2cdc5eSEmilio G. Cota {
431be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
432be2cdc5eSEmilio G. Cota 
433be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
434be2cdc5eSEmilio G. Cota     g_tree_insert(rt->tree, &tb->tc, tb);
435be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
436be2cdc5eSEmilio G. Cota }
437be2cdc5eSEmilio G. Cota 
438be2cdc5eSEmilio G. Cota void tcg_tb_remove(TranslationBlock *tb)
439be2cdc5eSEmilio G. Cota {
440be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
441be2cdc5eSEmilio G. Cota 
442be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
443be2cdc5eSEmilio G. Cota     g_tree_remove(rt->tree, &tb->tc);
444be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
445be2cdc5eSEmilio G. Cota }
446be2cdc5eSEmilio G. Cota 
447be2cdc5eSEmilio G. Cota /*
448be2cdc5eSEmilio G. Cota  * Find the TB 'tb' such that
449be2cdc5eSEmilio G. Cota  * tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size
450be2cdc5eSEmilio G. Cota  * Return NULL if not found.
451be2cdc5eSEmilio G. Cota  */
452be2cdc5eSEmilio G. Cota TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr)
453be2cdc5eSEmilio G. Cota {
454be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr);
455be2cdc5eSEmilio G. Cota     TranslationBlock *tb;
456be2cdc5eSEmilio G. Cota     struct tb_tc s = { .ptr = (void *)tc_ptr };
457be2cdc5eSEmilio G. Cota 
458be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
459be2cdc5eSEmilio G. Cota     tb = g_tree_lookup(rt->tree, &s);
460be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
461be2cdc5eSEmilio G. Cota     return tb;
462be2cdc5eSEmilio G. Cota }
463be2cdc5eSEmilio G. Cota 
464be2cdc5eSEmilio G. Cota static void tcg_region_tree_lock_all(void)
465be2cdc5eSEmilio G. Cota {
466be2cdc5eSEmilio G. Cota     size_t i;
467be2cdc5eSEmilio G. Cota 
468be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
469be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
470be2cdc5eSEmilio G. Cota 
471be2cdc5eSEmilio G. Cota         qemu_mutex_lock(&rt->lock);
472be2cdc5eSEmilio G. Cota     }
473be2cdc5eSEmilio G. Cota }
474be2cdc5eSEmilio G. Cota 
475be2cdc5eSEmilio G. Cota static void tcg_region_tree_unlock_all(void)
476be2cdc5eSEmilio G. Cota {
477be2cdc5eSEmilio G. Cota     size_t i;
478be2cdc5eSEmilio G. Cota 
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         qemu_mutex_unlock(&rt->lock);
483be2cdc5eSEmilio G. Cota     }
484be2cdc5eSEmilio G. Cota }
485be2cdc5eSEmilio G. Cota 
486be2cdc5eSEmilio G. Cota void tcg_tb_foreach(GTraverseFunc func, gpointer user_data)
487be2cdc5eSEmilio G. Cota {
488be2cdc5eSEmilio G. Cota     size_t i;
489be2cdc5eSEmilio G. Cota 
490be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
491be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
492be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
493be2cdc5eSEmilio G. Cota 
494be2cdc5eSEmilio G. Cota         g_tree_foreach(rt->tree, func, user_data);
495be2cdc5eSEmilio G. Cota     }
496be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
497be2cdc5eSEmilio G. Cota }
498be2cdc5eSEmilio G. Cota 
499be2cdc5eSEmilio G. Cota size_t tcg_nb_tbs(void)
500be2cdc5eSEmilio G. Cota {
501be2cdc5eSEmilio G. Cota     size_t nb_tbs = 0;
502be2cdc5eSEmilio G. Cota     size_t i;
503be2cdc5eSEmilio G. Cota 
504be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
505be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
506be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
507be2cdc5eSEmilio G. Cota 
508be2cdc5eSEmilio G. Cota         nb_tbs += g_tree_nnodes(rt->tree);
509be2cdc5eSEmilio G. Cota     }
510be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
511be2cdc5eSEmilio G. Cota     return nb_tbs;
512be2cdc5eSEmilio G. Cota }
513be2cdc5eSEmilio G. Cota 
514938e897aSEmilio G. Cota static gboolean tcg_region_tree_traverse(gpointer k, gpointer v, gpointer data)
515938e897aSEmilio G. Cota {
516938e897aSEmilio G. Cota     TranslationBlock *tb = v;
517938e897aSEmilio G. Cota 
518938e897aSEmilio G. Cota     tb_destroy(tb);
519938e897aSEmilio G. Cota     return FALSE;
520938e897aSEmilio G. Cota }
521938e897aSEmilio G. Cota 
522be2cdc5eSEmilio G. Cota static void tcg_region_tree_reset_all(void)
523be2cdc5eSEmilio G. Cota {
524be2cdc5eSEmilio G. Cota     size_t i;
525be2cdc5eSEmilio G. Cota 
526be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
527be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
528be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
529be2cdc5eSEmilio G. Cota 
530938e897aSEmilio G. Cota         g_tree_foreach(rt->tree, tcg_region_tree_traverse, NULL);
531be2cdc5eSEmilio G. Cota         /* Increment the refcount first so that destroy acts as a reset */
532be2cdc5eSEmilio G. Cota         g_tree_ref(rt->tree);
533be2cdc5eSEmilio G. Cota         g_tree_destroy(rt->tree);
534be2cdc5eSEmilio G. Cota     }
535be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
536be2cdc5eSEmilio G. Cota }
537be2cdc5eSEmilio G. Cota 
538e8feb96fSEmilio G. Cota static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend)
539e8feb96fSEmilio G. Cota {
540e8feb96fSEmilio G. Cota     void *start, *end;
541e8feb96fSEmilio G. Cota 
542e8feb96fSEmilio G. Cota     start = region.start_aligned + curr_region * region.stride;
543e8feb96fSEmilio G. Cota     end = start + region.size;
544e8feb96fSEmilio G. Cota 
545e8feb96fSEmilio G. Cota     if (curr_region == 0) {
546e8feb96fSEmilio G. Cota         start = region.start;
547e8feb96fSEmilio G. Cota     }
548e8feb96fSEmilio G. Cota     if (curr_region == region.n - 1) {
549e8feb96fSEmilio G. Cota         end = region.end;
550e8feb96fSEmilio G. Cota     }
551e8feb96fSEmilio G. Cota 
552e8feb96fSEmilio G. Cota     *pstart = start;
553e8feb96fSEmilio G. Cota     *pend = end;
554e8feb96fSEmilio G. Cota }
555e8feb96fSEmilio G. Cota 
556e8feb96fSEmilio G. Cota static void tcg_region_assign(TCGContext *s, size_t curr_region)
557e8feb96fSEmilio G. Cota {
558e8feb96fSEmilio G. Cota     void *start, *end;
559e8feb96fSEmilio G. Cota 
560e8feb96fSEmilio G. Cota     tcg_region_bounds(curr_region, &start, &end);
561e8feb96fSEmilio G. Cota 
562e8feb96fSEmilio G. Cota     s->code_gen_buffer = start;
563e8feb96fSEmilio G. Cota     s->code_gen_ptr = start;
564e8feb96fSEmilio G. Cota     s->code_gen_buffer_size = end - start;
565e8feb96fSEmilio G. Cota     s->code_gen_highwater = end - TCG_HIGHWATER;
566e8feb96fSEmilio G. Cota }
567e8feb96fSEmilio G. Cota 
568e8feb96fSEmilio G. Cota static bool tcg_region_alloc__locked(TCGContext *s)
569e8feb96fSEmilio G. Cota {
570e8feb96fSEmilio G. Cota     if (region.current == region.n) {
571e8feb96fSEmilio G. Cota         return true;
572e8feb96fSEmilio G. Cota     }
573e8feb96fSEmilio G. Cota     tcg_region_assign(s, region.current);
574e8feb96fSEmilio G. Cota     region.current++;
575e8feb96fSEmilio G. Cota     return false;
576e8feb96fSEmilio G. Cota }
577e8feb96fSEmilio G. Cota 
578e8feb96fSEmilio G. Cota /*
579e8feb96fSEmilio G. Cota  * Request a new region once the one in use has filled up.
580e8feb96fSEmilio G. Cota  * Returns true on error.
581e8feb96fSEmilio G. Cota  */
582e8feb96fSEmilio G. Cota static bool tcg_region_alloc(TCGContext *s)
583e8feb96fSEmilio G. Cota {
584e8feb96fSEmilio G. Cota     bool err;
585e8feb96fSEmilio G. Cota     /* read the region size now; alloc__locked will overwrite it on success */
586e8feb96fSEmilio G. Cota     size_t size_full = s->code_gen_buffer_size;
587e8feb96fSEmilio G. Cota 
588e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
589e8feb96fSEmilio G. Cota     err = tcg_region_alloc__locked(s);
590e8feb96fSEmilio G. Cota     if (!err) {
591e8feb96fSEmilio G. Cota         region.agg_size_full += size_full - TCG_HIGHWATER;
592e8feb96fSEmilio G. Cota     }
593e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
594e8feb96fSEmilio G. Cota     return err;
595e8feb96fSEmilio G. Cota }
596e8feb96fSEmilio G. Cota 
597e8feb96fSEmilio G. Cota /*
598e8feb96fSEmilio G. Cota  * Perform a context's first region allocation.
599e8feb96fSEmilio G. Cota  * This function does _not_ increment region.agg_size_full.
600e8feb96fSEmilio G. Cota  */
601e8feb96fSEmilio G. Cota static inline bool tcg_region_initial_alloc__locked(TCGContext *s)
602e8feb96fSEmilio G. Cota {
603e8feb96fSEmilio G. Cota     return tcg_region_alloc__locked(s);
604e8feb96fSEmilio G. Cota }
605e8feb96fSEmilio G. Cota 
606e8feb96fSEmilio G. Cota /* Call from a safe-work context */
607e8feb96fSEmilio G. Cota void tcg_region_reset_all(void)
608e8feb96fSEmilio G. Cota {
609d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
610e8feb96fSEmilio G. Cota     unsigned int i;
611e8feb96fSEmilio G. Cota 
612e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
613e8feb96fSEmilio G. Cota     region.current = 0;
614e8feb96fSEmilio G. Cota     region.agg_size_full = 0;
615e8feb96fSEmilio G. Cota 
6163468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
617d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
6183468b59eSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(s);
619e8feb96fSEmilio G. Cota 
620e8feb96fSEmilio G. Cota         g_assert(!err);
621e8feb96fSEmilio G. Cota     }
622e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
623be2cdc5eSEmilio G. Cota 
624be2cdc5eSEmilio G. Cota     tcg_region_tree_reset_all();
625e8feb96fSEmilio G. Cota }
626e8feb96fSEmilio G. Cota 
6273468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
6283468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
6293468b59eSEmilio G. Cota {
6303468b59eSEmilio G. Cota     return 1;
6313468b59eSEmilio G. Cota }
6323468b59eSEmilio G. Cota #else
6333468b59eSEmilio G. Cota /*
6343468b59eSEmilio G. Cota  * It is likely that some vCPUs will translate more code than others, so we
6353468b59eSEmilio G. Cota  * first try to set more regions than max_cpus, with those regions being of
6363468b59eSEmilio G. Cota  * reasonable size. If that's not possible we make do by evenly dividing
6373468b59eSEmilio G. Cota  * the code_gen_buffer among the vCPUs.
6383468b59eSEmilio G. Cota  */
6393468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
6403468b59eSEmilio G. Cota {
6413468b59eSEmilio G. Cota     size_t i;
6423468b59eSEmilio G. Cota 
6433468b59eSEmilio G. Cota     /* Use a single region if all we have is one vCPU thread */
6445cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY)
6455cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
6465cc8767dSLike Xu     unsigned int max_cpus = ms->smp.max_cpus;
6475cc8767dSLike Xu #endif
6483468b59eSEmilio G. Cota     if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) {
6493468b59eSEmilio G. Cota         return 1;
6503468b59eSEmilio G. Cota     }
6513468b59eSEmilio G. Cota 
6523468b59eSEmilio G. Cota     /* Try to have more regions than max_cpus, with each region being >= 2 MB */
6533468b59eSEmilio G. Cota     for (i = 8; i > 0; i--) {
6543468b59eSEmilio G. Cota         size_t regions_per_thread = i;
6553468b59eSEmilio G. Cota         size_t region_size;
6563468b59eSEmilio G. Cota 
6573468b59eSEmilio G. Cota         region_size = tcg_init_ctx.code_gen_buffer_size;
6583468b59eSEmilio G. Cota         region_size /= max_cpus * regions_per_thread;
6593468b59eSEmilio G. Cota 
6603468b59eSEmilio G. Cota         if (region_size >= 2 * 1024u * 1024) {
6613468b59eSEmilio G. Cota             return max_cpus * regions_per_thread;
6623468b59eSEmilio G. Cota         }
6633468b59eSEmilio G. Cota     }
6643468b59eSEmilio G. Cota     /* If we can't, then just allocate one region per vCPU thread */
6653468b59eSEmilio G. Cota     return max_cpus;
6663468b59eSEmilio G. Cota }
6673468b59eSEmilio G. Cota #endif
6683468b59eSEmilio G. Cota 
669e8feb96fSEmilio G. Cota /*
670e8feb96fSEmilio G. Cota  * Initializes region partitioning.
671e8feb96fSEmilio G. Cota  *
672e8feb96fSEmilio G. Cota  * Called at init time from the parent thread (i.e. the one calling
673e8feb96fSEmilio G. Cota  * tcg_context_init), after the target's TCG globals have been set.
6743468b59eSEmilio G. Cota  *
6753468b59eSEmilio G. Cota  * Region partitioning works by splitting code_gen_buffer into separate regions,
6763468b59eSEmilio G. Cota  * and then assigning regions to TCG threads so that the threads can translate
6773468b59eSEmilio G. Cota  * code in parallel without synchronization.
6783468b59eSEmilio G. Cota  *
6793468b59eSEmilio G. Cota  * In softmmu the number of TCG threads is bounded by max_cpus, so we use at
6803468b59eSEmilio G. Cota  * least max_cpus regions in MTTCG. In !MTTCG we use a single region.
6813468b59eSEmilio G. Cota  * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...])
6823468b59eSEmilio G. Cota  * must have been parsed before calling this function, since it calls
6833468b59eSEmilio G. Cota  * qemu_tcg_mttcg_enabled().
6843468b59eSEmilio G. Cota  *
6853468b59eSEmilio G. Cota  * In user-mode we use a single region.  Having multiple regions in user-mode
6863468b59eSEmilio G. Cota  * is not supported, because the number of vCPU threads (recall that each thread
6873468b59eSEmilio G. Cota  * spawned by the guest corresponds to a vCPU thread) is only bounded by the
6883468b59eSEmilio G. Cota  * OS, and usually this number is huge (tens of thousands is not uncommon).
6893468b59eSEmilio G. Cota  * Thus, given this large bound on the number of vCPU threads and the fact
6903468b59eSEmilio G. Cota  * that code_gen_buffer is allocated at compile-time, we cannot guarantee
6913468b59eSEmilio G. Cota  * that the availability of at least one region per vCPU thread.
6923468b59eSEmilio G. Cota  *
6933468b59eSEmilio G. Cota  * However, this user-mode limitation is unlikely to be a significant problem
6943468b59eSEmilio G. Cota  * in practice. Multi-threaded guests share most if not all of their translated
6953468b59eSEmilio G. Cota  * code, which makes parallel code generation less appealing than in softmmu.
696e8feb96fSEmilio G. Cota  */
697e8feb96fSEmilio G. Cota void tcg_region_init(void)
698e8feb96fSEmilio G. Cota {
699e8feb96fSEmilio G. Cota     void *buf = tcg_init_ctx.code_gen_buffer;
700e8feb96fSEmilio G. Cota     void *aligned;
701e8feb96fSEmilio G. Cota     size_t size = tcg_init_ctx.code_gen_buffer_size;
702e8feb96fSEmilio G. Cota     size_t page_size = qemu_real_host_page_size;
703e8feb96fSEmilio G. Cota     size_t region_size;
704e8feb96fSEmilio G. Cota     size_t n_regions;
705e8feb96fSEmilio G. Cota     size_t i;
706db0c51a3SRichard Henderson     uintptr_t splitwx_diff;
707e8feb96fSEmilio G. Cota 
7083468b59eSEmilio G. Cota     n_regions = tcg_n_regions();
709e8feb96fSEmilio G. Cota 
710e8feb96fSEmilio G. Cota     /* The first region will be 'aligned - buf' bytes larger than the others */
711e8feb96fSEmilio G. Cota     aligned = QEMU_ALIGN_PTR_UP(buf, page_size);
712e8feb96fSEmilio G. Cota     g_assert(aligned < tcg_init_ctx.code_gen_buffer + size);
713e8feb96fSEmilio G. Cota     /*
714e8feb96fSEmilio G. Cota      * Make region_size a multiple of page_size, using aligned as the start.
715e8feb96fSEmilio G. Cota      * As a result of this we might end up with a few extra pages at the end of
716e8feb96fSEmilio G. Cota      * the buffer; we will assign those to the last region.
717e8feb96fSEmilio G. Cota      */
718e8feb96fSEmilio G. Cota     region_size = (size - (aligned - buf)) / n_regions;
719e8feb96fSEmilio G. Cota     region_size = QEMU_ALIGN_DOWN(region_size, page_size);
720e8feb96fSEmilio G. Cota 
721e8feb96fSEmilio G. Cota     /* A region must have at least 2 pages; one code, one guard */
722e8feb96fSEmilio G. Cota     g_assert(region_size >= 2 * page_size);
723e8feb96fSEmilio G. Cota 
724e8feb96fSEmilio G. Cota     /* init the region struct */
725e8feb96fSEmilio G. Cota     qemu_mutex_init(&region.lock);
726e8feb96fSEmilio G. Cota     region.n = n_regions;
727e8feb96fSEmilio G. Cota     region.size = region_size - page_size;
728e8feb96fSEmilio G. Cota     region.stride = region_size;
729e8feb96fSEmilio G. Cota     region.start = buf;
730e8feb96fSEmilio G. Cota     region.start_aligned = aligned;
731e8feb96fSEmilio G. Cota     /* page-align the end, since its last page will be a guard page */
732e8feb96fSEmilio G. Cota     region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size);
733e8feb96fSEmilio G. Cota     /* account for that last guard page */
734e8feb96fSEmilio G. Cota     region.end -= page_size;
735e8feb96fSEmilio G. Cota 
736e8feb96fSEmilio G. Cota     /* set guard pages */
737db0c51a3SRichard Henderson     splitwx_diff = tcg_splitwx_diff;
738e8feb96fSEmilio G. Cota     for (i = 0; i < region.n; i++) {
739e8feb96fSEmilio G. Cota         void *start, *end;
740e8feb96fSEmilio G. Cota         int rc;
741e8feb96fSEmilio G. Cota 
742e8feb96fSEmilio G. Cota         tcg_region_bounds(i, &start, &end);
743e8feb96fSEmilio G. Cota         rc = qemu_mprotect_none(end, page_size);
744e8feb96fSEmilio G. Cota         g_assert(!rc);
745db0c51a3SRichard Henderson         if (splitwx_diff) {
746db0c51a3SRichard Henderson             rc = qemu_mprotect_none(end + splitwx_diff, page_size);
747db0c51a3SRichard Henderson             g_assert(!rc);
748db0c51a3SRichard Henderson         }
749e8feb96fSEmilio G. Cota     }
750e8feb96fSEmilio G. Cota 
751be2cdc5eSEmilio G. Cota     tcg_region_trees_init();
752be2cdc5eSEmilio G. Cota 
7533468b59eSEmilio G. Cota     /* In user-mode we support only one ctx, so do the initial allocation now */
7543468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
755e8feb96fSEmilio G. Cota     {
756e8feb96fSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(tcg_ctx);
757e8feb96fSEmilio G. Cota 
758e8feb96fSEmilio G. Cota         g_assert(!err);
759e8feb96fSEmilio G. Cota     }
7603468b59eSEmilio G. Cota #endif
761e8feb96fSEmilio G. Cota }
762e8feb96fSEmilio G. Cota 
763db0c51a3SRichard Henderson #ifdef CONFIG_DEBUG_TCG
764db0c51a3SRichard Henderson const void *tcg_splitwx_to_rx(void *rw)
765db0c51a3SRichard Henderson {
766db0c51a3SRichard Henderson     /* Pass NULL pointers unchanged. */
767db0c51a3SRichard Henderson     if (rw) {
768db0c51a3SRichard Henderson         g_assert(in_code_gen_buffer(rw));
769db0c51a3SRichard Henderson         rw += tcg_splitwx_diff;
770db0c51a3SRichard Henderson     }
771db0c51a3SRichard Henderson     return rw;
772db0c51a3SRichard Henderson }
773db0c51a3SRichard Henderson 
774db0c51a3SRichard Henderson void *tcg_splitwx_to_rw(const void *rx)
775db0c51a3SRichard Henderson {
776db0c51a3SRichard Henderson     /* Pass NULL pointers unchanged. */
777db0c51a3SRichard Henderson     if (rx) {
778db0c51a3SRichard Henderson         rx -= tcg_splitwx_diff;
779db0c51a3SRichard Henderson         /* Assert that we end with a pointer in the rw region. */
780db0c51a3SRichard Henderson         g_assert(in_code_gen_buffer(rx));
781db0c51a3SRichard Henderson     }
782db0c51a3SRichard Henderson     return (void *)rx;
783db0c51a3SRichard Henderson }
784db0c51a3SRichard Henderson #endif /* CONFIG_DEBUG_TCG */
785db0c51a3SRichard Henderson 
78638b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s)
78738b47b19SEmilio G. Cota {
78838b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
78938b47b19SEmilio G. Cota     s->plugin_tb = g_new0(struct qemu_plugin_tb, 1);
79038b47b19SEmilio G. Cota     s->plugin_tb->insns =
79138b47b19SEmilio G. Cota         g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn);
79238b47b19SEmilio G. Cota #endif
79338b47b19SEmilio G. Cota }
79438b47b19SEmilio G. Cota 
795e8feb96fSEmilio G. Cota /*
7963468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
7973468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
7983468b59eSEmilio G. Cota  * before initiating translation.
7993468b59eSEmilio G. Cota  *
8003468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
8013468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
8023468b59eSEmilio G. Cota  *
8033468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
8043468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
8053468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
8063468b59eSEmilio G. Cota  *
8073468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
8083468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
8093468b59eSEmilio G. Cota  */
8103468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
8113468b59eSEmilio G. Cota void tcg_register_thread(void)
8123468b59eSEmilio G. Cota {
8133468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
8143468b59eSEmilio G. Cota }
8153468b59eSEmilio G. Cota #else
8163468b59eSEmilio G. Cota void tcg_register_thread(void)
8173468b59eSEmilio G. Cota {
8185cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
8193468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
8203468b59eSEmilio G. Cota     unsigned int i, n;
8213468b59eSEmilio G. Cota     bool err;
8223468b59eSEmilio G. Cota 
8233468b59eSEmilio G. Cota     *s = tcg_init_ctx;
8243468b59eSEmilio G. Cota 
8253468b59eSEmilio G. Cota     /* Relink mem_base.  */
8263468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
8273468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
8283468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
8293468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
8303468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
8313468b59eSEmilio G. Cota         }
8323468b59eSEmilio G. Cota     }
8333468b59eSEmilio G. Cota 
8343468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
835d73415a3SStefan Hajnoczi     n = qatomic_fetch_inc(&n_tcg_ctxs);
8365cc8767dSLike Xu     g_assert(n < ms->smp.max_cpus);
837d73415a3SStefan Hajnoczi     qatomic_set(&tcg_ctxs[n], s);
8383468b59eSEmilio G. Cota 
83938b47b19SEmilio G. Cota     if (n > 0) {
84038b47b19SEmilio G. Cota         alloc_tcg_plugin_context(s);
84138b47b19SEmilio G. Cota     }
84238b47b19SEmilio G. Cota 
8433468b59eSEmilio G. Cota     tcg_ctx = s;
8443468b59eSEmilio G. Cota     qemu_mutex_lock(&region.lock);
8453468b59eSEmilio G. Cota     err = tcg_region_initial_alloc__locked(tcg_ctx);
8463468b59eSEmilio G. Cota     g_assert(!err);
8473468b59eSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
8483468b59eSEmilio G. Cota }
8493468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
8503468b59eSEmilio G. Cota 
8513468b59eSEmilio G. Cota /*
852e8feb96fSEmilio G. Cota  * Returns the size (in bytes) of all translated code (i.e. from all regions)
853e8feb96fSEmilio G. Cota  * currently in the cache.
854e8feb96fSEmilio G. Cota  * See also: tcg_code_capacity()
855e8feb96fSEmilio G. Cota  * Do not confuse with tcg_current_code_size(); that one applies to a single
856e8feb96fSEmilio G. Cota  * TCG context.
857e8feb96fSEmilio G. Cota  */
858e8feb96fSEmilio G. Cota size_t tcg_code_size(void)
859e8feb96fSEmilio G. Cota {
860d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
861e8feb96fSEmilio G. Cota     unsigned int i;
862e8feb96fSEmilio G. Cota     size_t total;
863e8feb96fSEmilio G. Cota 
864e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
865e8feb96fSEmilio G. Cota     total = region.agg_size_full;
8663468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
867d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
868e8feb96fSEmilio G. Cota         size_t size;
869e8feb96fSEmilio G. Cota 
870d73415a3SStefan Hajnoczi         size = qatomic_read(&s->code_gen_ptr) - s->code_gen_buffer;
871e8feb96fSEmilio G. Cota         g_assert(size <= s->code_gen_buffer_size);
872e8feb96fSEmilio G. Cota         total += size;
873e8feb96fSEmilio G. Cota     }
874e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
875e8feb96fSEmilio G. Cota     return total;
876e8feb96fSEmilio G. Cota }
877e8feb96fSEmilio G. Cota 
878e8feb96fSEmilio G. Cota /*
879e8feb96fSEmilio G. Cota  * Returns the code capacity (in bytes) of the entire cache, i.e. including all
880e8feb96fSEmilio G. Cota  * regions.
881e8feb96fSEmilio G. Cota  * See also: tcg_code_size()
882e8feb96fSEmilio G. Cota  */
883e8feb96fSEmilio G. Cota size_t tcg_code_capacity(void)
884e8feb96fSEmilio G. Cota {
885e8feb96fSEmilio G. Cota     size_t guard_size, capacity;
886e8feb96fSEmilio G. Cota 
887e8feb96fSEmilio G. Cota     /* no need for synchronization; these variables are set at init time */
888e8feb96fSEmilio G. Cota     guard_size = region.stride - region.size;
889e8feb96fSEmilio G. Cota     capacity = region.end + guard_size - region.start;
890e8feb96fSEmilio G. Cota     capacity -= region.n * (guard_size + TCG_HIGHWATER);
891e8feb96fSEmilio G. Cota     return capacity;
892e8feb96fSEmilio G. Cota }
893e8feb96fSEmilio G. Cota 
894128ed227SEmilio G. Cota size_t tcg_tb_phys_invalidate_count(void)
895128ed227SEmilio G. Cota {
896d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
897128ed227SEmilio G. Cota     unsigned int i;
898128ed227SEmilio G. Cota     size_t total = 0;
899128ed227SEmilio G. Cota 
900128ed227SEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
901d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
902128ed227SEmilio G. Cota 
903d73415a3SStefan Hajnoczi         total += qatomic_read(&s->tb_phys_invalidate_count);
904128ed227SEmilio G. Cota     }
905128ed227SEmilio G. Cota     return total;
906128ed227SEmilio G. Cota }
907128ed227SEmilio G. Cota 
908c896fe29Sbellard /* pool based memory allocation */
909c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
910c896fe29Sbellard {
911c896fe29Sbellard     TCGPool *p;
912c896fe29Sbellard     int pool_size;
913c896fe29Sbellard 
914c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
915c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
9167267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
917c896fe29Sbellard         p->size = size;
9184055299eSKirill Batuzov         p->next = s->pool_first_large;
9194055299eSKirill Batuzov         s->pool_first_large = p;
9204055299eSKirill Batuzov         return p->data;
921c896fe29Sbellard     } else {
922c896fe29Sbellard         p = s->pool_current;
923c896fe29Sbellard         if (!p) {
924c896fe29Sbellard             p = s->pool_first;
925c896fe29Sbellard             if (!p)
926c896fe29Sbellard                 goto new_pool;
927c896fe29Sbellard         } else {
928c896fe29Sbellard             if (!p->next) {
929c896fe29Sbellard             new_pool:
930c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
9317267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
932c896fe29Sbellard                 p->size = pool_size;
933c896fe29Sbellard                 p->next = NULL;
934c896fe29Sbellard                 if (s->pool_current)
935c896fe29Sbellard                     s->pool_current->next = p;
936c896fe29Sbellard                 else
937c896fe29Sbellard                     s->pool_first = p;
938c896fe29Sbellard             } else {
939c896fe29Sbellard                 p = p->next;
940c896fe29Sbellard             }
941c896fe29Sbellard         }
942c896fe29Sbellard     }
943c896fe29Sbellard     s->pool_current = p;
944c896fe29Sbellard     s->pool_cur = p->data + size;
945c896fe29Sbellard     s->pool_end = p->data + p->size;
946c896fe29Sbellard     return p->data;
947c896fe29Sbellard }
948c896fe29Sbellard 
949c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
950c896fe29Sbellard {
9514055299eSKirill Batuzov     TCGPool *p, *t;
9524055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
9534055299eSKirill Batuzov         t = p->next;
9544055299eSKirill Batuzov         g_free(p);
9554055299eSKirill Batuzov     }
9564055299eSKirill Batuzov     s->pool_first_large = NULL;
957c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
958c896fe29Sbellard     s->pool_current = NULL;
959c896fe29Sbellard }
960c896fe29Sbellard 
961100b5e01SRichard Henderson typedef struct TCGHelperInfo {
962100b5e01SRichard Henderson     void *func;
963100b5e01SRichard Henderson     const char *name;
964afb49896SRichard Henderson     unsigned flags;
965afb49896SRichard Henderson     unsigned sizemask;
966100b5e01SRichard Henderson } TCGHelperInfo;
967100b5e01SRichard Henderson 
9682ef6175aSRichard Henderson #include "exec/helper-proto.h"
9692ef6175aSRichard Henderson 
970100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = {
9712ef6175aSRichard Henderson #include "exec/helper-tcg.h"
972100b5e01SRichard Henderson };
973619205fdSEmilio G. Cota static GHashTable *helper_table;
974100b5e01SRichard Henderson 
97591478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
976f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
9771c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
9781c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
97991478cefSRichard Henderson 
980c896fe29Sbellard void tcg_context_init(TCGContext *s)
981c896fe29Sbellard {
982100b5e01SRichard Henderson     int op, total_args, n, i;
983c896fe29Sbellard     TCGOpDef *def;
984c896fe29Sbellard     TCGArgConstraint *args_ct;
9851c2adb95SRichard Henderson     TCGTemp *ts;
986c896fe29Sbellard 
987c896fe29Sbellard     memset(s, 0, sizeof(*s));
988c896fe29Sbellard     s->nb_globals = 0;
989c896fe29Sbellard 
990c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
991c896fe29Sbellard        space */
992c896fe29Sbellard     total_args = 0;
993c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
994c896fe29Sbellard         def = &tcg_op_defs[op];
995c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
996c896fe29Sbellard         total_args += n;
997c896fe29Sbellard     }
998c896fe29Sbellard 
999bc2b17e6SRichard Henderson     args_ct = g_new0(TCGArgConstraint, total_args);
1000c896fe29Sbellard 
1001c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
1002c896fe29Sbellard         def = &tcg_op_defs[op];
1003c896fe29Sbellard         def->args_ct = args_ct;
1004c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
1005c896fe29Sbellard         args_ct += n;
1006c896fe29Sbellard     }
1007c896fe29Sbellard 
10085cd8f621SRichard Henderson     /* Register helpers.  */
100984fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
1010619205fdSEmilio G. Cota     helper_table = g_hash_table_new(NULL, NULL);
101184fd9dd3SRichard Henderson 
1012100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
101384fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
101472866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
1015100b5e01SRichard Henderson     }
10165cd8f621SRichard Henderson 
1017c896fe29Sbellard     tcg_target_init(s);
1018f69d277eSRichard Henderson     process_op_defs(s);
101991478cefSRichard Henderson 
102091478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
102191478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
102291478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
102391478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
102491478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
102591478cefSRichard Henderson             break;
102691478cefSRichard Henderson         }
102791478cefSRichard Henderson     }
102891478cefSRichard Henderson     for (i = 0; i < n; ++i) {
102991478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
103091478cefSRichard Henderson     }
103191478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
103291478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
103391478cefSRichard Henderson     }
1034b1311c4aSEmilio G. Cota 
103538b47b19SEmilio G. Cota     alloc_tcg_plugin_context(s);
103638b47b19SEmilio G. Cota 
1037b1311c4aSEmilio G. Cota     tcg_ctx = s;
10383468b59eSEmilio G. Cota     /*
10393468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
10403468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
10413468b59eSEmilio G. Cota      * reasoning behind this.
10423468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
10433468b59eSEmilio G. Cota      */
10443468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
1045df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
1046df2cce29SEmilio G. Cota     n_tcg_ctxs = 1;
10473468b59eSEmilio G. Cota #else
10485cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
10495cc8767dSLike Xu     unsigned int max_cpus = ms->smp.max_cpus;
10503468b59eSEmilio G. Cota     tcg_ctxs = g_new(TCGContext *, max_cpus);
10513468b59eSEmilio G. Cota #endif
10521c2adb95SRichard Henderson 
10531c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
10541c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
10551c2adb95SRichard Henderson     cpu_env = temp_tcgv_ptr(ts);
10569002ec79SRichard Henderson }
1057b03cce8eSbellard 
10586e3b2bfdSEmilio G. Cota /*
10596e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
10606e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
10616e3b2bfdSEmilio G. Cota  */
10626e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
10636e3b2bfdSEmilio G. Cota {
10646e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
10656e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
10666e3b2bfdSEmilio G. Cota     void *next;
10676e3b2bfdSEmilio G. Cota 
1068e8feb96fSEmilio G. Cota  retry:
10696e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
10706e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
10716e3b2bfdSEmilio G. Cota 
10726e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
1073e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
10746e3b2bfdSEmilio G. Cota             return NULL;
10756e3b2bfdSEmilio G. Cota         }
1076e8feb96fSEmilio G. Cota         goto retry;
1077e8feb96fSEmilio G. Cota     }
1078d73415a3SStefan Hajnoczi     qatomic_set(&s->code_gen_ptr, next);
107957a26946SRichard Henderson     s->data_gen_ptr = NULL;
10806e3b2bfdSEmilio G. Cota     return tb;
10816e3b2bfdSEmilio G. Cota }
10826e3b2bfdSEmilio G. Cota 
10839002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
10849002ec79SRichard Henderson {
10858163b749SRichard Henderson     size_t prologue_size, total_size;
10868163b749SRichard Henderson     void *buf0, *buf1;
10878163b749SRichard Henderson 
10888163b749SRichard Henderson     /* Put the prologue at the beginning of code_gen_buffer.  */
10898163b749SRichard Henderson     buf0 = s->code_gen_buffer;
10905b38ee31SRichard Henderson     total_size = s->code_gen_buffer_size;
10918163b749SRichard Henderson     s->code_ptr = buf0;
10928163b749SRichard Henderson     s->code_buf = buf0;
10935b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
1094b91ccb31SRichard Henderson 
1095db0c51a3SRichard Henderson     /*
1096db0c51a3SRichard Henderson      * The region trees are not yet configured, but tcg_splitwx_to_rx
1097db0c51a3SRichard Henderson      * needs the bounds for an assert.
1098db0c51a3SRichard Henderson      */
1099db0c51a3SRichard Henderson     region.start = buf0;
1100db0c51a3SRichard Henderson     region.end = buf0 + total_size;
1101db0c51a3SRichard Henderson 
1102b91ccb31SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1103db0c51a3SRichard Henderson     tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(buf0);
1104b91ccb31SRichard Henderson #endif
11058163b749SRichard Henderson 
11065b38ee31SRichard Henderson     /* Compute a high-water mark, at which we voluntarily flush the buffer
11075b38ee31SRichard Henderson        and start over.  The size here is arbitrary, significantly larger
11085b38ee31SRichard Henderson        than we expect the code generation for any one opcode to require.  */
11095b38ee31SRichard Henderson     s->code_gen_highwater = s->code_gen_buffer + (total_size - TCG_HIGHWATER);
11105b38ee31SRichard Henderson 
11115b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
11125b38ee31SRichard Henderson     s->pool_labels = NULL;
11135b38ee31SRichard Henderson #endif
11145b38ee31SRichard Henderson 
11158163b749SRichard Henderson     /* Generate the prologue.  */
1116b03cce8eSbellard     tcg_target_qemu_prologue(s);
11175b38ee31SRichard Henderson 
11185b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
11195b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
11205b38ee31SRichard Henderson     {
11211768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
11221768987bSRichard Henderson         tcg_debug_assert(result == 0);
11235b38ee31SRichard Henderson     }
11245b38ee31SRichard Henderson #endif
11255b38ee31SRichard Henderson 
11268163b749SRichard Henderson     buf1 = s->code_ptr;
1127df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
1128db0c51a3SRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(buf0), (uintptr_t)buf0,
11291da8de39SRichard Henderson                         tcg_ptr_byte_diff(buf1, buf0));
1130df5d2b16SRichard Henderson #endif
11318163b749SRichard Henderson 
11328163b749SRichard Henderson     /* Deduct the prologue from the buffer.  */
11338163b749SRichard Henderson     prologue_size = tcg_current_code_size(s);
11348163b749SRichard Henderson     s->code_gen_ptr = buf1;
11358163b749SRichard Henderson     s->code_gen_buffer = buf1;
11368163b749SRichard Henderson     s->code_buf = buf1;
11375b38ee31SRichard Henderson     total_size -= prologue_size;
11388163b749SRichard Henderson     s->code_gen_buffer_size = total_size;
11398163b749SRichard Henderson 
1140755bf9e5SRichard Henderson     tcg_register_jit(tcg_splitwx_to_rx(s->code_gen_buffer), total_size);
1141d6b64b2bSRichard Henderson 
1142d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
1143d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
1144fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
11458163b749SRichard Henderson         qemu_log("PROLOGUE: [size=%zu]\n", prologue_size);
11465b38ee31SRichard Henderson         if (s->data_gen_ptr) {
11475b38ee31SRichard Henderson             size_t code_size = s->data_gen_ptr - buf0;
11485b38ee31SRichard Henderson             size_t data_size = prologue_size - code_size;
11495b38ee31SRichard Henderson             size_t i;
11505b38ee31SRichard Henderson 
11514c389f6eSRichard Henderson             log_disas(buf0, code_size);
11525b38ee31SRichard Henderson 
11535b38ee31SRichard Henderson             for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
11545b38ee31SRichard Henderson                 if (sizeof(tcg_target_ulong) == 8) {
11555b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
11565b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
11575b38ee31SRichard Henderson                              *(uint64_t *)(s->data_gen_ptr + i));
11585b38ee31SRichard Henderson                 } else {
11595b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .long  0x%08x\n",
11605b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
11615b38ee31SRichard Henderson                              *(uint32_t *)(s->data_gen_ptr + i));
11625b38ee31SRichard Henderson                 }
11635b38ee31SRichard Henderson             }
11645b38ee31SRichard Henderson         } else {
11654c389f6eSRichard Henderson             log_disas(buf0, prologue_size);
11665b38ee31SRichard Henderson         }
1167d6b64b2bSRichard Henderson         qemu_log("\n");
1168d6b64b2bSRichard Henderson         qemu_log_flush();
1169fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
1170d6b64b2bSRichard Henderson     }
1171d6b64b2bSRichard Henderson #endif
1172cedbcb01SEmilio G. Cota 
1173cedbcb01SEmilio G. Cota     /* Assert that goto_ptr is implemented completely.  */
1174cedbcb01SEmilio G. Cota     if (TCG_TARGET_HAS_goto_ptr) {
11758b5c2b62SRichard Henderson         tcg_debug_assert(tcg_code_gen_epilogue != NULL);
1176cedbcb01SEmilio G. Cota     }
1177c896fe29Sbellard }
1178c896fe29Sbellard 
1179c896fe29Sbellard void tcg_func_start(TCGContext *s)
1180c896fe29Sbellard {
1181c896fe29Sbellard     tcg_pool_reset(s);
1182c896fe29Sbellard     s->nb_temps = s->nb_globals;
11830ec9eabcSRichard Henderson 
11840ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
11850ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
11860ec9eabcSRichard Henderson 
1187abebf925SRichard Henderson     s->nb_ops = 0;
1188c896fe29Sbellard     s->nb_labels = 0;
1189c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1190c896fe29Sbellard 
11910a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
11920a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
11930a209d4bSRichard Henderson #endif
11940a209d4bSRichard Henderson 
119515fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
119615fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
1197bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
1198c896fe29Sbellard }
1199c896fe29Sbellard 
12007ca4b752SRichard Henderson static inline TCGTemp *tcg_temp_alloc(TCGContext *s)
12017ca4b752SRichard Henderson {
12027ca4b752SRichard Henderson     int n = s->nb_temps++;
12037ca4b752SRichard Henderson     tcg_debug_assert(n < TCG_MAX_TEMPS);
12047ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
12057ca4b752SRichard Henderson }
12067ca4b752SRichard Henderson 
12077ca4b752SRichard Henderson static inline TCGTemp *tcg_global_alloc(TCGContext *s)
12087ca4b752SRichard Henderson {
1209fa477d25SRichard Henderson     TCGTemp *ts;
1210fa477d25SRichard Henderson 
12117ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
12127ca4b752SRichard Henderson     s->nb_globals++;
1213fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1214ee17db83SRichard Henderson     ts->kind = TEMP_GLOBAL;
1215fa477d25SRichard Henderson 
1216fa477d25SRichard Henderson     return ts;
1217c896fe29Sbellard }
1218c896fe29Sbellard 
1219085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1220b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1221c896fe29Sbellard {
1222c896fe29Sbellard     TCGTemp *ts;
1223c896fe29Sbellard 
1224b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
1225c896fe29Sbellard         tcg_abort();
1226b3a62939SRichard Henderson     }
12277ca4b752SRichard Henderson 
12287ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1229c896fe29Sbellard     ts->base_type = type;
1230c896fe29Sbellard     ts->type = type;
1231ee17db83SRichard Henderson     ts->kind = TEMP_FIXED;
1232c896fe29Sbellard     ts->reg = reg;
1233c896fe29Sbellard     ts->name = name;
1234c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
12357ca4b752SRichard Henderson 
1236085272b3SRichard Henderson     return ts;
1237a7812ae4Spbrook }
1238a7812ae4Spbrook 
1239b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1240a7812ae4Spbrook {
1241b3a62939SRichard Henderson     s->frame_start = start;
1242b3a62939SRichard Henderson     s->frame_end = start + size;
1243085272b3SRichard Henderson     s->frame_temp
1244085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1245b3a62939SRichard Henderson }
1246a7812ae4Spbrook 
1247085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
1248e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
1249c896fe29Sbellard {
1250b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1251dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
12527ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1253b3915dbbSRichard Henderson     int indirect_reg = 0, bigendian = 0;
12547ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
12557ca4b752SRichard Henderson     bigendian = 1;
12567ca4b752SRichard Henderson #endif
1257c896fe29Sbellard 
1258ee17db83SRichard Henderson     if (base_ts->kind != TEMP_FIXED) {
12595a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
12605a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1261b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
12625a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
12635a18407fSRichard Henderson                             ? 2 : 1);
12645a18407fSRichard Henderson         indirect_reg = 1;
1265b3915dbbSRichard Henderson     }
1266b3915dbbSRichard Henderson 
12677ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
12687ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1269c896fe29Sbellard         char buf[64];
12707ca4b752SRichard Henderson 
12717ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1272c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1273b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1274c896fe29Sbellard         ts->mem_allocated = 1;
1275b3a62939SRichard Henderson         ts->mem_base = base_ts;
12767ca4b752SRichard Henderson         ts->mem_offset = offset + bigendian * 4;
1277c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1278c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1279c896fe29Sbellard         ts->name = strdup(buf);
1280c896fe29Sbellard 
12817ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
12827ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
12837ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1284b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
12857ca4b752SRichard Henderson         ts2->mem_allocated = 1;
12867ca4b752SRichard Henderson         ts2->mem_base = base_ts;
12877ca4b752SRichard Henderson         ts2->mem_offset = offset + (1 - bigendian) * 4;
1288c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1289c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1290120c1084SRichard Henderson         ts2->name = strdup(buf);
12917ca4b752SRichard Henderson     } else {
1292c896fe29Sbellard         ts->base_type = type;
1293c896fe29Sbellard         ts->type = type;
1294b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1295c896fe29Sbellard         ts->mem_allocated = 1;
1296b3a62939SRichard Henderson         ts->mem_base = base_ts;
1297c896fe29Sbellard         ts->mem_offset = offset;
1298c896fe29Sbellard         ts->name = name;
1299c896fe29Sbellard     }
1300085272b3SRichard Henderson     return ts;
1301c896fe29Sbellard }
1302c896fe29Sbellard 
13035bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local)
1304c896fe29Sbellard {
1305b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1306ee17db83SRichard Henderson     TCGTempKind kind = temp_local ? TEMP_LOCAL : TEMP_NORMAL;
1307c896fe29Sbellard     TCGTemp *ts;
1308641d5fbeSbellard     int idx, k;
1309c896fe29Sbellard 
13100ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
13110ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
13120ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
13130ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
13140ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
13150ec9eabcSRichard Henderson 
1316e8996ee0Sbellard         ts = &s->temps[idx];
1317e8996ee0Sbellard         ts->temp_allocated = 1;
13187ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
1319ee17db83SRichard Henderson         tcg_debug_assert(ts->kind == kind);
1320e8996ee0Sbellard     } else {
13217ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
13227ca4b752SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
13237ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
13247ca4b752SRichard Henderson 
1325c896fe29Sbellard             ts->base_type = type;
1326c896fe29Sbellard             ts->type = TCG_TYPE_I32;
1327e8996ee0Sbellard             ts->temp_allocated = 1;
1328ee17db83SRichard Henderson             ts->kind = kind;
13297ca4b752SRichard Henderson 
13307ca4b752SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
13317ca4b752SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
13327ca4b752SRichard Henderson             ts2->type = TCG_TYPE_I32;
13337ca4b752SRichard Henderson             ts2->temp_allocated = 1;
1334ee17db83SRichard Henderson             ts2->kind = kind;
13357ca4b752SRichard Henderson         } else {
1336c896fe29Sbellard             ts->base_type = type;
1337c896fe29Sbellard             ts->type = type;
1338e8996ee0Sbellard             ts->temp_allocated = 1;
1339ee17db83SRichard Henderson             ts->kind = kind;
1340c896fe29Sbellard         }
1341e8996ee0Sbellard     }
134227bfd83cSPeter Maydell 
134327bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
134427bfd83cSPeter Maydell     s->temps_in_use++;
134527bfd83cSPeter Maydell #endif
1346085272b3SRichard Henderson     return ts;
1347c896fe29Sbellard }
1348c896fe29Sbellard 
1349d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1350d2fd745fSRichard Henderson {
1351d2fd745fSRichard Henderson     TCGTemp *t;
1352d2fd745fSRichard Henderson 
1353d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1354d2fd745fSRichard Henderson     switch (type) {
1355d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1356d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1357d2fd745fSRichard Henderson         break;
1358d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1359d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1360d2fd745fSRichard Henderson         break;
1361d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1362d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1363d2fd745fSRichard Henderson         break;
1364d2fd745fSRichard Henderson     default:
1365d2fd745fSRichard Henderson         g_assert_not_reached();
1366d2fd745fSRichard Henderson     }
1367d2fd745fSRichard Henderson #endif
1368d2fd745fSRichard Henderson 
1369d2fd745fSRichard Henderson     t = tcg_temp_new_internal(type, 0);
1370d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1371d2fd745fSRichard Henderson }
1372d2fd745fSRichard Henderson 
1373d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1374d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1375d2fd745fSRichard Henderson {
1376d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1377d2fd745fSRichard Henderson 
1378d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1379d2fd745fSRichard Henderson 
1380d2fd745fSRichard Henderson     t = tcg_temp_new_internal(t->base_type, 0);
1381d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1382d2fd745fSRichard Henderson }
1383d2fd745fSRichard Henderson 
13845bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1385c896fe29Sbellard {
1386b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1387085272b3SRichard Henderson     int k, idx;
1388c896fe29Sbellard 
138927bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
139027bfd83cSPeter Maydell     s->temps_in_use--;
139127bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
139227bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
139327bfd83cSPeter Maydell     }
139427bfd83cSPeter Maydell #endif
139527bfd83cSPeter Maydell 
1396ee17db83SRichard Henderson     tcg_debug_assert(ts->kind < TEMP_GLOBAL);
1397eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
1398e8996ee0Sbellard     ts->temp_allocated = 0;
13990ec9eabcSRichard Henderson 
1400085272b3SRichard Henderson     idx = temp_idx(ts);
1401ee17db83SRichard Henderson     k = ts->base_type + (ts->kind == TEMP_NORMAL ? 0 : TCG_TYPE_COUNT);
14020ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
1403e8996ee0Sbellard }
1404e8996ee0Sbellard 
1405a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
1406a7812ae4Spbrook {
1407a7812ae4Spbrook     TCGv_i32 t0;
1408a7812ae4Spbrook     t0 = tcg_temp_new_i32();
1409e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
1410e8996ee0Sbellard     return t0;
1411c896fe29Sbellard }
1412c896fe29Sbellard 
1413a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
1414c896fe29Sbellard {
1415a7812ae4Spbrook     TCGv_i64 t0;
1416a7812ae4Spbrook     t0 = tcg_temp_new_i64();
1417e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
1418e8996ee0Sbellard     return t0;
1419c896fe29Sbellard }
1420c896fe29Sbellard 
1421a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
1422bdffd4a9Saurel32 {
1423a7812ae4Spbrook     TCGv_i32 t0;
1424a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
1425bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
1426bdffd4a9Saurel32     return t0;
1427bdffd4a9Saurel32 }
1428bdffd4a9Saurel32 
1429a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
1430bdffd4a9Saurel32 {
1431a7812ae4Spbrook     TCGv_i64 t0;
1432a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
1433bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
1434bdffd4a9Saurel32     return t0;
1435bdffd4a9Saurel32 }
1436bdffd4a9Saurel32 
143727bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
143827bfd83cSPeter Maydell void tcg_clear_temp_count(void)
143927bfd83cSPeter Maydell {
1440b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
144127bfd83cSPeter Maydell     s->temps_in_use = 0;
144227bfd83cSPeter Maydell }
144327bfd83cSPeter Maydell 
144427bfd83cSPeter Maydell int tcg_check_temp_count(void)
144527bfd83cSPeter Maydell {
1446b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
144727bfd83cSPeter Maydell     if (s->temps_in_use) {
144827bfd83cSPeter Maydell         /* Clear the count so that we don't give another
144927bfd83cSPeter Maydell          * warning immediately next time around.
145027bfd83cSPeter Maydell          */
145127bfd83cSPeter Maydell         s->temps_in_use = 0;
145227bfd83cSPeter Maydell         return 1;
145327bfd83cSPeter Maydell     }
145427bfd83cSPeter Maydell     return 0;
145527bfd83cSPeter Maydell }
145627bfd83cSPeter Maydell #endif
145727bfd83cSPeter Maydell 
1458be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1459be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1460be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1461be0f34b5SRichard Henderson {
1462d2fd745fSRichard Henderson     const bool have_vec
1463d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1464d2fd745fSRichard Henderson 
1465be0f34b5SRichard Henderson     switch (op) {
1466be0f34b5SRichard Henderson     case INDEX_op_discard:
1467be0f34b5SRichard Henderson     case INDEX_op_set_label:
1468be0f34b5SRichard Henderson     case INDEX_op_call:
1469be0f34b5SRichard Henderson     case INDEX_op_br:
1470be0f34b5SRichard Henderson     case INDEX_op_mb:
1471be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1472be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1473be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1474be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i32:
1475be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i32:
1476be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i64:
1477be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i64:
1478be0f34b5SRichard Henderson         return true;
1479be0f34b5SRichard Henderson 
148007ce0b05SRichard Henderson     case INDEX_op_qemu_st8_i32:
148107ce0b05SRichard Henderson         return TCG_TARGET_HAS_qemu_st8_i32;
148207ce0b05SRichard Henderson 
1483be0f34b5SRichard Henderson     case INDEX_op_goto_ptr:
1484be0f34b5SRichard Henderson         return TCG_TARGET_HAS_goto_ptr;
1485be0f34b5SRichard Henderson 
1486be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1487be0f34b5SRichard Henderson     case INDEX_op_movi_i32:
1488be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1489be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1490be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1491be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1492be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1493be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1494be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1495be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1496be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1497be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1498be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1499be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1500be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1501be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1502be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1503be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1504be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1505be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1506be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1507be0f34b5SRichard Henderson         return true;
1508be0f34b5SRichard Henderson 
1509be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1510be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1511be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1512be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1513be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1514be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1515be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1516be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1517be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1518be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1519be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1520be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1521be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1522be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1523be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1524be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1525be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1526be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1527be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1528be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1529fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
1530fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
1531be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1532be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1533be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1534be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1535be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1536be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1537be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1538be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1539be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1540be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1541be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1542be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1543be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1544be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1545be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1546be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1547be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1548be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1549be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1550be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1551be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1552be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1553be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1554be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1555be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1556be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1557be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1558be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1559be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1560be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1561be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1562be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1563be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1564be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1565be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1566be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1567be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1568be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1569be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1570be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1571be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1572be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1573be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1574be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1575be0f34b5SRichard Henderson 
1576be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1577be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1578be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1579be0f34b5SRichard Henderson 
1580be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1581be0f34b5SRichard Henderson     case INDEX_op_movi_i64:
1582be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1583be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1584be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1585be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1586be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1587be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1588be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1589be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1590be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1591be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1592be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1593be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1594be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1595be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1596be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1597be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1598be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1599be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1600be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1601be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1602be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1603be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1604be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1605be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1606be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1607be0f34b5SRichard Henderson 
1608be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1609be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1610be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1611be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1612be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1613be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1614be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1615be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1616be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1617be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
1618be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
1619be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
1620be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
1621be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
1622be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
1623be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
1624be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
1625be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
1626be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
1627be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
1628fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
1629fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
1630be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
1631be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrl_i64_i32;
1632be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
1633be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrh_i64_i32;
1634be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
1635be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
1636be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
1637be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
1638be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
1639be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
1640be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
1641be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
1642be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
1643be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
1644be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
1645be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
1646be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
1647be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
1648be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
1649be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
1650be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
1651be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
1652be0f34b5SRichard Henderson     case INDEX_op_not_i64:
1653be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
1654be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
1655be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
1656be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
1657be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
1658be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
1659be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
1660be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
1661be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
1662be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
1663be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
1664be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
1665be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
1666be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
1667be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
1668be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
1669be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
1670be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
1671be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
1672be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
1673be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
1674be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
1675be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
1676be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
1677be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
1678be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
1679be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
1680be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
1681be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
1682be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
1683be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
1684be0f34b5SRichard Henderson 
1685d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
1686d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
1687d2fd745fSRichard Henderson     case INDEX_op_dupi_vec:
168837ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
1689d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
1690d2fd745fSRichard Henderson     case INDEX_op_st_vec:
1691d2fd745fSRichard Henderson     case INDEX_op_add_vec:
1692d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
1693d2fd745fSRichard Henderson     case INDEX_op_and_vec:
1694d2fd745fSRichard Henderson     case INDEX_op_or_vec:
1695d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
1696212be173SRichard Henderson     case INDEX_op_cmp_vec:
1697d2fd745fSRichard Henderson         return have_vec;
1698d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
1699d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
1700d2fd745fSRichard Henderson     case INDEX_op_not_vec:
1701d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
1702d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
1703d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
1704bcefc902SRichard Henderson     case INDEX_op_abs_vec:
1705bcefc902SRichard Henderson         return have_vec && TCG_TARGET_HAS_abs_vec;
1706d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
1707d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
1708d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
1709d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
17103774030aSRichard Henderson     case INDEX_op_mul_vec:
17113774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
1712d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
1713d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
1714d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
1715d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
1716d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
1717d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
1718d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
1719d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
1720d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
1721d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
1722d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
1723d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
1724b0f7e744SRichard Henderson     case INDEX_op_rotli_vec:
1725b0f7e744SRichard Henderson         return have_vec && TCG_TARGET_HAS_roti_vec;
172623850a74SRichard Henderson     case INDEX_op_rotls_vec:
172723850a74SRichard Henderson         return have_vec && TCG_TARGET_HAS_rots_vec;
17285d0ceda9SRichard Henderson     case INDEX_op_rotlv_vec:
17295d0ceda9SRichard Henderson     case INDEX_op_rotrv_vec:
17305d0ceda9SRichard Henderson         return have_vec && TCG_TARGET_HAS_rotv_vec;
17318afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
17328afaf050SRichard Henderson     case INDEX_op_usadd_vec:
17338afaf050SRichard Henderson     case INDEX_op_sssub_vec:
17348afaf050SRichard Henderson     case INDEX_op_ussub_vec:
17358afaf050SRichard Henderson         return have_vec && TCG_TARGET_HAS_sat_vec;
1736dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
1737dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
1738dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
1739dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
1740dd0a0fcdSRichard Henderson         return have_vec && TCG_TARGET_HAS_minmax_vec;
174138dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
174238dc1294SRichard Henderson         return have_vec && TCG_TARGET_HAS_bitsel_vec;
1743f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
1744f75da298SRichard Henderson         return have_vec && TCG_TARGET_HAS_cmpsel_vec;
1745d2fd745fSRichard Henderson 
1746db432672SRichard Henderson     default:
1747db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
1748db432672SRichard Henderson         return true;
1749be0f34b5SRichard Henderson     }
1750be0f34b5SRichard Henderson }
1751be0f34b5SRichard Henderson 
175239cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment
175339cf05d3Sbellard    and endian swap. Maybe it would be better to do the alignment
175439cf05d3Sbellard    and endian swap in tcg_reg_alloc_call(). */
1755ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
1756c896fe29Sbellard {
175775e8b9b7SRichard Henderson     int i, real_args, nb_rets, pi;
1758bbb8a1b4SRichard Henderson     unsigned sizemask, flags;
1759afb49896SRichard Henderson     TCGHelperInfo *info;
176075e8b9b7SRichard Henderson     TCGOp *op;
1761afb49896SRichard Henderson 
1762619205fdSEmilio G. Cota     info = g_hash_table_lookup(helper_table, (gpointer)func);
1763bbb8a1b4SRichard Henderson     flags = info->flags;
1764bbb8a1b4SRichard Henderson     sizemask = info->sizemask;
17652bece2c8SRichard Henderson 
176638b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
176738b47b19SEmilio G. Cota     /* detect non-plugin helpers */
176838b47b19SEmilio G. Cota     if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) {
176938b47b19SEmilio G. Cota         tcg_ctx->plugin_insn->calls_helpers = true;
177038b47b19SEmilio G. Cota     }
177138b47b19SEmilio G. Cota #endif
177238b47b19SEmilio G. Cota 
177334b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
177434b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
177534b1a49cSRichard Henderson     /* We have 64-bit values in one register, but need to pass as two
177634b1a49cSRichard Henderson        separate parameters.  Split them.  */
177734b1a49cSRichard Henderson     int orig_sizemask = sizemask;
177834b1a49cSRichard Henderson     int orig_nargs = nargs;
177934b1a49cSRichard Henderson     TCGv_i64 retl, reth;
1780ae8b75dcSRichard Henderson     TCGTemp *split_args[MAX_OPC_PARAM];
178134b1a49cSRichard Henderson 
1782f764718dSRichard Henderson     retl = NULL;
1783f764718dSRichard Henderson     reth = NULL;
178434b1a49cSRichard Henderson     if (sizemask != 0) {
178534b1a49cSRichard Henderson         for (i = real_args = 0; i < nargs; ++i) {
178634b1a49cSRichard Henderson             int is_64bit = sizemask & (1 << (i+1)*2);
178734b1a49cSRichard Henderson             if (is_64bit) {
1788085272b3SRichard Henderson                 TCGv_i64 orig = temp_tcgv_i64(args[i]);
178934b1a49cSRichard Henderson                 TCGv_i32 h = tcg_temp_new_i32();
179034b1a49cSRichard Henderson                 TCGv_i32 l = tcg_temp_new_i32();
179134b1a49cSRichard Henderson                 tcg_gen_extr_i64_i32(l, h, orig);
1792ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(h);
1793ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(l);
179434b1a49cSRichard Henderson             } else {
179534b1a49cSRichard Henderson                 split_args[real_args++] = args[i];
179634b1a49cSRichard Henderson             }
179734b1a49cSRichard Henderson         }
179834b1a49cSRichard Henderson         nargs = real_args;
179934b1a49cSRichard Henderson         args = split_args;
180034b1a49cSRichard Henderson         sizemask = 0;
180134b1a49cSRichard Henderson     }
180234b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
18032bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
18042bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
18052bece2c8SRichard Henderson         int is_signed = sizemask & (2 << (i+1)*2);
18062bece2c8SRichard Henderson         if (!is_64bit) {
18072bece2c8SRichard Henderson             TCGv_i64 temp = tcg_temp_new_i64();
1808085272b3SRichard Henderson             TCGv_i64 orig = temp_tcgv_i64(args[i]);
18092bece2c8SRichard Henderson             if (is_signed) {
18102bece2c8SRichard Henderson                 tcg_gen_ext32s_i64(temp, orig);
18112bece2c8SRichard Henderson             } else {
18122bece2c8SRichard Henderson                 tcg_gen_ext32u_i64(temp, orig);
18132bece2c8SRichard Henderson             }
1814ae8b75dcSRichard Henderson             args[i] = tcgv_i64_temp(temp);
18152bece2c8SRichard Henderson         }
18162bece2c8SRichard Henderson     }
18172bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
18182bece2c8SRichard Henderson 
181915fa08f8SRichard Henderson     op = tcg_emit_op(INDEX_op_call);
182075e8b9b7SRichard Henderson 
182175e8b9b7SRichard Henderson     pi = 0;
1822ae8b75dcSRichard Henderson     if (ret != NULL) {
182334b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
182434b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
182534b1a49cSRichard Henderson         if (orig_sizemask & 1) {
182634b1a49cSRichard Henderson             /* The 32-bit ABI is going to return the 64-bit value in
182734b1a49cSRichard Henderson                the %o0/%o1 register pair.  Prepare for this by using
182834b1a49cSRichard Henderson                two return temporaries, and reassemble below.  */
182934b1a49cSRichard Henderson             retl = tcg_temp_new_i64();
183034b1a49cSRichard Henderson             reth = tcg_temp_new_i64();
1831ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(reth);
1832ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(retl);
183334b1a49cSRichard Henderson             nb_rets = 2;
183434b1a49cSRichard Henderson         } else {
1835ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
183634b1a49cSRichard Henderson             nb_rets = 1;
183734b1a49cSRichard Henderson         }
183834b1a49cSRichard Henderson #else
183934b1a49cSRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) {
184002eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
1841ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1842ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1843a7812ae4Spbrook #else
1844ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1845ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1846a7812ae4Spbrook #endif
1847a7812ae4Spbrook             nb_rets = 2;
184834b1a49cSRichard Henderson         } else {
1849ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1850a7812ae4Spbrook             nb_rets = 1;
1851a7812ae4Spbrook         }
185234b1a49cSRichard Henderson #endif
1853a7812ae4Spbrook     } else {
1854a7812ae4Spbrook         nb_rets = 0;
1855a7812ae4Spbrook     }
1856cd9090aaSRichard Henderson     TCGOP_CALLO(op) = nb_rets;
185775e8b9b7SRichard Henderson 
1858a7812ae4Spbrook     real_args = 0;
1859a7812ae4Spbrook     for (i = 0; i < nargs; i++) {
18602bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
1861bbb8a1b4SRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
186239cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS
186339cf05d3Sbellard             /* some targets want aligned 64 bit args */
1864ebd486d5Smalc             if (real_args & 1) {
186575e8b9b7SRichard Henderson                 op->args[pi++] = TCG_CALL_DUMMY_ARG;
1866ebd486d5Smalc                 real_args++;
186739cf05d3Sbellard             }
186839cf05d3Sbellard #endif
18693f90f252SRichard Henderson            /* If stack grows up, then we will be placing successive
18703f90f252SRichard Henderson               arguments at lower addresses, which means we need to
18713f90f252SRichard Henderson               reverse the order compared to how we would normally
18723f90f252SRichard Henderson               treat either big or little-endian.  For those arguments
18733f90f252SRichard Henderson               that will wind up in registers, this still works for
18743f90f252SRichard Henderson               HPPA (the only current STACK_GROWSUP target) since the
18753f90f252SRichard Henderson               argument registers are *also* allocated in decreasing
18763f90f252SRichard Henderson               order.  If another such target is added, this logic may
18773f90f252SRichard Henderson               have to get more complicated to differentiate between
18783f90f252SRichard Henderson               stack arguments and register arguments.  */
187902eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
1880ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1881ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1882c896fe29Sbellard #else
1883ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1884ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1885c896fe29Sbellard #endif
1886a7812ae4Spbrook             real_args += 2;
18872bece2c8SRichard Henderson             continue;
18882bece2c8SRichard Henderson         }
18892bece2c8SRichard Henderson 
1890ae8b75dcSRichard Henderson         op->args[pi++] = temp_arg(args[i]);
1891a7812ae4Spbrook         real_args++;
1892c896fe29Sbellard     }
189375e8b9b7SRichard Henderson     op->args[pi++] = (uintptr_t)func;
189475e8b9b7SRichard Henderson     op->args[pi++] = flags;
1895cd9090aaSRichard Henderson     TCGOP_CALLI(op) = real_args;
1896a7812ae4Spbrook 
189775e8b9b7SRichard Henderson     /* Make sure the fields didn't overflow.  */
1898cd9090aaSRichard Henderson     tcg_debug_assert(TCGOP_CALLI(op) == real_args);
189975e8b9b7SRichard Henderson     tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
19002bece2c8SRichard Henderson 
190134b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
190234b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
190334b1a49cSRichard Henderson     /* Free all of the parts we allocated above.  */
190434b1a49cSRichard Henderson     for (i = real_args = 0; i < orig_nargs; ++i) {
190534b1a49cSRichard Henderson         int is_64bit = orig_sizemask & (1 << (i+1)*2);
190634b1a49cSRichard Henderson         if (is_64bit) {
1907085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
1908085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
190934b1a49cSRichard Henderson         } else {
191034b1a49cSRichard Henderson             real_args++;
191134b1a49cSRichard Henderson         }
191234b1a49cSRichard Henderson     }
191334b1a49cSRichard Henderson     if (orig_sizemask & 1) {
191434b1a49cSRichard Henderson         /* The 32-bit ABI returned two 32-bit pieces.  Re-assemble them.
191534b1a49cSRichard Henderson            Note that describing these as TCGv_i64 eliminates an unnecessary
191634b1a49cSRichard Henderson            zero-extension that tcg_gen_concat_i32_i64 would create.  */
1917085272b3SRichard Henderson         tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth);
191834b1a49cSRichard Henderson         tcg_temp_free_i64(retl);
191934b1a49cSRichard Henderson         tcg_temp_free_i64(reth);
192034b1a49cSRichard Henderson     }
192134b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
19222bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
19232bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
19242bece2c8SRichard Henderson         if (!is_64bit) {
1925085272b3SRichard Henderson             tcg_temp_free_internal(args[i]);
19262bece2c8SRichard Henderson         }
19272bece2c8SRichard Henderson     }
19282bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
1929a7812ae4Spbrook }
1930c896fe29Sbellard 
19318fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
1932c896fe29Sbellard {
1933ac3b8891SRichard Henderson     int i, n;
1934ac3b8891SRichard Henderson 
1935ee17db83SRichard Henderson     for (i = 0, n = s->nb_temps; i < n; i++) {
1936ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
1937ee17db83SRichard Henderson         TCGTempVal val = TEMP_VAL_MEM;
1938ee17db83SRichard Henderson 
1939ee17db83SRichard Henderson         switch (ts->kind) {
1940ee17db83SRichard Henderson         case TEMP_FIXED:
1941ee17db83SRichard Henderson             val = TEMP_VAL_REG;
1942ee17db83SRichard Henderson             break;
1943ee17db83SRichard Henderson         case TEMP_GLOBAL:
1944ee17db83SRichard Henderson             break;
1945ee17db83SRichard Henderson         case TEMP_NORMAL:
1946ee17db83SRichard Henderson             val = TEMP_VAL_DEAD;
1947ee17db83SRichard Henderson             /* fall through */
1948ee17db83SRichard Henderson         case TEMP_LOCAL:
1949e8996ee0Sbellard             ts->mem_allocated = 0;
1950ee17db83SRichard Henderson             break;
1951ee17db83SRichard Henderson         default:
1952ee17db83SRichard Henderson             g_assert_not_reached();
1953ee17db83SRichard Henderson         }
1954ee17db83SRichard Henderson         ts->val_type = val;
1955e8996ee0Sbellard     }
1956f8b2f202SRichard Henderson 
1957f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
1958c896fe29Sbellard }
1959c896fe29Sbellard 
1960f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
1961f8b2f202SRichard Henderson                                  TCGTemp *ts)
1962c896fe29Sbellard {
19631807f4c4SRichard Henderson     int idx = temp_idx(ts);
1964ac56dd48Spbrook 
1965ee17db83SRichard Henderson     switch (ts->kind) {
1966ee17db83SRichard Henderson     case TEMP_FIXED:
1967ee17db83SRichard Henderson     case TEMP_GLOBAL:
1968ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
1969ee17db83SRichard Henderson         break;
1970ee17db83SRichard Henderson     case TEMP_LOCAL:
1971641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
1972ee17db83SRichard Henderson         break;
1973ee17db83SRichard Henderson     case TEMP_NORMAL:
1974ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
1975ee17db83SRichard Henderson         break;
1976c896fe29Sbellard     }
1977c896fe29Sbellard     return buf;
1978c896fe29Sbellard }
1979c896fe29Sbellard 
198043439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
198143439139SRichard Henderson                              int buf_size, TCGArg arg)
1982f8b2f202SRichard Henderson {
198343439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
1984f8b2f202SRichard Henderson }
1985f8b2f202SRichard Henderson 
19866e085f72SRichard Henderson /* Find helper name.  */
19876e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val)
1988e8996ee0Sbellard {
19896e085f72SRichard Henderson     const char *ret = NULL;
1990619205fdSEmilio G. Cota     if (helper_table) {
1991619205fdSEmilio G. Cota         TCGHelperInfo *info = g_hash_table_lookup(helper_table, (gpointer)val);
199272866e82SRichard Henderson         if (info) {
199372866e82SRichard Henderson             ret = info->name;
199472866e82SRichard Henderson         }
1995e8996ee0Sbellard     }
19966e085f72SRichard Henderson     return ret;
19974dc81f28Sbellard }
19984dc81f28Sbellard 
1999f48f3edeSblueswir1 static const char * const cond_name[] =
2000f48f3edeSblueswir1 {
20010aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
20020aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
2003f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
2004f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
2005f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
2006f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
2007f48f3edeSblueswir1     [TCG_COND_LE] = "le",
2008f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
2009f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
2010f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
2011f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
2012f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
2013f48f3edeSblueswir1 };
2014f48f3edeSblueswir1 
2015f713d6adSRichard Henderson static const char * const ldst_name[] =
2016f713d6adSRichard Henderson {
2017f713d6adSRichard Henderson     [MO_UB]   = "ub",
2018f713d6adSRichard Henderson     [MO_SB]   = "sb",
2019f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
2020f713d6adSRichard Henderson     [MO_LESW] = "lesw",
2021f713d6adSRichard Henderson     [MO_LEUL] = "leul",
2022f713d6adSRichard Henderson     [MO_LESL] = "lesl",
2023f713d6adSRichard Henderson     [MO_LEQ]  = "leq",
2024f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
2025f713d6adSRichard Henderson     [MO_BESW] = "besw",
2026f713d6adSRichard Henderson     [MO_BEUL] = "beul",
2027f713d6adSRichard Henderson     [MO_BESL] = "besl",
2028f713d6adSRichard Henderson     [MO_BEQ]  = "beq",
2029f713d6adSRichard Henderson };
2030f713d6adSRichard Henderson 
20311f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
203252bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY
20331f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
20341f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
20351f00b27fSSergey Sorokin #else
20361f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
20371f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
20381f00b27fSSergey Sorokin #endif
20391f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
20401f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
20411f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
20421f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
20431f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
20441f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
20451f00b27fSSergey Sorokin };
20461f00b27fSSergey Sorokin 
2047b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
2048b016486eSRichard Henderson {
2049b016486eSRichard Henderson     return (d & (d - 1)) == 0;
2050b016486eSRichard Henderson }
2051b016486eSRichard Henderson 
2052b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
2053b016486eSRichard Henderson {
2054b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
2055b016486eSRichard Henderson         return ctz32(d);
2056b016486eSRichard Henderson     } else {
2057b016486eSRichard Henderson         return ctz64(d);
2058b016486eSRichard Henderson     }
2059b016486eSRichard Henderson }
2060b016486eSRichard Henderson 
20611894f69aSRichard Henderson static void tcg_dump_ops(TCGContext *s, bool have_prefs)
2062c896fe29Sbellard {
2063c896fe29Sbellard     char buf[128];
2064c45cb8bbSRichard Henderson     TCGOp *op;
2065c896fe29Sbellard 
206615fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
2067c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
2068c45cb8bbSRichard Henderson         const TCGOpDef *def;
2069c45cb8bbSRichard Henderson         TCGOpcode c;
2070bdfb460eSRichard Henderson         int col = 0;
2071c45cb8bbSRichard Henderson 
2072c45cb8bbSRichard Henderson         c = op->opc;
2073c896fe29Sbellard         def = &tcg_op_defs[c];
2074c45cb8bbSRichard Henderson 
2075765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
2076b016486eSRichard Henderson             nb_oargs = 0;
207715fa08f8SRichard Henderson             col += qemu_log("\n ----");
20789aef40edSRichard Henderson 
20799aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
20809aef40edSRichard Henderson                 target_ulong a;
20817e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
2082efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
20837e4597d7Sbellard #else
2084efee3746SRichard Henderson                 a = op->args[i];
20857e4597d7Sbellard #endif
2086bdfb460eSRichard Henderson                 col += qemu_log(" " TARGET_FMT_lx, a);
2087eeacee4dSBlue Swirl             }
20887e4597d7Sbellard         } else if (c == INDEX_op_call) {
2089c896fe29Sbellard             /* variable number of arguments */
2090cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2091cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2092c896fe29Sbellard             nb_cargs = def->nb_cargs;
2093b03cce8eSbellard 
2094cf066674SRichard Henderson             /* function name, flags, out args */
2095bdfb460eSRichard Henderson             col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name,
2096efee3746SRichard Henderson                             tcg_find_helper(s, op->args[nb_oargs + nb_iargs]),
2097efee3746SRichard Henderson                             op->args[nb_oargs + nb_iargs + 1], nb_oargs);
2098b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
209943439139SRichard Henderson                 col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf),
2100efee3746SRichard Henderson                                                        op->args[i]));
2101b03cce8eSbellard             }
2102cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
2103efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
2104cf066674SRichard Henderson                 const char *t = "<dummy>";
2105cf066674SRichard Henderson                 if (arg != TCG_CALL_DUMMY_ARG) {
210643439139SRichard Henderson                     t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
2107b03cce8eSbellard                 }
2108bdfb460eSRichard Henderson                 col += qemu_log(",%s", t);
2109e8996ee0Sbellard             }
2110b03cce8eSbellard         } else {
2111bdfb460eSRichard Henderson             col += qemu_log(" %s ", def->name);
2112c45cb8bbSRichard Henderson 
2113c896fe29Sbellard             nb_oargs = def->nb_oargs;
2114c896fe29Sbellard             nb_iargs = def->nb_iargs;
2115c896fe29Sbellard             nb_cargs = def->nb_cargs;
2116c896fe29Sbellard 
2117d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
2118d2fd745fSRichard Henderson                 col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op),
2119d2fd745fSRichard Henderson                                 8 << TCGOP_VECE(op));
2120d2fd745fSRichard Henderson             }
2121d2fd745fSRichard Henderson 
2122c896fe29Sbellard             k = 0;
2123c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
2124eeacee4dSBlue Swirl                 if (k != 0) {
2125bdfb460eSRichard Henderson                     col += qemu_log(",");
2126eeacee4dSBlue Swirl                 }
212743439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2128efee3746SRichard Henderson                                                       op->args[k++]));
2129c896fe29Sbellard             }
2130c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
2131eeacee4dSBlue Swirl                 if (k != 0) {
2132bdfb460eSRichard Henderson                     col += qemu_log(",");
2133eeacee4dSBlue Swirl                 }
213443439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2135efee3746SRichard Henderson                                                       op->args[k++]));
2136c896fe29Sbellard             }
2137be210acbSRichard Henderson             switch (c) {
2138be210acbSRichard Henderson             case INDEX_op_brcond_i32:
2139ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
2140ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
2141be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
2142be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
2143ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
2144be210acbSRichard Henderson             case INDEX_op_setcond_i64:
2145ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
2146212be173SRichard Henderson             case INDEX_op_cmp_vec:
2147f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
2148efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
2149efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
2150efee3746SRichard Henderson                     col += qemu_log(",%s", cond_name[op->args[k++]]);
2151eeacee4dSBlue Swirl                 } else {
2152efee3746SRichard Henderson                     col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]);
2153eeacee4dSBlue Swirl                 }
2154f48f3edeSblueswir1                 i = 1;
2155be210acbSRichard Henderson                 break;
2156f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
2157f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
215807ce0b05SRichard Henderson             case INDEX_op_qemu_st8_i32:
2159f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
2160f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
216159227d5dSRichard Henderson                 {
2162efee3746SRichard Henderson                     TCGMemOpIdx oi = op->args[k++];
216314776ab5STony Nguyen                     MemOp op = get_memop(oi);
216459227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
216559227d5dSRichard Henderson 
216659c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
2167bdfb460eSRichard Henderson                         col += qemu_log(",$0x%x,%u", op, ix);
216859c4b7e8SRichard Henderson                     } else {
21691f00b27fSSergey Sorokin                         const char *s_al, *s_op;
21701f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
217159c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
2172bdfb460eSRichard Henderson                         col += qemu_log(",%s%s,%u", s_al, s_op, ix);
2173f713d6adSRichard Henderson                     }
2174f713d6adSRichard Henderson                     i = 1;
217559227d5dSRichard Henderson                 }
2176f713d6adSRichard Henderson                 break;
2177be210acbSRichard Henderson             default:
2178f48f3edeSblueswir1                 i = 0;
2179be210acbSRichard Henderson                 break;
2180be210acbSRichard Henderson             }
218151e3972cSRichard Henderson             switch (c) {
218251e3972cSRichard Henderson             case INDEX_op_set_label:
218351e3972cSRichard Henderson             case INDEX_op_br:
218451e3972cSRichard Henderson             case INDEX_op_brcond_i32:
218551e3972cSRichard Henderson             case INDEX_op_brcond_i64:
218651e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2187efee3746SRichard Henderson                 col += qemu_log("%s$L%d", k ? "," : "",
2188efee3746SRichard Henderson                                 arg_label(op->args[k])->id);
218951e3972cSRichard Henderson                 i++, k++;
219051e3972cSRichard Henderson                 break;
219151e3972cSRichard Henderson             default:
219251e3972cSRichard Henderson                 break;
2193eeacee4dSBlue Swirl             }
219451e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
2195efee3746SRichard Henderson                 col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]);
2196bdfb460eSRichard Henderson             }
2197bdfb460eSRichard Henderson         }
2198bdfb460eSRichard Henderson 
21991894f69aSRichard Henderson         if (have_prefs || op->life) {
22007606488cSRobert Foley 
22017606488cSRobert Foley             QemuLogFile *logfile;
22027606488cSRobert Foley 
22037606488cSRobert Foley             rcu_read_lock();
2204d73415a3SStefan Hajnoczi             logfile = qatomic_rcu_read(&qemu_logfile);
22057606488cSRobert Foley             if (logfile) {
22061894f69aSRichard Henderson                 for (; col < 40; ++col) {
22077606488cSRobert Foley                     putc(' ', logfile->fd);
2208bdfb460eSRichard Henderson                 }
22091894f69aSRichard Henderson             }
22107606488cSRobert Foley             rcu_read_unlock();
22117606488cSRobert Foley         }
22121894f69aSRichard Henderson 
22131894f69aSRichard Henderson         if (op->life) {
22141894f69aSRichard Henderson             unsigned life = op->life;
2215bdfb460eSRichard Henderson 
2216bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
2217bdfb460eSRichard Henderson                 qemu_log("  sync:");
2218bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
2219bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
2220bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2221bdfb460eSRichard Henderson                     }
2222bdfb460eSRichard Henderson                 }
2223bdfb460eSRichard Henderson             }
2224bdfb460eSRichard Henderson             life /= DEAD_ARG;
2225bdfb460eSRichard Henderson             if (life) {
2226bdfb460eSRichard Henderson                 qemu_log("  dead:");
2227bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
2228bdfb460eSRichard Henderson                     if (life & 1) {
2229bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2230bdfb460eSRichard Henderson                     }
2231bdfb460eSRichard Henderson                 }
2232c896fe29Sbellard             }
2233b03cce8eSbellard         }
22341894f69aSRichard Henderson 
22351894f69aSRichard Henderson         if (have_prefs) {
22361894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
22371894f69aSRichard Henderson                 TCGRegSet set = op->output_pref[i];
22381894f69aSRichard Henderson 
22391894f69aSRichard Henderson                 if (i == 0) {
22401894f69aSRichard Henderson                     qemu_log("  pref=");
22411894f69aSRichard Henderson                 } else {
22421894f69aSRichard Henderson                     qemu_log(",");
22431894f69aSRichard Henderson                 }
22441894f69aSRichard Henderson                 if (set == 0) {
22451894f69aSRichard Henderson                     qemu_log("none");
22461894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
22471894f69aSRichard Henderson                     qemu_log("all");
22481894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
22491894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
22501894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
22511894f69aSRichard Henderson                     qemu_log("%s", tcg_target_reg_names[reg]);
22521894f69aSRichard Henderson #endif
22531894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
22541894f69aSRichard Henderson                     qemu_log("%#x", (uint32_t)set);
22551894f69aSRichard Henderson                 } else {
22561894f69aSRichard Henderson                     qemu_log("%#" PRIx64, (uint64_t)set);
22571894f69aSRichard Henderson                 }
22581894f69aSRichard Henderson             }
22591894f69aSRichard Henderson         }
22601894f69aSRichard Henderson 
2261eeacee4dSBlue Swirl         qemu_log("\n");
2262c896fe29Sbellard     }
2263c896fe29Sbellard }
2264c896fe29Sbellard 
2265c896fe29Sbellard /* we give more priority to constraints with less registers */
2266c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2267c896fe29Sbellard {
226874a11790SRichard Henderson     const TCGArgConstraint *arg_ct = &def->args_ct[k];
226974a11790SRichard Henderson     int n;
2270c896fe29Sbellard 
2271bc2b17e6SRichard Henderson     if (arg_ct->oalias) {
2272c896fe29Sbellard         /* an alias is equivalent to a single register */
2273c896fe29Sbellard         n = 1;
2274c896fe29Sbellard     } else {
227574a11790SRichard Henderson         n = ctpop64(arg_ct->regs);
2276c896fe29Sbellard     }
2277c896fe29Sbellard     return TCG_TARGET_NB_REGS - n + 1;
2278c896fe29Sbellard }
2279c896fe29Sbellard 
2280c896fe29Sbellard /* sort from highest priority to lowest */
2281c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2282c896fe29Sbellard {
228366792f90SRichard Henderson     int i, j;
228466792f90SRichard Henderson     TCGArgConstraint *a = def->args_ct;
2285c896fe29Sbellard 
228666792f90SRichard Henderson     for (i = 0; i < n; i++) {
228766792f90SRichard Henderson         a[start + i].sort_index = start + i;
228866792f90SRichard Henderson     }
228966792f90SRichard Henderson     if (n <= 1) {
2290c896fe29Sbellard         return;
229166792f90SRichard Henderson     }
2292c896fe29Sbellard     for (i = 0; i < n - 1; i++) {
2293c896fe29Sbellard         for (j = i + 1; j < n; j++) {
229466792f90SRichard Henderson             int p1 = get_constraint_priority(def, a[start + i].sort_index);
229566792f90SRichard Henderson             int p2 = get_constraint_priority(def, a[start + j].sort_index);
2296c896fe29Sbellard             if (p1 < p2) {
229766792f90SRichard Henderson                 int tmp = a[start + i].sort_index;
229866792f90SRichard Henderson                 a[start + i].sort_index = a[start + j].sort_index;
229966792f90SRichard Henderson                 a[start + j].sort_index = tmp;
2300c896fe29Sbellard             }
2301c896fe29Sbellard         }
2302c896fe29Sbellard     }
2303c896fe29Sbellard }
2304c896fe29Sbellard 
2305f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2306c896fe29Sbellard {
2307a9751609SRichard Henderson     TCGOpcode op;
2308c896fe29Sbellard 
2309f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
2310f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
2311f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
2312069ea736SRichard Henderson         TCGType type;
2313069ea736SRichard Henderson         int i, nb_args;
2314f69d277eSRichard Henderson 
2315f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
2316f69d277eSRichard Henderson             continue;
2317f69d277eSRichard Henderson         }
2318f69d277eSRichard Henderson 
2319c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
2320f69d277eSRichard Henderson         if (nb_args == 0) {
2321f69d277eSRichard Henderson             continue;
2322f69d277eSRichard Henderson         }
2323f69d277eSRichard Henderson 
2324f69d277eSRichard Henderson         tdefs = tcg_target_op_def(op);
2325f69d277eSRichard Henderson         /* Missing TCGTargetOpDef entry. */
2326f69d277eSRichard Henderson         tcg_debug_assert(tdefs != NULL);
2327f69d277eSRichard Henderson 
2328069ea736SRichard Henderson         type = (def->flags & TCG_OPF_64BIT ? TCG_TYPE_I64 : TCG_TYPE_I32);
2329c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2330f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
2331f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2332eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2333f69d277eSRichard Henderson 
233417280ff4SRichard Henderson             while (*ct_str != '\0') {
233517280ff4SRichard Henderson                 switch(*ct_str) {
233617280ff4SRichard Henderson                 case '0' ... '9':
233717280ff4SRichard Henderson                     {
233817280ff4SRichard Henderson                         int oarg = *ct_str - '0';
233917280ff4SRichard Henderson                         tcg_debug_assert(ct_str == tdefs->args_ct_str[i]);
2340eabb7b91SAurelien Jarno                         tcg_debug_assert(oarg < def->nb_oargs);
234174a11790SRichard Henderson                         tcg_debug_assert(def->args_ct[oarg].regs != 0);
2342c896fe29Sbellard                         def->args_ct[i] = def->args_ct[oarg];
2343bc2b17e6SRichard Henderson                         /* The output sets oalias.  */
2344bc2b17e6SRichard Henderson                         def->args_ct[oarg].oalias = true;
23455ff9d6a4Sbellard                         def->args_ct[oarg].alias_index = i;
2346bc2b17e6SRichard Henderson                         /* The input sets ialias. */
2347bc2b17e6SRichard Henderson                         def->args_ct[i].ialias = true;
23485ff9d6a4Sbellard                         def->args_ct[i].alias_index = oarg;
234917280ff4SRichard Henderson                     }
235017280ff4SRichard Henderson                     ct_str++;
2351c896fe29Sbellard                     break;
235282790a87SRichard Henderson                 case '&':
2353bc2b17e6SRichard Henderson                     def->args_ct[i].newreg = true;
235482790a87SRichard Henderson                     ct_str++;
235582790a87SRichard Henderson                     break;
2356c896fe29Sbellard                 case 'i':
2357c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2358c896fe29Sbellard                     ct_str++;
2359c896fe29Sbellard                     break;
2360c896fe29Sbellard                 default:
2361069ea736SRichard Henderson                     ct_str = target_parse_constraint(&def->args_ct[i],
2362069ea736SRichard Henderson                                                      ct_str, type);
2363f69d277eSRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2364069ea736SRichard Henderson                     tcg_debug_assert(ct_str != NULL);
2365c896fe29Sbellard                 }
2366c896fe29Sbellard             }
2367c896fe29Sbellard         }
2368c896fe29Sbellard 
2369c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2370eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2371c68aaa18SStefan Weil 
2372c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
2373c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
2374c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
2375c896fe29Sbellard     }
2376c896fe29Sbellard }
2377c896fe29Sbellard 
23780c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
23790c627cdcSRichard Henderson {
2380d88a117eSRichard Henderson     TCGLabel *label;
2381d88a117eSRichard Henderson 
2382d88a117eSRichard Henderson     switch (op->opc) {
2383d88a117eSRichard Henderson     case INDEX_op_br:
2384d88a117eSRichard Henderson         label = arg_label(op->args[0]);
2385d88a117eSRichard Henderson         label->refs--;
2386d88a117eSRichard Henderson         break;
2387d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
2388d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
2389d88a117eSRichard Henderson         label = arg_label(op->args[3]);
2390d88a117eSRichard Henderson         label->refs--;
2391d88a117eSRichard Henderson         break;
2392d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
2393d88a117eSRichard Henderson         label = arg_label(op->args[5]);
2394d88a117eSRichard Henderson         label->refs--;
2395d88a117eSRichard Henderson         break;
2396d88a117eSRichard Henderson     default:
2397d88a117eSRichard Henderson         break;
2398d88a117eSRichard Henderson     }
2399d88a117eSRichard Henderson 
240015fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
240115fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
2402abebf925SRichard Henderson     s->nb_ops--;
24030c627cdcSRichard Henderson 
24040c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
2405d73415a3SStefan Hajnoczi     qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
24060c627cdcSRichard Henderson #endif
24070c627cdcSRichard Henderson }
24080c627cdcSRichard Henderson 
240915fa08f8SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc)
241015fa08f8SRichard Henderson {
241115fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
241215fa08f8SRichard Henderson     TCGOp *op;
241315fa08f8SRichard Henderson 
241415fa08f8SRichard Henderson     if (likely(QTAILQ_EMPTY(&s->free_ops))) {
241515fa08f8SRichard Henderson         op = tcg_malloc(sizeof(TCGOp));
241615fa08f8SRichard Henderson     } else {
241715fa08f8SRichard Henderson         op = QTAILQ_FIRST(&s->free_ops);
241815fa08f8SRichard Henderson         QTAILQ_REMOVE(&s->free_ops, op, link);
241915fa08f8SRichard Henderson     }
242015fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
242115fa08f8SRichard Henderson     op->opc = opc;
2422abebf925SRichard Henderson     s->nb_ops++;
242315fa08f8SRichard Henderson 
242415fa08f8SRichard Henderson     return op;
242515fa08f8SRichard Henderson }
242615fa08f8SRichard Henderson 
242715fa08f8SRichard Henderson TCGOp *tcg_emit_op(TCGOpcode opc)
242815fa08f8SRichard Henderson {
242915fa08f8SRichard Henderson     TCGOp *op = tcg_op_alloc(opc);
243015fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
243115fa08f8SRichard Henderson     return op;
243215fa08f8SRichard Henderson }
243315fa08f8SRichard Henderson 
2434ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
24355a18407fSRichard Henderson {
243615fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
243715fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
24385a18407fSRichard Henderson     return new_op;
24395a18407fSRichard Henderson }
24405a18407fSRichard Henderson 
2441ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
24425a18407fSRichard Henderson {
244315fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
244415fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
24455a18407fSRichard Henderson     return new_op;
24465a18407fSRichard Henderson }
24475a18407fSRichard Henderson 
2448b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
2449b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s)
2450b4fc67c7SRichard Henderson {
2451b4fc67c7SRichard Henderson     TCGOp *op, *op_next;
2452b4fc67c7SRichard Henderson     bool dead = false;
2453b4fc67c7SRichard Henderson 
2454b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
2455b4fc67c7SRichard Henderson         bool remove = dead;
2456b4fc67c7SRichard Henderson         TCGLabel *label;
2457b4fc67c7SRichard Henderson         int call_flags;
2458b4fc67c7SRichard Henderson 
2459b4fc67c7SRichard Henderson         switch (op->opc) {
2460b4fc67c7SRichard Henderson         case INDEX_op_set_label:
2461b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
2462b4fc67c7SRichard Henderson             if (label->refs == 0) {
2463b4fc67c7SRichard Henderson                 /*
2464b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
2465b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
2466b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
2467b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
2468b4fc67c7SRichard Henderson                  * little to be gained by iterating.
2469b4fc67c7SRichard Henderson                  */
2470b4fc67c7SRichard Henderson                 remove = true;
2471b4fc67c7SRichard Henderson             } else {
2472b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
2473b4fc67c7SRichard Henderson                 dead = false;
2474b4fc67c7SRichard Henderson                 remove = false;
2475b4fc67c7SRichard Henderson 
2476b4fc67c7SRichard Henderson                 /*
2477b4fc67c7SRichard Henderson                  * Optimization can fold conditional branches to unconditional.
2478b4fc67c7SRichard Henderson                  * If we find a label with one reference which is preceded by
2479b4fc67c7SRichard Henderson                  * an unconditional branch to it, remove both.  This needed to
2480b4fc67c7SRichard Henderson                  * wait until the dead code in between them was removed.
2481b4fc67c7SRichard Henderson                  */
2482b4fc67c7SRichard Henderson                 if (label->refs == 1) {
2483eae3eb3eSPaolo Bonzini                     TCGOp *op_prev = QTAILQ_PREV(op, link);
2484b4fc67c7SRichard Henderson                     if (op_prev->opc == INDEX_op_br &&
2485b4fc67c7SRichard Henderson                         label == arg_label(op_prev->args[0])) {
2486b4fc67c7SRichard Henderson                         tcg_op_remove(s, op_prev);
2487b4fc67c7SRichard Henderson                         remove = true;
2488b4fc67c7SRichard Henderson                     }
2489b4fc67c7SRichard Henderson                 }
2490b4fc67c7SRichard Henderson             }
2491b4fc67c7SRichard Henderson             break;
2492b4fc67c7SRichard Henderson 
2493b4fc67c7SRichard Henderson         case INDEX_op_br:
2494b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
2495b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
2496b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
2497b4fc67c7SRichard Henderson             dead = true;
2498b4fc67c7SRichard Henderson             break;
2499b4fc67c7SRichard Henderson 
2500b4fc67c7SRichard Henderson         case INDEX_op_call:
2501b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
2502b4fc67c7SRichard Henderson             call_flags = op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1];
2503b4fc67c7SRichard Henderson             if (call_flags & TCG_CALL_NO_RETURN) {
2504b4fc67c7SRichard Henderson                 dead = true;
2505b4fc67c7SRichard Henderson             }
2506b4fc67c7SRichard Henderson             break;
2507b4fc67c7SRichard Henderson 
2508b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
2509b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
2510b4fc67c7SRichard Henderson             remove = false;
2511b4fc67c7SRichard Henderson             break;
2512b4fc67c7SRichard Henderson 
2513b4fc67c7SRichard Henderson         default:
2514b4fc67c7SRichard Henderson             break;
2515b4fc67c7SRichard Henderson         }
2516b4fc67c7SRichard Henderson 
2517b4fc67c7SRichard Henderson         if (remove) {
2518b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
2519b4fc67c7SRichard Henderson         }
2520b4fc67c7SRichard Henderson     }
2521b4fc67c7SRichard Henderson }
2522b4fc67c7SRichard Henderson 
2523c70fbf0aSRichard Henderson #define TS_DEAD  1
2524c70fbf0aSRichard Henderson #define TS_MEM   2
2525c70fbf0aSRichard Henderson 
25265a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
25275a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
25285a18407fSRichard Henderson 
252925f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
253025f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
253125f49c5fSRichard Henderson {
253225f49c5fSRichard Henderson     return ts->state_ptr;
253325f49c5fSRichard Henderson }
253425f49c5fSRichard Henderson 
253525f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
253625f49c5fSRichard Henderson  * maximal regset for its type.
253725f49c5fSRichard Henderson  */
253825f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
253925f49c5fSRichard Henderson {
254025f49c5fSRichard Henderson     *la_temp_pref(ts)
254125f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
254225f49c5fSRichard Henderson }
254325f49c5fSRichard Henderson 
25449c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
25459c43b68dSAurelien Jarno    should be in memory. */
25462616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
2547c896fe29Sbellard {
2548b83eabeaSRichard Henderson     int i;
2549b83eabeaSRichard Henderson 
2550b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2551b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
255225f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2553b83eabeaSRichard Henderson     }
2554b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2555b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
255625f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2557b83eabeaSRichard Henderson     }
2558c896fe29Sbellard }
2559c896fe29Sbellard 
25609c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
25619c43b68dSAurelien Jarno    and local temps should be in memory. */
25622616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
2563641d5fbeSbellard {
2564b83eabeaSRichard Henderson     int i;
2565641d5fbeSbellard 
2566ee17db83SRichard Henderson     for (i = 0; i < nt; ++i) {
2567ee17db83SRichard Henderson         TCGTemp *ts = &s->temps[i];
2568ee17db83SRichard Henderson         int state;
2569ee17db83SRichard Henderson 
2570ee17db83SRichard Henderson         switch (ts->kind) {
2571ee17db83SRichard Henderson         case TEMP_FIXED:
2572ee17db83SRichard Henderson         case TEMP_GLOBAL:
2573ee17db83SRichard Henderson         case TEMP_LOCAL:
2574ee17db83SRichard Henderson             state = TS_DEAD | TS_MEM;
2575ee17db83SRichard Henderson             break;
2576ee17db83SRichard Henderson         case TEMP_NORMAL:
2577ee17db83SRichard Henderson             state = TS_DEAD;
2578ee17db83SRichard Henderson             break;
2579ee17db83SRichard Henderson         default:
2580ee17db83SRichard Henderson             g_assert_not_reached();
2581c70fbf0aSRichard Henderson         }
2582ee17db83SRichard Henderson         ts->state = state;
2583ee17db83SRichard Henderson         la_reset_pref(ts);
2584641d5fbeSbellard     }
2585641d5fbeSbellard }
2586641d5fbeSbellard 
2587f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
2588f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
2589f65a061cSRichard Henderson {
2590f65a061cSRichard Henderson     int i;
2591f65a061cSRichard Henderson 
2592f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
259325f49c5fSRichard Henderson         int state = s->temps[i].state;
259425f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
259525f49c5fSRichard Henderson         if (state == TS_DEAD) {
259625f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
259725f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
259825f49c5fSRichard Henderson         }
2599f65a061cSRichard Henderson     }
2600f65a061cSRichard Henderson }
2601f65a061cSRichard Henderson 
2602b4cb76e6SRichard Henderson /*
2603b4cb76e6SRichard Henderson  * liveness analysis: conditional branch: all temps are dead,
2604b4cb76e6SRichard Henderson  * globals and local temps should be synced.
2605b4cb76e6SRichard Henderson  */
2606b4cb76e6SRichard Henderson static void la_bb_sync(TCGContext *s, int ng, int nt)
2607b4cb76e6SRichard Henderson {
2608b4cb76e6SRichard Henderson     la_global_sync(s, ng);
2609b4cb76e6SRichard Henderson 
2610b4cb76e6SRichard Henderson     for (int i = ng; i < nt; ++i) {
2611ee17db83SRichard Henderson         if (s->temps[i].kind == TEMP_LOCAL) {
2612b4cb76e6SRichard Henderson             int state = s->temps[i].state;
2613b4cb76e6SRichard Henderson             s->temps[i].state = state | TS_MEM;
2614b4cb76e6SRichard Henderson             if (state != TS_DEAD) {
2615b4cb76e6SRichard Henderson                 continue;
2616b4cb76e6SRichard Henderson             }
2617b4cb76e6SRichard Henderson         } else {
2618b4cb76e6SRichard Henderson             s->temps[i].state = TS_DEAD;
2619b4cb76e6SRichard Henderson         }
2620b4cb76e6SRichard Henderson         la_reset_pref(&s->temps[i]);
2621b4cb76e6SRichard Henderson     }
2622b4cb76e6SRichard Henderson }
2623b4cb76e6SRichard Henderson 
2624f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
2625f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
2626f65a061cSRichard Henderson {
2627f65a061cSRichard Henderson     int i;
2628f65a061cSRichard Henderson 
2629f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
2630f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
263125f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
263225f49c5fSRichard Henderson     }
263325f49c5fSRichard Henderson }
263425f49c5fSRichard Henderson 
263525f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
263625f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
263725f49c5fSRichard Henderson {
263825f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
263925f49c5fSRichard Henderson     int i;
264025f49c5fSRichard Henderson 
264125f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
264225f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
264325f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
264425f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
264525f49c5fSRichard Henderson             TCGRegSet set = *pset;
264625f49c5fSRichard Henderson 
264725f49c5fSRichard Henderson             set &= mask;
264825f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
264925f49c5fSRichard Henderson             if (set == 0) {
265025f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
265125f49c5fSRichard Henderson             }
265225f49c5fSRichard Henderson             *pset = set;
265325f49c5fSRichard Henderson         }
2654f65a061cSRichard Henderson     }
2655f65a061cSRichard Henderson }
2656f65a061cSRichard Henderson 
2657a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
2658c896fe29Sbellard    given input arguments is dead. Instructions updating dead
2659c896fe29Sbellard    temporaries are removed. */
2660b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s)
2661c896fe29Sbellard {
2662c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
26632616c808SRichard Henderson     int nb_temps = s->nb_temps;
266415fa08f8SRichard Henderson     TCGOp *op, *op_prev;
266525f49c5fSRichard Henderson     TCGRegSet *prefs;
266625f49c5fSRichard Henderson     int i;
266725f49c5fSRichard Henderson 
266825f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
266925f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
267025f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
267125f49c5fSRichard Henderson     }
2672c896fe29Sbellard 
2673ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
26742616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
2675c896fe29Sbellard 
2676eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
267725f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
2678c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
2679c45cb8bbSRichard Henderson         bool have_opc_new2;
2680a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
268125f49c5fSRichard Henderson         TCGTemp *ts;
2682c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2683c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2684c45cb8bbSRichard Henderson 
2685c45cb8bbSRichard Henderson         switch (opc) {
2686c896fe29Sbellard         case INDEX_op_call:
2687c6e113f5Sbellard             {
2688c6e113f5Sbellard                 int call_flags;
268925f49c5fSRichard Henderson                 int nb_call_regs;
2690c6e113f5Sbellard 
2691cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
2692cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
2693efee3746SRichard Henderson                 call_flags = op->args[nb_oargs + nb_iargs + 1];
2694c6e113f5Sbellard 
2695c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
269678505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
2697c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
269825f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
269925f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
2700c6e113f5Sbellard                             goto do_not_remove_call;
2701c6e113f5Sbellard                         }
27029c43b68dSAurelien Jarno                     }
2703c45cb8bbSRichard Henderson                     goto do_remove;
2704152c35aaSRichard Henderson                 }
2705c6e113f5Sbellard             do_not_remove_call:
2706c896fe29Sbellard 
270725f49c5fSRichard Henderson                 /* Output args are dead.  */
2708c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
270925f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
271025f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
2711a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
27126b64b624SAurelien Jarno                     }
271325f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
2714a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
27159c43b68dSAurelien Jarno                     }
271625f49c5fSRichard Henderson                     ts->state = TS_DEAD;
271725f49c5fSRichard Henderson                     la_reset_pref(ts);
271825f49c5fSRichard Henderson 
271925f49c5fSRichard Henderson                     /* Not used -- it will be tcg_target_call_oarg_regs[i].  */
272025f49c5fSRichard Henderson                     op->output_pref[i] = 0;
2721c896fe29Sbellard                 }
2722c896fe29Sbellard 
272378505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
272478505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
2725f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
2726c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
2727f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
2728b9c18f56Saurel32                 }
2729c896fe29Sbellard 
273025f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
2731866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
273225f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
273325f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
2734a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
2735c896fe29Sbellard                     }
2736c896fe29Sbellard                 }
273725f49c5fSRichard Henderson 
273825f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
273925f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
274025f49c5fSRichard Henderson 
274125f49c5fSRichard Henderson                 nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
274225f49c5fSRichard Henderson 
274325f49c5fSRichard Henderson                 /* Input arguments are live for preceding opcodes.  */
274425f49c5fSRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
274525f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
274625f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
274725f49c5fSRichard Henderson                         /* For those arguments that die, and will be allocated
274825f49c5fSRichard Henderson                          * in registers, clear the register set for that arg,
274925f49c5fSRichard Henderson                          * to be filled in below.  For args that will be on
275025f49c5fSRichard Henderson                          * the stack, reset to any available reg.
275125f49c5fSRichard Henderson                          */
275225f49c5fSRichard Henderson                         *la_temp_pref(ts)
275325f49c5fSRichard Henderson                             = (i < nb_call_regs ? 0 :
275425f49c5fSRichard Henderson                                tcg_target_available_regs[ts->type]);
275525f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
275625f49c5fSRichard Henderson                     }
275725f49c5fSRichard Henderson                 }
275825f49c5fSRichard Henderson 
275925f49c5fSRichard Henderson                 /* For each input argument, add its input register to prefs.
276025f49c5fSRichard Henderson                    If a temp is used once, this produces a single set bit.  */
276125f49c5fSRichard Henderson                 for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) {
276225f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
276325f49c5fSRichard Henderson                     if (ts) {
276425f49c5fSRichard Henderson                         tcg_regset_set_reg(*la_temp_pref(ts),
276525f49c5fSRichard Henderson                                            tcg_target_call_iarg_regs[i]);
2766c70fbf0aSRichard Henderson                     }
2767c19f47bfSAurelien Jarno                 }
2768c6e113f5Sbellard             }
2769c896fe29Sbellard             break;
2770765b842aSRichard Henderson         case INDEX_op_insn_start:
2771c896fe29Sbellard             break;
27725ff9d6a4Sbellard         case INDEX_op_discard:
27735ff9d6a4Sbellard             /* mark the temporary as dead */
277425f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
277525f49c5fSRichard Henderson             ts->state = TS_DEAD;
277625f49c5fSRichard Henderson             la_reset_pref(ts);
27775ff9d6a4Sbellard             break;
27781305c451SRichard Henderson 
27791305c451SRichard Henderson         case INDEX_op_add2_i32:
2780c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
2781f1fae40cSRichard Henderson             goto do_addsub2;
27821305c451SRichard Henderson         case INDEX_op_sub2_i32:
2783c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
2784f1fae40cSRichard Henderson             goto do_addsub2;
2785f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
2786c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
2787f1fae40cSRichard Henderson             goto do_addsub2;
2788f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
2789c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
2790f1fae40cSRichard Henderson         do_addsub2:
27911305c451SRichard Henderson             nb_iargs = 4;
27921305c451SRichard Henderson             nb_oargs = 2;
27931305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
27941305c451SRichard Henderson                the low part.  The result can be optimized to a simple
27951305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
27961305c451SRichard Henderson                cpu mode is set to 32 bit.  */
2797b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2798b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
27991305c451SRichard Henderson                     goto do_remove;
28001305c451SRichard Henderson                 }
2801c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
2802c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
2803c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2804efee3746SRichard Henderson                 op->args[1] = op->args[2];
2805efee3746SRichard Henderson                 op->args[2] = op->args[4];
28061305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
28071305c451SRichard Henderson                 nb_iargs = 2;
28081305c451SRichard Henderson                 nb_oargs = 1;
28091305c451SRichard Henderson             }
28101305c451SRichard Henderson             goto do_not_remove;
28111305c451SRichard Henderson 
28121414968aSRichard Henderson         case INDEX_op_mulu2_i32:
2813c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2814c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
2815c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
281603271524SRichard Henderson             goto do_mul2;
2817f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
2818c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2819c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
2820c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
2821f1fae40cSRichard Henderson             goto do_mul2;
2822f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
2823c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2824c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
2825c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
282603271524SRichard Henderson             goto do_mul2;
2827f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
2828c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2829c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
2830c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
283103271524SRichard Henderson             goto do_mul2;
2832f1fae40cSRichard Henderson         do_mul2:
28331414968aSRichard Henderson             nb_iargs = 2;
28341414968aSRichard Henderson             nb_oargs = 2;
2835b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2836b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
283703271524SRichard Henderson                     /* Both parts of the operation are dead.  */
28381414968aSRichard Henderson                     goto do_remove;
28391414968aSRichard Henderson                 }
284003271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
2841c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2842efee3746SRichard Henderson                 op->args[1] = op->args[2];
2843efee3746SRichard Henderson                 op->args[2] = op->args[3];
2844b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
284503271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
2846c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
2847efee3746SRichard Henderson                 op->args[0] = op->args[1];
2848efee3746SRichard Henderson                 op->args[1] = op->args[2];
2849efee3746SRichard Henderson                 op->args[2] = op->args[3];
285003271524SRichard Henderson             } else {
285103271524SRichard Henderson                 goto do_not_remove;
285203271524SRichard Henderson             }
285303271524SRichard Henderson             /* Mark the single-word operation live.  */
28541414968aSRichard Henderson             nb_oargs = 1;
28551414968aSRichard Henderson             goto do_not_remove;
28561414968aSRichard Henderson 
2857c896fe29Sbellard         default:
28581305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
2859c896fe29Sbellard             nb_iargs = def->nb_iargs;
2860c896fe29Sbellard             nb_oargs = def->nb_oargs;
2861c896fe29Sbellard 
2862c896fe29Sbellard             /* Test if the operation can be removed because all
28635ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
28645ff9d6a4Sbellard                implies side effects */
28655ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
2866c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
2867b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
2868c896fe29Sbellard                         goto do_not_remove;
2869c896fe29Sbellard                     }
28709c43b68dSAurelien Jarno                 }
2871152c35aaSRichard Henderson                 goto do_remove;
2872152c35aaSRichard Henderson             }
2873152c35aaSRichard Henderson             goto do_not_remove;
2874152c35aaSRichard Henderson 
28751305c451SRichard Henderson         do_remove:
28760c627cdcSRichard Henderson             tcg_op_remove(s, op);
2877152c35aaSRichard Henderson             break;
2878152c35aaSRichard Henderson 
2879c896fe29Sbellard         do_not_remove:
2880c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
288125f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
288225f49c5fSRichard Henderson 
288325f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
288425f49c5fSRichard Henderson                 op->output_pref[i] = *la_temp_pref(ts);
288525f49c5fSRichard Henderson 
288625f49c5fSRichard Henderson                 /* Output args are dead.  */
288725f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2888a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
28896b64b624SAurelien Jarno                 }
289025f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
2891a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
28929c43b68dSAurelien Jarno                 }
289325f49c5fSRichard Henderson                 ts->state = TS_DEAD;
289425f49c5fSRichard Henderson                 la_reset_pref(ts);
2895c896fe29Sbellard             }
2896c896fe29Sbellard 
289725f49c5fSRichard Henderson             /* If end of basic block, update.  */
2898ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
2899ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
2900b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_COND_BRANCH) {
2901b4cb76e6SRichard Henderson                 la_bb_sync(s, nb_globals, nb_temps);
2902ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
29032616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
29043d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
2905f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
290625f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
290725f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
290825f49c5fSRichard Henderson                 }
2909c896fe29Sbellard             }
2910c896fe29Sbellard 
291125f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
2912866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
291325f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
291425f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2915a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
2916c896fe29Sbellard                 }
2917c19f47bfSAurelien Jarno             }
291825f49c5fSRichard Henderson 
291925f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
2920c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
292125f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
292225f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
292325f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
292425f49c5fSRichard Henderson                        all regs for the type.  */
292525f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
292625f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
292725f49c5fSRichard Henderson                 }
292825f49c5fSRichard Henderson             }
292925f49c5fSRichard Henderson 
293025f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
293125f49c5fSRichard Henderson             switch (opc) {
293225f49c5fSRichard Henderson             case INDEX_op_mov_i32:
293325f49c5fSRichard Henderson             case INDEX_op_mov_i64:
293425f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
293525f49c5fSRichard Henderson                    have proper constraints.  That said, special case
293625f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
293725f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
293825f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
293925f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
294025f49c5fSRichard Henderson                 }
294125f49c5fSRichard Henderson                 break;
294225f49c5fSRichard Henderson 
294325f49c5fSRichard Henderson             default:
294425f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
294525f49c5fSRichard Henderson                     const TCGArgConstraint *ct = &def->args_ct[i];
294625f49c5fSRichard Henderson                     TCGRegSet set, *pset;
294725f49c5fSRichard Henderson 
294825f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
294925f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
295025f49c5fSRichard Henderson                     set = *pset;
295125f49c5fSRichard Henderson 
29529be0d080SRichard Henderson                     set &= ct->regs;
2953bc2b17e6SRichard Henderson                     if (ct->ialias) {
295425f49c5fSRichard Henderson                         set &= op->output_pref[ct->alias_index];
295525f49c5fSRichard Henderson                     }
295625f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
295725f49c5fSRichard Henderson                     if (set == 0) {
29589be0d080SRichard Henderson                         set = ct->regs;
295925f49c5fSRichard Henderson                     }
296025f49c5fSRichard Henderson                     *pset = set;
296125f49c5fSRichard Henderson                 }
296225f49c5fSRichard Henderson                 break;
2963c896fe29Sbellard             }
2964c896fe29Sbellard             break;
2965c896fe29Sbellard         }
2966bee158cbSRichard Henderson         op->life = arg_life;
2967c896fe29Sbellard     }
29681ff0a2c5SEvgeny Voevodin }
2969c896fe29Sbellard 
29705a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
2971b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s)
29725a18407fSRichard Henderson {
29735a18407fSRichard Henderson     int nb_globals = s->nb_globals;
297415fa08f8SRichard Henderson     int nb_temps, i;
29755a18407fSRichard Henderson     bool changes = false;
297615fa08f8SRichard Henderson     TCGOp *op, *op_next;
29775a18407fSRichard Henderson 
29785a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
29795a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
29805a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
29815a18407fSRichard Henderson         if (its->indirect_reg) {
29825a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
29835a18407fSRichard Henderson             dts->type = its->type;
29845a18407fSRichard Henderson             dts->base_type = its->base_type;
2985b83eabeaSRichard Henderson             its->state_ptr = dts;
2986b83eabeaSRichard Henderson         } else {
2987b83eabeaSRichard Henderson             its->state_ptr = NULL;
29885a18407fSRichard Henderson         }
2989b83eabeaSRichard Henderson         /* All globals begin dead.  */
2990b83eabeaSRichard Henderson         its->state = TS_DEAD;
29915a18407fSRichard Henderson     }
2992b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
2993b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
2994b83eabeaSRichard Henderson         its->state_ptr = NULL;
2995b83eabeaSRichard Henderson         its->state = TS_DEAD;
2996b83eabeaSRichard Henderson     }
29975a18407fSRichard Henderson 
299815fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
29995a18407fSRichard Henderson         TCGOpcode opc = op->opc;
30005a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
30015a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
30025a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
3003b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
30045a18407fSRichard Henderson 
30055a18407fSRichard Henderson         if (opc == INDEX_op_call) {
3006cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
3007cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
3008efee3746SRichard Henderson             call_flags = op->args[nb_oargs + nb_iargs + 1];
30095a18407fSRichard Henderson         } else {
30105a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
30115a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
30125a18407fSRichard Henderson 
30135a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
3014b4cb76e6SRichard Henderson             if (def->flags & TCG_OPF_COND_BRANCH) {
3015b4cb76e6SRichard Henderson                 /* Like reading globals: sync_globals */
3016b4cb76e6SRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
3017b4cb76e6SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
30185a18407fSRichard Henderson                 /* Like writing globals: save_globals */
30195a18407fSRichard Henderson                 call_flags = 0;
30205a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
30215a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
30225a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
30235a18407fSRichard Henderson             } else {
30245a18407fSRichard Henderson                 /* No effect on globals.  */
30255a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
30265a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
30275a18407fSRichard Henderson             }
30285a18407fSRichard Henderson         }
30295a18407fSRichard Henderson 
30305a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
30315a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3032b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3033b83eabeaSRichard Henderson             if (arg_ts) {
3034b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3035b83eabeaSRichard Henderson                 if (dir_ts && arg_ts->state == TS_DEAD) {
3036b83eabeaSRichard Henderson                     TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
30375a18407fSRichard Henderson                                       ? INDEX_op_ld_i32
30385a18407fSRichard Henderson                                       : INDEX_op_ld_i64);
3039ac1043f6SEmilio G. Cota                     TCGOp *lop = tcg_op_insert_before(s, op, lopc);
30405a18407fSRichard Henderson 
3041b83eabeaSRichard Henderson                     lop->args[0] = temp_arg(dir_ts);
3042b83eabeaSRichard Henderson                     lop->args[1] = temp_arg(arg_ts->mem_base);
3043b83eabeaSRichard Henderson                     lop->args[2] = arg_ts->mem_offset;
30445a18407fSRichard Henderson 
30455a18407fSRichard Henderson                     /* Loaded, but synced with memory.  */
3046b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
30475a18407fSRichard Henderson                 }
30485a18407fSRichard Henderson             }
30495a18407fSRichard Henderson         }
30505a18407fSRichard Henderson 
30515a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
30525a18407fSRichard Henderson            No action is required except keeping temp_state up to date
30535a18407fSRichard Henderson            so that we reload when needed.  */
30545a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3055b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
3056b83eabeaSRichard Henderson             if (arg_ts) {
3057b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3058b83eabeaSRichard Henderson                 if (dir_ts) {
3059b83eabeaSRichard Henderson                     op->args[i] = temp_arg(dir_ts);
30605a18407fSRichard Henderson                     changes = true;
30615a18407fSRichard Henderson                     if (IS_DEAD_ARG(i)) {
3062b83eabeaSRichard Henderson                         arg_ts->state = TS_DEAD;
30635a18407fSRichard Henderson                     }
30645a18407fSRichard Henderson                 }
30655a18407fSRichard Henderson             }
30665a18407fSRichard Henderson         }
30675a18407fSRichard Henderson 
30685a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
30695a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
30705a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
30715a18407fSRichard Henderson             /* Nothing to do */
30725a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
30735a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
30745a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
30755a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
3076b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3077b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3078b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
30795a18407fSRichard Henderson             }
30805a18407fSRichard Henderson         } else {
30815a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
30825a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
30835a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
3084b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
3085b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
3086b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
30875a18407fSRichard Henderson             }
30885a18407fSRichard Henderson         }
30895a18407fSRichard Henderson 
30905a18407fSRichard Henderson         /* Outputs become available.  */
309161f15c48SRichard Henderson         if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) {
309261f15c48SRichard Henderson             arg_ts = arg_temp(op->args[0]);
309361f15c48SRichard Henderson             dir_ts = arg_ts->state_ptr;
309461f15c48SRichard Henderson             if (dir_ts) {
309561f15c48SRichard Henderson                 op->args[0] = temp_arg(dir_ts);
309661f15c48SRichard Henderson                 changes = true;
309761f15c48SRichard Henderson 
309861f15c48SRichard Henderson                 /* The output is now live and modified.  */
309961f15c48SRichard Henderson                 arg_ts->state = 0;
310061f15c48SRichard Henderson 
310161f15c48SRichard Henderson                 if (NEED_SYNC_ARG(0)) {
310261f15c48SRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
310361f15c48SRichard Henderson                                       ? INDEX_op_st_i32
310461f15c48SRichard Henderson                                       : INDEX_op_st_i64);
310561f15c48SRichard Henderson                     TCGOp *sop = tcg_op_insert_after(s, op, sopc);
310661f15c48SRichard Henderson                     TCGTemp *out_ts = dir_ts;
310761f15c48SRichard Henderson 
310861f15c48SRichard Henderson                     if (IS_DEAD_ARG(0)) {
310961f15c48SRichard Henderson                         out_ts = arg_temp(op->args[1]);
311061f15c48SRichard Henderson                         arg_ts->state = TS_DEAD;
311161f15c48SRichard Henderson                         tcg_op_remove(s, op);
311261f15c48SRichard Henderson                     } else {
311361f15c48SRichard Henderson                         arg_ts->state = TS_MEM;
311461f15c48SRichard Henderson                     }
311561f15c48SRichard Henderson 
311661f15c48SRichard Henderson                     sop->args[0] = temp_arg(out_ts);
311761f15c48SRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
311861f15c48SRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
311961f15c48SRichard Henderson                 } else {
312061f15c48SRichard Henderson                     tcg_debug_assert(!IS_DEAD_ARG(0));
312161f15c48SRichard Henderson                 }
312261f15c48SRichard Henderson             }
312361f15c48SRichard Henderson         } else {
31245a18407fSRichard Henderson             for (i = 0; i < nb_oargs; i++) {
3125b83eabeaSRichard Henderson                 arg_ts = arg_temp(op->args[i]);
3126b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
3127b83eabeaSRichard Henderson                 if (!dir_ts) {
31285a18407fSRichard Henderson                     continue;
31295a18407fSRichard Henderson                 }
3130b83eabeaSRichard Henderson                 op->args[i] = temp_arg(dir_ts);
31315a18407fSRichard Henderson                 changes = true;
31325a18407fSRichard Henderson 
31335a18407fSRichard Henderson                 /* The output is now live and modified.  */
3134b83eabeaSRichard Henderson                 arg_ts->state = 0;
31355a18407fSRichard Henderson 
31365a18407fSRichard Henderson                 /* Sync outputs upon their last write.  */
31375a18407fSRichard Henderson                 if (NEED_SYNC_ARG(i)) {
3138b83eabeaSRichard Henderson                     TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
31395a18407fSRichard Henderson                                       ? INDEX_op_st_i32
31405a18407fSRichard Henderson                                       : INDEX_op_st_i64);
3141ac1043f6SEmilio G. Cota                     TCGOp *sop = tcg_op_insert_after(s, op, sopc);
31425a18407fSRichard Henderson 
3143b83eabeaSRichard Henderson                     sop->args[0] = temp_arg(dir_ts);
3144b83eabeaSRichard Henderson                     sop->args[1] = temp_arg(arg_ts->mem_base);
3145b83eabeaSRichard Henderson                     sop->args[2] = arg_ts->mem_offset;
31465a18407fSRichard Henderson 
3147b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
31485a18407fSRichard Henderson                 }
31495a18407fSRichard Henderson                 /* Drop outputs that are dead.  */
31505a18407fSRichard Henderson                 if (IS_DEAD_ARG(i)) {
3151b83eabeaSRichard Henderson                     arg_ts->state = TS_DEAD;
31525a18407fSRichard Henderson                 }
31535a18407fSRichard Henderson             }
31545a18407fSRichard Henderson         }
315561f15c48SRichard Henderson     }
31565a18407fSRichard Henderson 
31575a18407fSRichard Henderson     return changes;
31585a18407fSRichard Henderson }
31595a18407fSRichard Henderson 
31608d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
3161c896fe29Sbellard static void dump_regs(TCGContext *s)
3162c896fe29Sbellard {
3163c896fe29Sbellard     TCGTemp *ts;
3164c896fe29Sbellard     int i;
3165c896fe29Sbellard     char buf[64];
3166c896fe29Sbellard 
3167c896fe29Sbellard     for(i = 0; i < s->nb_temps; i++) {
3168c896fe29Sbellard         ts = &s->temps[i];
316943439139SRichard Henderson         printf("  %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3170c896fe29Sbellard         switch(ts->val_type) {
3171c896fe29Sbellard         case TEMP_VAL_REG:
3172c896fe29Sbellard             printf("%s", tcg_target_reg_names[ts->reg]);
3173c896fe29Sbellard             break;
3174c896fe29Sbellard         case TEMP_VAL_MEM:
3175b3a62939SRichard Henderson             printf("%d(%s)", (int)ts->mem_offset,
3176b3a62939SRichard Henderson                    tcg_target_reg_names[ts->mem_base->reg]);
3177c896fe29Sbellard             break;
3178c896fe29Sbellard         case TEMP_VAL_CONST:
3179c896fe29Sbellard             printf("$0x%" TCG_PRIlx, ts->val);
3180c896fe29Sbellard             break;
3181c896fe29Sbellard         case TEMP_VAL_DEAD:
3182c896fe29Sbellard             printf("D");
3183c896fe29Sbellard             break;
3184c896fe29Sbellard         default:
3185c896fe29Sbellard             printf("???");
3186c896fe29Sbellard             break;
3187c896fe29Sbellard         }
3188c896fe29Sbellard         printf("\n");
3189c896fe29Sbellard     }
3190c896fe29Sbellard 
3191c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
3192f8b2f202SRichard Henderson         if (s->reg_to_temp[i] != NULL) {
3193c896fe29Sbellard             printf("%s: %s\n",
3194c896fe29Sbellard                    tcg_target_reg_names[i],
3195f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i]));
3196c896fe29Sbellard         }
3197c896fe29Sbellard     }
3198c896fe29Sbellard }
3199c896fe29Sbellard 
3200c896fe29Sbellard static void check_regs(TCGContext *s)
3201c896fe29Sbellard {
3202869938aeSRichard Henderson     int reg;
3203b6638662SRichard Henderson     int k;
3204c896fe29Sbellard     TCGTemp *ts;
3205c896fe29Sbellard     char buf[64];
3206c896fe29Sbellard 
3207c896fe29Sbellard     for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
3208f8b2f202SRichard Henderson         ts = s->reg_to_temp[reg];
3209f8b2f202SRichard Henderson         if (ts != NULL) {
3210f8b2f202SRichard Henderson             if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) {
3211c896fe29Sbellard                 printf("Inconsistency for register %s:\n",
3212c896fe29Sbellard                        tcg_target_reg_names[reg]);
3213b03cce8eSbellard                 goto fail;
3214c896fe29Sbellard             }
3215c896fe29Sbellard         }
3216c896fe29Sbellard     }
3217c896fe29Sbellard     for (k = 0; k < s->nb_temps; k++) {
3218c896fe29Sbellard         ts = &s->temps[k];
3219ee17db83SRichard Henderson         if (ts->val_type == TEMP_VAL_REG
3220ee17db83SRichard Henderson             && ts->kind != TEMP_FIXED
3221f8b2f202SRichard Henderson             && s->reg_to_temp[ts->reg] != ts) {
3222c896fe29Sbellard             printf("Inconsistency for temp %s:\n",
3223f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3224b03cce8eSbellard         fail:
3225c896fe29Sbellard             printf("reg state:\n");
3226c896fe29Sbellard             dump_regs(s);
3227c896fe29Sbellard             tcg_abort();
3228c896fe29Sbellard         }
3229c896fe29Sbellard     }
3230c896fe29Sbellard }
3231c896fe29Sbellard #endif
3232c896fe29Sbellard 
32332272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
3234c896fe29Sbellard {
32359b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64)
32369b9c37c3SRichard Henderson     /* Sparc64 stack is accessed with offset of 2047 */
3237b591dc59SBlue Swirl     s->current_frame_offset = (s->current_frame_offset +
3238b591dc59SBlue Swirl                                (tcg_target_long)sizeof(tcg_target_long) - 1) &
3239b591dc59SBlue Swirl         ~(sizeof(tcg_target_long) - 1);
3240f44c9960SBlue Swirl #endif
3241b591dc59SBlue Swirl     if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
3242b591dc59SBlue Swirl         s->frame_end) {
32435ff9d6a4Sbellard         tcg_abort();
3244b591dc59SBlue Swirl     }
3245c896fe29Sbellard     ts->mem_offset = s->current_frame_offset;
3246b3a62939SRichard Henderson     ts->mem_base = s->frame_temp;
3247c896fe29Sbellard     ts->mem_allocated = 1;
3248e2c6d1b4SRichard Henderson     s->current_frame_offset += sizeof(tcg_target_long);
3249c896fe29Sbellard }
3250c896fe29Sbellard 
3251b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
3252b3915dbbSRichard Henderson 
325359d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
325459d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
325559d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
3256c896fe29Sbellard {
3257*e01fa97dSRichard Henderson     if (temp_readonly(ts)) {
325859d7c14eSRichard Henderson         return;
325959d7c14eSRichard Henderson     }
326059d7c14eSRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
326159d7c14eSRichard Henderson         s->reg_to_temp[ts->reg] = NULL;
326259d7c14eSRichard Henderson     }
326359d7c14eSRichard Henderson     ts->val_type = (free_or_dead < 0
3264ee17db83SRichard Henderson                     || ts->kind != TEMP_NORMAL
326559d7c14eSRichard Henderson                     ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
326659d7c14eSRichard Henderson }
3267c896fe29Sbellard 
326859d7c14eSRichard Henderson /* Mark a temporary as dead.  */
326959d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
327059d7c14eSRichard Henderson {
327159d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
327259d7c14eSRichard Henderson }
327359d7c14eSRichard Henderson 
327459d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
327559d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
327659d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
327759d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
327898b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
327998b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
328059d7c14eSRichard Henderson {
3281*e01fa97dSRichard Henderson     if (temp_readonly(ts)) {
328259d7c14eSRichard Henderson         return;
328359d7c14eSRichard Henderson     }
328459d7c14eSRichard Henderson     if (!ts->mem_coherent) {
32857f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
32862272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
328759d7c14eSRichard Henderson         }
328859d7c14eSRichard Henderson         switch (ts->val_type) {
328959d7c14eSRichard Henderson         case TEMP_VAL_CONST:
329059d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
329159d7c14eSRichard Henderson                require it later in a register, so attempt to store the
329259d7c14eSRichard Henderson                constant to memory directly.  */
329359d7c14eSRichard Henderson             if (free_or_dead
329459d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
329559d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
329659d7c14eSRichard Henderson                 break;
329759d7c14eSRichard Henderson             }
329859d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
329998b4e186SRichard Henderson                       allocated_regs, preferred_regs);
330059d7c14eSRichard Henderson             /* fallthrough */
330159d7c14eSRichard Henderson 
330259d7c14eSRichard Henderson         case TEMP_VAL_REG:
330359d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
330459d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
330559d7c14eSRichard Henderson             break;
330659d7c14eSRichard Henderson 
330759d7c14eSRichard Henderson         case TEMP_VAL_MEM:
330859d7c14eSRichard Henderson             break;
330959d7c14eSRichard Henderson 
331059d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
331159d7c14eSRichard Henderson         default:
331259d7c14eSRichard Henderson             tcg_abort();
3313c896fe29Sbellard         }
33147f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
33157f6ceedfSAurelien Jarno     }
331659d7c14eSRichard Henderson     if (free_or_dead) {
331759d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
331859d7c14eSRichard Henderson     }
331959d7c14eSRichard Henderson }
33207f6ceedfSAurelien Jarno 
33217f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
3322b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
33237f6ceedfSAurelien Jarno {
3324f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
3325f8b2f202SRichard Henderson     if (ts != NULL) {
332698b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
3327c896fe29Sbellard     }
3328c896fe29Sbellard }
3329c896fe29Sbellard 
3330b016486eSRichard Henderson /**
3331b016486eSRichard Henderson  * tcg_reg_alloc:
3332b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
3333b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
3334b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
3335b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
3336b016486eSRichard Henderson  *
3337b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
3338b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
3339b016486eSRichard Henderson  */
3340b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
3341b016486eSRichard Henderson                             TCGRegSet allocated_regs,
3342b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
3343c896fe29Sbellard {
3344b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
3345b016486eSRichard Henderson     TCGRegSet reg_ct[2];
334691478cefSRichard Henderson     const int *order;
3347c896fe29Sbellard 
3348b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
3349b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
3350b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
3351b016486eSRichard Henderson 
3352b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
3353b016486eSRichard Henderson        or if the preference made no difference.  */
3354b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
3355b016486eSRichard Henderson 
335691478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
3357c896fe29Sbellard 
3358b016486eSRichard Henderson     /* Try free registers, preferences first.  */
3359b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3360b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3361b016486eSRichard Henderson 
3362b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3363b016486eSRichard Henderson             /* One register in the set.  */
3364b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3365b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
3366c896fe29Sbellard                 return reg;
3367c896fe29Sbellard             }
3368b016486eSRichard Henderson         } else {
336991478cefSRichard Henderson             for (i = 0; i < n; i++) {
3370b016486eSRichard Henderson                 TCGReg reg = order[i];
3371b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
3372b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
3373b016486eSRichard Henderson                     return reg;
3374b016486eSRichard Henderson                 }
3375b016486eSRichard Henderson             }
3376b016486eSRichard Henderson         }
3377b016486eSRichard Henderson     }
3378b016486eSRichard Henderson 
3379b016486eSRichard Henderson     /* We must spill something.  */
3380b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3381b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3382b016486eSRichard Henderson 
3383b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3384b016486eSRichard Henderson             /* One register in the set.  */
3385b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3386b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
3387c896fe29Sbellard             return reg;
3388b016486eSRichard Henderson         } else {
3389b016486eSRichard Henderson             for (i = 0; i < n; i++) {
3390b016486eSRichard Henderson                 TCGReg reg = order[i];
3391b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
3392b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
3393b016486eSRichard Henderson                     return reg;
3394b016486eSRichard Henderson                 }
3395b016486eSRichard Henderson             }
3396c896fe29Sbellard         }
3397c896fe29Sbellard     }
3398c896fe29Sbellard 
3399c896fe29Sbellard     tcg_abort();
3400c896fe29Sbellard }
3401c896fe29Sbellard 
340240ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
340340ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
340440ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
3405b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
340640ae5c62SRichard Henderson {
340740ae5c62SRichard Henderson     TCGReg reg;
340840ae5c62SRichard Henderson 
340940ae5c62SRichard Henderson     switch (ts->val_type) {
341040ae5c62SRichard Henderson     case TEMP_VAL_REG:
341140ae5c62SRichard Henderson         return;
341240ae5c62SRichard Henderson     case TEMP_VAL_CONST:
3413b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3414b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
34150a6a8bc8SRichard Henderson         if (ts->type <= TCG_TYPE_I64) {
341640ae5c62SRichard Henderson             tcg_out_movi(s, ts->type, reg, ts->val);
34170a6a8bc8SRichard Henderson         } else {
34184e186175SRichard Henderson             uint64_t val = ts->val;
34194e186175SRichard Henderson             MemOp vece = MO_64;
34204e186175SRichard Henderson 
34214e186175SRichard Henderson             /*
34224e186175SRichard Henderson              * Find the minimal vector element that matches the constant.
34234e186175SRichard Henderson              * The targets will, in general, have to do this search anyway,
34244e186175SRichard Henderson              * do this generically.
34254e186175SRichard Henderson              */
34264e186175SRichard Henderson             if (TCG_TARGET_REG_BITS == 32) {
34274e186175SRichard Henderson                 val = dup_const(MO_32, val);
34284e186175SRichard Henderson                 vece = MO_32;
34294e186175SRichard Henderson             }
34304e186175SRichard Henderson             if (val == dup_const(MO_8, val)) {
34314e186175SRichard Henderson                 vece = MO_8;
34324e186175SRichard Henderson             } else if (val == dup_const(MO_16, val)) {
34334e186175SRichard Henderson                 vece = MO_16;
34344e186175SRichard Henderson             } else if (TCG_TARGET_REG_BITS == 64 &&
34354e186175SRichard Henderson                        val == dup_const(MO_32, val)) {
34364e186175SRichard Henderson                 vece = MO_32;
34374e186175SRichard Henderson             }
34384e186175SRichard Henderson 
34394e186175SRichard Henderson             tcg_out_dupi_vec(s, ts->type, vece, reg, ts->val);
34400a6a8bc8SRichard Henderson         }
344140ae5c62SRichard Henderson         ts->mem_coherent = 0;
344240ae5c62SRichard Henderson         break;
344340ae5c62SRichard Henderson     case TEMP_VAL_MEM:
3444b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3445b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
344640ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
344740ae5c62SRichard Henderson         ts->mem_coherent = 1;
344840ae5c62SRichard Henderson         break;
344940ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
345040ae5c62SRichard Henderson     default:
345140ae5c62SRichard Henderson         tcg_abort();
345240ae5c62SRichard Henderson     }
345340ae5c62SRichard Henderson     ts->reg = reg;
345440ae5c62SRichard Henderson     ts->val_type = TEMP_VAL_REG;
345540ae5c62SRichard Henderson     s->reg_to_temp[reg] = ts;
345640ae5c62SRichard Henderson }
345740ae5c62SRichard Henderson 
345859d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
3459e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
346059d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
34611ad80729SAurelien Jarno {
34622c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
3463eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
3464*e01fa97dSRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || temp_readonly(ts));
34651ad80729SAurelien Jarno }
34661ad80729SAurelien Jarno 
34679814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
3468641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
3469641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
3470641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
3471641d5fbeSbellard {
3472ac3b8891SRichard Henderson     int i, n;
3473641d5fbeSbellard 
3474ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
3475b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
3476641d5fbeSbellard     }
3477e5097dc8Sbellard }
3478e5097dc8Sbellard 
34793d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
34803d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
34813d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
34823d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
34833d5c5f87SAurelien Jarno {
3484ac3b8891SRichard Henderson     int i, n;
34853d5c5f87SAurelien Jarno 
3486ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
348712b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
348812b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
3489ee17db83SRichard Henderson                          || ts->kind == TEMP_FIXED
349012b9b11aSRichard Henderson                          || ts->mem_coherent);
34913d5c5f87SAurelien Jarno     }
34923d5c5f87SAurelien Jarno }
34933d5c5f87SAurelien Jarno 
3494e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
3495e8996ee0Sbellard    all globals are stored at their canonical location. */
3496e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
3497e5097dc8Sbellard {
3498e5097dc8Sbellard     int i;
3499e5097dc8Sbellard 
3500c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
3501b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
3502ee17db83SRichard Henderson         if (ts->kind == TEMP_LOCAL) {
3503b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
3504641d5fbeSbellard         } else {
35052c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
3506eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
3507eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3508c896fe29Sbellard         }
3509641d5fbeSbellard     }
3510e8996ee0Sbellard 
3511e8996ee0Sbellard     save_globals(s, allocated_regs);
3512c896fe29Sbellard }
3513c896fe29Sbellard 
3514bab1671fSRichard Henderson /*
3515b4cb76e6SRichard Henderson  * At a conditional branch, we assume all temporaries are dead and
3516b4cb76e6SRichard Henderson  * all globals and local temps are synced to their location.
3517b4cb76e6SRichard Henderson  */
3518b4cb76e6SRichard Henderson static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
3519b4cb76e6SRichard Henderson {
3520b4cb76e6SRichard Henderson     sync_globals(s, allocated_regs);
3521b4cb76e6SRichard Henderson 
3522b4cb76e6SRichard Henderson     for (int i = s->nb_globals; i < s->nb_temps; i++) {
3523b4cb76e6SRichard Henderson         TCGTemp *ts = &s->temps[i];
3524b4cb76e6SRichard Henderson         /*
3525b4cb76e6SRichard Henderson          * The liveness analysis already ensures that temps are dead.
3526b4cb76e6SRichard Henderson          * Keep tcg_debug_asserts for safety.
3527b4cb76e6SRichard Henderson          */
3528ee17db83SRichard Henderson         if (ts->kind == TEMP_LOCAL) {
3529b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type != TEMP_VAL_REG || ts->mem_coherent);
3530b4cb76e6SRichard Henderson         } else {
3531b4cb76e6SRichard Henderson             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3532b4cb76e6SRichard Henderson         }
3533b4cb76e6SRichard Henderson     }
3534b4cb76e6SRichard Henderson }
3535b4cb76e6SRichard Henderson 
3536b4cb76e6SRichard Henderson /*
3537bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_movi_*.
3538bab1671fSRichard Henderson  */
35390fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
3540ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
3541ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
3542e8996ee0Sbellard {
3543d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3544*e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
354559d7c14eSRichard Henderson 
354659d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
3547f8b2f202SRichard Henderson     if (ots->val_type == TEMP_VAL_REG) {
3548f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = NULL;
3549f8b2f202SRichard Henderson     }
3550e8996ee0Sbellard     ots->val_type = TEMP_VAL_CONST;
3551e8996ee0Sbellard     ots->val = val;
355259d7c14eSRichard Henderson     ots->mem_coherent = 0;
3553ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
3554ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
355559d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
3556f8bf00f1SRichard Henderson         temp_dead(s, ots);
35574c4e1ab2SAurelien Jarno     }
3558e8996ee0Sbellard }
3559e8996ee0Sbellard 
3560dd186292SRichard Henderson static void tcg_reg_alloc_movi(TCGContext *s, const TCGOp *op)
35610fe4fca4SPaolo Bonzini {
356243439139SRichard Henderson     TCGTemp *ots = arg_temp(op->args[0]);
3563dd186292SRichard Henderson     tcg_target_ulong val = op->args[1];
35640fe4fca4SPaolo Bonzini 
356569e3706dSRichard Henderson     tcg_reg_alloc_do_movi(s, ots, val, op->life, op->output_pref[0]);
35660fe4fca4SPaolo Bonzini }
35670fe4fca4SPaolo Bonzini 
3568bab1671fSRichard Henderson /*
3569bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
3570bab1671fSRichard Henderson  */
3571dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
3572c896fe29Sbellard {
3573dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
357469e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
3575c896fe29Sbellard     TCGTemp *ts, *ots;
3576450445d5SRichard Henderson     TCGType otype, itype;
3577c896fe29Sbellard 
3578d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
357969e3706dSRichard Henderson     preferred_regs = op->output_pref[0];
358043439139SRichard Henderson     ots = arg_temp(op->args[0]);
358143439139SRichard Henderson     ts = arg_temp(op->args[1]);
3582450445d5SRichard Henderson 
3583d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3584*e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
3585d63e3b6eSRichard Henderson 
3586450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
3587450445d5SRichard Henderson     otype = ots->type;
3588450445d5SRichard Henderson     itype = ts->type;
3589c896fe29Sbellard 
35900fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
35910fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
35920fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
35930fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
35940fe4fca4SPaolo Bonzini             temp_dead(s, ts);
35950fe4fca4SPaolo Bonzini         }
359669e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
35970fe4fca4SPaolo Bonzini         return;
35980fe4fca4SPaolo Bonzini     }
35990fe4fca4SPaolo Bonzini 
36000fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
36010fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
36020fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
36030fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
36040fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
360569e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
360669e3706dSRichard Henderson                   allocated_regs, preferred_regs);
3607c29c1d7eSAurelien Jarno     }
3608c29c1d7eSAurelien Jarno 
36090fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
3610d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
3611c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
3612c29c1d7eSAurelien Jarno            liveness analysis disabled). */
3613eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
3614c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
36152272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
3616c29c1d7eSAurelien Jarno         }
3617b3a62939SRichard Henderson         tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset);
3618c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
3619f8bf00f1SRichard Henderson             temp_dead(s, ts);
3620c29c1d7eSAurelien Jarno         }
3621f8bf00f1SRichard Henderson         temp_dead(s, ots);
3622e8996ee0Sbellard     } else {
3623ee17db83SRichard Henderson         if (IS_DEAD_ARG(1) && ts->kind != TEMP_FIXED) {
3624c29c1d7eSAurelien Jarno             /* the mov can be suppressed */
3625c29c1d7eSAurelien Jarno             if (ots->val_type == TEMP_VAL_REG) {
3626f8b2f202SRichard Henderson                 s->reg_to_temp[ots->reg] = NULL;
3627c896fe29Sbellard             }
3628c29c1d7eSAurelien Jarno             ots->reg = ts->reg;
3629f8bf00f1SRichard Henderson             temp_dead(s, ts);
3630c29c1d7eSAurelien Jarno         } else {
3631c29c1d7eSAurelien Jarno             if (ots->val_type != TEMP_VAL_REG) {
3632c29c1d7eSAurelien Jarno                 /* When allocating a new register, make sure to not spill the
3633c29c1d7eSAurelien Jarno                    input one. */
3634c29c1d7eSAurelien Jarno                 tcg_regset_set_reg(allocated_regs, ts->reg);
3635450445d5SRichard Henderson                 ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
363669e3706dSRichard Henderson                                          allocated_regs, preferred_regs,
3637b016486eSRichard Henderson                                          ots->indirect_base);
3638c29c1d7eSAurelien Jarno             }
363978113e83SRichard Henderson             if (!tcg_out_mov(s, otype, ots->reg, ts->reg)) {
3640240c08d0SRichard Henderson                 /*
3641240c08d0SRichard Henderson                  * Cross register class move not supported.
3642240c08d0SRichard Henderson                  * Store the source register into the destination slot
3643240c08d0SRichard Henderson                  * and leave the destination temp as TEMP_VAL_MEM.
3644240c08d0SRichard Henderson                  */
3645*e01fa97dSRichard Henderson                 assert(!temp_readonly(ots));
3646240c08d0SRichard Henderson                 if (!ts->mem_allocated) {
3647240c08d0SRichard Henderson                     temp_allocate_frame(s, ots);
3648240c08d0SRichard Henderson                 }
3649240c08d0SRichard Henderson                 tcg_out_st(s, ts->type, ts->reg,
3650240c08d0SRichard Henderson                            ots->mem_base->reg, ots->mem_offset);
3651240c08d0SRichard Henderson                 ots->mem_coherent = 1;
3652240c08d0SRichard Henderson                 temp_free_or_dead(s, ots, -1);
3653240c08d0SRichard Henderson                 return;
365478113e83SRichard Henderson             }
3655c29c1d7eSAurelien Jarno         }
3656c896fe29Sbellard         ots->val_type = TEMP_VAL_REG;
3657c896fe29Sbellard         ots->mem_coherent = 0;
3658f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3659ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(0)) {
366098b4e186SRichard Henderson             temp_sync(s, ots, allocated_regs, 0, 0);
3661c29c1d7eSAurelien Jarno         }
3662ec7a869dSAurelien Jarno     }
3663c896fe29Sbellard }
3664c896fe29Sbellard 
3665bab1671fSRichard Henderson /*
3666bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
3667bab1671fSRichard Henderson  */
3668bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
3669bab1671fSRichard Henderson {
3670bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
3671bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
3672bab1671fSRichard Henderson     TCGTemp *its, *ots;
3673bab1671fSRichard Henderson     TCGType itype, vtype;
3674d6ecb4a9SRichard Henderson     intptr_t endian_fixup;
3675bab1671fSRichard Henderson     unsigned vece;
3676bab1671fSRichard Henderson     bool ok;
3677bab1671fSRichard Henderson 
3678bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
3679bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
3680bab1671fSRichard Henderson 
3681bab1671fSRichard Henderson     /* ENV should not be modified.  */
3682*e01fa97dSRichard Henderson     tcg_debug_assert(!temp_readonly(ots));
3683bab1671fSRichard Henderson 
3684bab1671fSRichard Henderson     itype = its->type;
3685bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
3686bab1671fSRichard Henderson     vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
3687bab1671fSRichard Henderson 
3688bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
3689bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
3690bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
3691bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
3692bab1671fSRichard Henderson             temp_dead(s, its);
3693bab1671fSRichard Henderson         }
3694bab1671fSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, op->output_pref[0]);
3695bab1671fSRichard Henderson         return;
3696bab1671fSRichard Henderson     }
3697bab1671fSRichard Henderson 
36989be0d080SRichard Henderson     dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].regs;
36999be0d080SRichard Henderson     dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].regs;
3700bab1671fSRichard Henderson 
3701bab1671fSRichard Henderson     /* Allocate the output register now.  */
3702bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
3703bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
3704bab1671fSRichard Henderson 
3705bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
3706bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
3707bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
3708bab1671fSRichard Henderson         }
3709bab1671fSRichard Henderson         ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
3710bab1671fSRichard Henderson                                  op->output_pref[0], ots->indirect_base);
3711bab1671fSRichard Henderson         ots->val_type = TEMP_VAL_REG;
3712bab1671fSRichard Henderson         ots->mem_coherent = 0;
3713bab1671fSRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3714bab1671fSRichard Henderson     }
3715bab1671fSRichard Henderson 
3716bab1671fSRichard Henderson     switch (its->val_type) {
3717bab1671fSRichard Henderson     case TEMP_VAL_REG:
3718bab1671fSRichard Henderson         /*
3719bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
3720bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
3721bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
3722bab1671fSRichard Henderson          */
3723bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
3724bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
3725bab1671fSRichard Henderson                 goto done;
3726bab1671fSRichard Henderson             }
3727bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
3728bab1671fSRichard Henderson         }
3729bab1671fSRichard Henderson         if (!its->mem_coherent) {
3730bab1671fSRichard Henderson             /*
3731bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
3732bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
3733bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
3734bab1671fSRichard Henderson              */
3735bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
3736bab1671fSRichard Henderson                 break;
3737bab1671fSRichard Henderson             }
3738bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
3739bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
3740bab1671fSRichard Henderson         }
3741bab1671fSRichard Henderson         /* fall through */
3742bab1671fSRichard Henderson 
3743bab1671fSRichard Henderson     case TEMP_VAL_MEM:
3744d6ecb4a9SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
3745d6ecb4a9SRichard Henderson         endian_fixup = itype == TCG_TYPE_I32 ? 4 : 8;
3746d6ecb4a9SRichard Henderson         endian_fixup -= 1 << vece;
3747d6ecb4a9SRichard Henderson #else
3748d6ecb4a9SRichard Henderson         endian_fixup = 0;
3749d6ecb4a9SRichard Henderson #endif
3750d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
3751d6ecb4a9SRichard Henderson                              its->mem_offset + endian_fixup)) {
3752d6ecb4a9SRichard Henderson             goto done;
3753d6ecb4a9SRichard Henderson         }
3754bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
3755bab1671fSRichard Henderson         break;
3756bab1671fSRichard Henderson 
3757bab1671fSRichard Henderson     default:
3758bab1671fSRichard Henderson         g_assert_not_reached();
3759bab1671fSRichard Henderson     }
3760bab1671fSRichard Henderson 
3761bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
3762bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
3763bab1671fSRichard Henderson     tcg_debug_assert(ok);
3764bab1671fSRichard Henderson 
3765bab1671fSRichard Henderson  done:
3766bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
3767bab1671fSRichard Henderson         temp_dead(s, its);
3768bab1671fSRichard Henderson     }
3769bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
3770bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
3771bab1671fSRichard Henderson     }
3772bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
3773bab1671fSRichard Henderson         temp_dead(s, ots);
3774bab1671fSRichard Henderson     }
3775bab1671fSRichard Henderson }
3776bab1671fSRichard Henderson 
3777dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
3778c896fe29Sbellard {
3779dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3780dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
378182790a87SRichard Henderson     TCGRegSet i_allocated_regs;
378282790a87SRichard Henderson     TCGRegSet o_allocated_regs;
3783b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
3784b6638662SRichard Henderson     TCGReg reg;
3785c896fe29Sbellard     TCGArg arg;
3786c896fe29Sbellard     const TCGArgConstraint *arg_ct;
3787c896fe29Sbellard     TCGTemp *ts;
3788c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
3789c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
3790c896fe29Sbellard 
3791c896fe29Sbellard     nb_oargs = def->nb_oargs;
3792c896fe29Sbellard     nb_iargs = def->nb_iargs;
3793c896fe29Sbellard 
3794c896fe29Sbellard     /* copy constants */
3795c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
3796dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
3797c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
3798c896fe29Sbellard 
3799d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
3800d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
380182790a87SRichard Henderson 
3802c896fe29Sbellard     /* satisfy input constraints */
3803c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
3804d62816f2SRichard Henderson         TCGRegSet i_preferred_regs, o_preferred_regs;
3805d62816f2SRichard Henderson 
380666792f90SRichard Henderson         i = def->args_ct[nb_oargs + k].sort_index;
3807dd186292SRichard Henderson         arg = op->args[i];
3808c896fe29Sbellard         arg_ct = &def->args_ct[i];
380943439139SRichard Henderson         ts = arg_temp(arg);
381040ae5c62SRichard Henderson 
381140ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
381240ae5c62SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct)) {
3813c896fe29Sbellard             /* constant is OK for instruction */
3814c896fe29Sbellard             const_args[i] = 1;
3815c896fe29Sbellard             new_args[i] = ts->val;
3816d62816f2SRichard Henderson             continue;
3817c896fe29Sbellard         }
381840ae5c62SRichard Henderson 
3819d62816f2SRichard Henderson         i_preferred_regs = o_preferred_regs = 0;
3820bc2b17e6SRichard Henderson         if (arg_ct->ialias) {
3821d62816f2SRichard Henderson             o_preferred_regs = op->output_pref[arg_ct->alias_index];
3822ee17db83SRichard Henderson             if (ts->kind == TEMP_FIXED) {
38235ff9d6a4Sbellard                 /* if fixed register, we must allocate a new register
38245ff9d6a4Sbellard                    if the alias is not the same register */
3825d62816f2SRichard Henderson                 if (arg != op->args[arg_ct->alias_index]) {
38265ff9d6a4Sbellard                     goto allocate_in_reg;
3827d62816f2SRichard Henderson                 }
38285ff9d6a4Sbellard             } else {
3829c896fe29Sbellard                 /* if the input is aliased to an output and if it is
3830c896fe29Sbellard                    not dead after the instruction, we must allocate
3831c896fe29Sbellard                    a new register and move it */
3832866cb6cbSAurelien Jarno                 if (!IS_DEAD_ARG(i)) {
3833c896fe29Sbellard                     goto allocate_in_reg;
3834c896fe29Sbellard                 }
3835d62816f2SRichard Henderson 
38367e1df267SAurelien Jarno                 /* check if the current register has already been allocated
38377e1df267SAurelien Jarno                    for another input aliased to an output */
3838d62816f2SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG) {
38397e1df267SAurelien Jarno                     int k2, i2;
3840d62816f2SRichard Henderson                     reg = ts->reg;
38417e1df267SAurelien Jarno                     for (k2 = 0 ; k2 < k ; k2++) {
384266792f90SRichard Henderson                         i2 = def->args_ct[nb_oargs + k2].sort_index;
3843bc2b17e6SRichard Henderson                         if (def->args_ct[i2].ialias && reg == new_args[i2]) {
38447e1df267SAurelien Jarno                             goto allocate_in_reg;
38457e1df267SAurelien Jarno                         }
38467e1df267SAurelien Jarno                     }
38475ff9d6a4Sbellard                 }
3848d62816f2SRichard Henderson                 i_preferred_regs = o_preferred_regs;
3849866cb6cbSAurelien Jarno             }
3850d62816f2SRichard Henderson         }
3851d62816f2SRichard Henderson 
38529be0d080SRichard Henderson         temp_load(s, ts, arg_ct->regs, i_allocated_regs, i_preferred_regs);
3853c896fe29Sbellard         reg = ts->reg;
3854d62816f2SRichard Henderson 
38559be0d080SRichard Henderson         if (tcg_regset_test_reg(arg_ct->regs, reg)) {
3856c896fe29Sbellard             /* nothing to do : the constraint is satisfied */
3857c896fe29Sbellard         } else {
3858c896fe29Sbellard         allocate_in_reg:
3859c896fe29Sbellard             /* allocate a new register matching the constraint
3860c896fe29Sbellard                and move the temporary register into it */
3861d62816f2SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
3862d62816f2SRichard Henderson                       i_allocated_regs, 0);
38639be0d080SRichard Henderson             reg = tcg_reg_alloc(s, arg_ct->regs, i_allocated_regs,
3864d62816f2SRichard Henderson                                 o_preferred_regs, ts->indirect_base);
386578113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
3866240c08d0SRichard Henderson                 /*
3867240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
3868240c08d0SRichard Henderson                  * temp back to its slot and load from there.
3869240c08d0SRichard Henderson                  */
3870240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
3871240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
3872240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
387378113e83SRichard Henderson             }
3874c896fe29Sbellard         }
3875c896fe29Sbellard         new_args[i] = reg;
3876c896fe29Sbellard         const_args[i] = 0;
387782790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
3878c896fe29Sbellard     }
3879c896fe29Sbellard 
3880c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
3881866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
3882866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
388343439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
3884c896fe29Sbellard         }
3885c896fe29Sbellard     }
3886c896fe29Sbellard 
3887b4cb76e6SRichard Henderson     if (def->flags & TCG_OPF_COND_BRANCH) {
3888b4cb76e6SRichard Henderson         tcg_reg_alloc_cbranch(s, i_allocated_regs);
3889b4cb76e6SRichard Henderson     } else if (def->flags & TCG_OPF_BB_END) {
389082790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
3891a52ad07eSAurelien Jarno     } else {
3892c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
3893b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
3894c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
3895c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
389682790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
3897c896fe29Sbellard                 }
3898c896fe29Sbellard             }
38993d5c5f87SAurelien Jarno         }
39003d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
39013d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
39023d5c5f87SAurelien Jarno                an exception. */
390382790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
3904c896fe29Sbellard         }
3905c896fe29Sbellard 
3906c896fe29Sbellard         /* satisfy the output constraints */
3907c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
390866792f90SRichard Henderson             i = def->args_ct[k].sort_index;
3909dd186292SRichard Henderson             arg = op->args[i];
3910c896fe29Sbellard             arg_ct = &def->args_ct[i];
391143439139SRichard Henderson             ts = arg_temp(arg);
3912d63e3b6eSRichard Henderson 
3913d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
3914*e01fa97dSRichard Henderson             tcg_debug_assert(!temp_readonly(ts));
3915d63e3b6eSRichard Henderson 
3916bc2b17e6SRichard Henderson             if (arg_ct->oalias && !const_args[arg_ct->alias_index]) {
39175ff9d6a4Sbellard                 reg = new_args[arg_ct->alias_index];
3918bc2b17e6SRichard Henderson             } else if (arg_ct->newreg) {
39199be0d080SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->regs,
392082790a87SRichard Henderson                                     i_allocated_regs | o_allocated_regs,
392169e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
3922c896fe29Sbellard             } else {
39239be0d080SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->regs, o_allocated_regs,
392469e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
3925c896fe29Sbellard             }
392682790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
3927639368ddSAurelien Jarno             if (ts->val_type == TEMP_VAL_REG) {
3928f8b2f202SRichard Henderson                 s->reg_to_temp[ts->reg] = NULL;
3929639368ddSAurelien Jarno             }
3930c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
3931c896fe29Sbellard             ts->reg = reg;
3932d63e3b6eSRichard Henderson             /*
3933d63e3b6eSRichard Henderson              * Temp value is modified, so the value kept in memory is
3934d63e3b6eSRichard Henderson              * potentially not the same.
3935d63e3b6eSRichard Henderson              */
3936c896fe29Sbellard             ts->mem_coherent = 0;
3937f8b2f202SRichard Henderson             s->reg_to_temp[reg] = ts;
3938c896fe29Sbellard             new_args[i] = reg;
3939c896fe29Sbellard         }
3940e8996ee0Sbellard     }
3941c896fe29Sbellard 
3942c896fe29Sbellard     /* emit instruction */
3943d2fd745fSRichard Henderson     if (def->flags & TCG_OPF_VECTOR) {
3944d2fd745fSRichard Henderson         tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
3945d2fd745fSRichard Henderson                        new_args, const_args);
3946d2fd745fSRichard Henderson     } else {
3947dd186292SRichard Henderson         tcg_out_op(s, op->opc, new_args, const_args);
3948d2fd745fSRichard Henderson     }
3949c896fe29Sbellard 
3950c896fe29Sbellard     /* move the outputs in the correct register if needed */
3951c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
395243439139SRichard Henderson         ts = arg_temp(op->args[i]);
3953d63e3b6eSRichard Henderson 
3954d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
3955*e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
3956d63e3b6eSRichard Henderson 
3957ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
395898b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
395959d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
3960f8bf00f1SRichard Henderson             temp_dead(s, ts);
3961ec7a869dSAurelien Jarno         }
3962c896fe29Sbellard     }
3963c896fe29Sbellard }
3964c896fe29Sbellard 
3965b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP
3966b03cce8eSbellard #define STACK_DIR(x) (-(x))
3967b03cce8eSbellard #else
3968b03cce8eSbellard #define STACK_DIR(x) (x)
3969b03cce8eSbellard #endif
3970b03cce8eSbellard 
3971dd186292SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
3972c896fe29Sbellard {
3973cd9090aaSRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
3974cd9090aaSRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
3975dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3976b6638662SRichard Henderson     int flags, nb_regs, i;
3977b6638662SRichard Henderson     TCGReg reg;
3978cf066674SRichard Henderson     TCGArg arg;
3979c896fe29Sbellard     TCGTemp *ts;
3980d3452f1fSRichard Henderson     intptr_t stack_offset;
3981d3452f1fSRichard Henderson     size_t call_stack_size;
3982cf066674SRichard Henderson     tcg_insn_unit *func_addr;
3983cf066674SRichard Henderson     int allocate_args;
3984c896fe29Sbellard     TCGRegSet allocated_regs;
3985c896fe29Sbellard 
3986dd186292SRichard Henderson     func_addr = (tcg_insn_unit *)(intptr_t)op->args[nb_oargs + nb_iargs];
3987dd186292SRichard Henderson     flags = op->args[nb_oargs + nb_iargs + 1];
3988c896fe29Sbellard 
39896e17d0c5SStefan Weil     nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
3990c45cb8bbSRichard Henderson     if (nb_regs > nb_iargs) {
3991c45cb8bbSRichard Henderson         nb_regs = nb_iargs;
3992cf066674SRichard Henderson     }
3993c896fe29Sbellard 
3994c896fe29Sbellard     /* assign stack slots first */
3995c45cb8bbSRichard Henderson     call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long);
3996c896fe29Sbellard     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
3997c896fe29Sbellard         ~(TCG_TARGET_STACK_ALIGN - 1);
3998b03cce8eSbellard     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
3999b03cce8eSbellard     if (allocate_args) {
4000345649c0SBlue Swirl         /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
4001345649c0SBlue Swirl            preallocate call stack */
4002345649c0SBlue Swirl         tcg_abort();
4003b03cce8eSbellard     }
400439cf05d3Sbellard 
400539cf05d3Sbellard     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
4006c45cb8bbSRichard Henderson     for (i = nb_regs; i < nb_iargs; i++) {
4007dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
400839cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP
400939cf05d3Sbellard         stack_offset -= sizeof(tcg_target_long);
401039cf05d3Sbellard #endif
401139cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
401243439139SRichard Henderson             ts = arg_temp(arg);
401340ae5c62SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
4014b722452aSRichard Henderson                       s->reserved_regs, 0);
4015e4d5434cSblueswir1             tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
401639cf05d3Sbellard         }
401739cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP
401839cf05d3Sbellard         stack_offset += sizeof(tcg_target_long);
401939cf05d3Sbellard #endif
4020c896fe29Sbellard     }
4021c896fe29Sbellard 
4022c896fe29Sbellard     /* assign input registers */
4023d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
4024c896fe29Sbellard     for (i = 0; i < nb_regs; i++) {
4025dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
402639cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
402743439139SRichard Henderson             ts = arg_temp(arg);
4028c896fe29Sbellard             reg = tcg_target_call_iarg_regs[i];
402940ae5c62SRichard Henderson 
4030c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
4031c896fe29Sbellard                 if (ts->reg != reg) {
40324250da10SRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
403378113e83SRichard Henderson                     if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
4034240c08d0SRichard Henderson                         /*
4035240c08d0SRichard Henderson                          * Cross register class move not supported.  Sync the
4036240c08d0SRichard Henderson                          * temp back to its slot and load from there.
4037240c08d0SRichard Henderson                          */
4038240c08d0SRichard Henderson                         temp_sync(s, ts, allocated_regs, 0, 0);
4039240c08d0SRichard Henderson                         tcg_out_ld(s, ts->type, reg,
4040240c08d0SRichard Henderson                                    ts->mem_base->reg, ts->mem_offset);
404178113e83SRichard Henderson                     }
4042c896fe29Sbellard                 }
4043c896fe29Sbellard             } else {
4044ccb1bb66SRichard Henderson                 TCGRegSet arg_set = 0;
404540ae5c62SRichard Henderson 
40464250da10SRichard Henderson                 tcg_reg_free(s, reg, allocated_regs);
404740ae5c62SRichard Henderson                 tcg_regset_set_reg(arg_set, reg);
4048b722452aSRichard Henderson                 temp_load(s, ts, arg_set, allocated_regs, 0);
4049c896fe29Sbellard             }
405040ae5c62SRichard Henderson 
4051c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
4052c896fe29Sbellard         }
405339cf05d3Sbellard     }
4054c896fe29Sbellard 
4055c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
4056866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
4057866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
405843439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
4059c896fe29Sbellard         }
4060c896fe29Sbellard     }
4061c896fe29Sbellard 
4062c896fe29Sbellard     /* clobber call registers */
4063c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
4064c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
4065b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
4066c896fe29Sbellard         }
4067c896fe29Sbellard     }
4068c896fe29Sbellard 
406978505279SAurelien Jarno     /* Save globals if they might be written by the helper, sync them if
407078505279SAurelien Jarno        they might be read. */
407178505279SAurelien Jarno     if (flags & TCG_CALL_NO_READ_GLOBALS) {
407278505279SAurelien Jarno         /* Nothing to do */
407378505279SAurelien Jarno     } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) {
407478505279SAurelien Jarno         sync_globals(s, allocated_regs);
407578505279SAurelien Jarno     } else {
4076e8996ee0Sbellard         save_globals(s, allocated_regs);
4077b9c18f56Saurel32     }
4078c896fe29Sbellard 
4079cf066674SRichard Henderson     tcg_out_call(s, func_addr);
4080c896fe29Sbellard 
4081c896fe29Sbellard     /* assign output registers and emit moves if needed */
4082c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
4083dd186292SRichard Henderson         arg = op->args[i];
408443439139SRichard Henderson         ts = arg_temp(arg);
4085d63e3b6eSRichard Henderson 
4086d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
4087*e01fa97dSRichard Henderson         tcg_debug_assert(!temp_readonly(ts));
4088d63e3b6eSRichard Henderson 
4089c896fe29Sbellard         reg = tcg_target_call_oarg_regs[i];
4090eabb7b91SAurelien Jarno         tcg_debug_assert(s->reg_to_temp[reg] == NULL);
4091639368ddSAurelien Jarno         if (ts->val_type == TEMP_VAL_REG) {
4092f8b2f202SRichard Henderson             s->reg_to_temp[ts->reg] = NULL;
4093639368ddSAurelien Jarno         }
4094c896fe29Sbellard         ts->val_type = TEMP_VAL_REG;
4095c896fe29Sbellard         ts->reg = reg;
4096c896fe29Sbellard         ts->mem_coherent = 0;
4097f8b2f202SRichard Henderson         s->reg_to_temp[reg] = ts;
4098ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
409998b4e186SRichard Henderson             temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i));
410059d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
4101f8bf00f1SRichard Henderson             temp_dead(s, ts);
4102c896fe29Sbellard         }
4103c896fe29Sbellard     }
41048c11ad25SAurelien Jarno }
4105c896fe29Sbellard 
4106c896fe29Sbellard #ifdef CONFIG_PROFILER
4107c896fe29Sbellard 
4108c3fac113SEmilio G. Cota /* avoid copy/paste errors */
4109c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field)                       \
4110c3fac113SEmilio G. Cota     do {                                                \
4111d73415a3SStefan Hajnoczi         (to)->field += qatomic_read(&((from)->field));  \
4112c3fac113SEmilio G. Cota     } while (0)
4113c896fe29Sbellard 
4114c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field)                                       \
4115c3fac113SEmilio G. Cota     do {                                                                \
4116d73415a3SStefan Hajnoczi         typeof((from)->field) val__ = qatomic_read(&((from)->field));   \
4117c3fac113SEmilio G. Cota         if (val__ > (to)->field) {                                      \
4118c3fac113SEmilio G. Cota             (to)->field = val__;                                        \
4119c3fac113SEmilio G. Cota         }                                                               \
4120c3fac113SEmilio G. Cota     } while (0)
4121c3fac113SEmilio G. Cota 
4122c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */
4123c3fac113SEmilio G. Cota static inline
4124c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
4125c896fe29Sbellard {
4126d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
4127c3fac113SEmilio G. Cota     unsigned int i;
4128c3fac113SEmilio G. Cota 
41293468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4130d73415a3SStefan Hajnoczi         TCGContext *s = qatomic_read(&tcg_ctxs[i]);
41313468b59eSEmilio G. Cota         const TCGProfile *orig = &s->prof;
4132c3fac113SEmilio G. Cota 
4133c3fac113SEmilio G. Cota         if (counters) {
413472fd2efbSEmilio G. Cota             PROF_ADD(prof, orig, cpu_exec_time);
4135c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count1);
4136c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count);
4137c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, op_count);
4138c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, op_count_max);
4139c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, temp_count);
4140c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, temp_count_max);
4141c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, del_op_count);
4142c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_in_len);
4143c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_out_len);
4144c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, search_out_len);
4145c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, interm_time);
4146c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_time);
4147c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, la_time);
4148c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, opt_time);
4149c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_count);
4150c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_time);
4151c3fac113SEmilio G. Cota         }
4152c3fac113SEmilio G. Cota         if (table) {
4153c896fe29Sbellard             int i;
4154d70724ceSzhanghailiang 
415515fc7daaSRichard Henderson             for (i = 0; i < NB_OPS; i++) {
4156c3fac113SEmilio G. Cota                 PROF_ADD(prof, orig, table_op_count[i]);
4157c3fac113SEmilio G. Cota             }
4158c3fac113SEmilio G. Cota         }
4159c3fac113SEmilio G. Cota     }
4160c3fac113SEmilio G. Cota }
4161c3fac113SEmilio G. Cota 
4162c3fac113SEmilio G. Cota #undef PROF_ADD
4163c3fac113SEmilio G. Cota #undef PROF_MAX
4164c3fac113SEmilio G. Cota 
4165c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof)
4166c3fac113SEmilio G. Cota {
4167c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, true, false);
4168c3fac113SEmilio G. Cota }
4169c3fac113SEmilio G. Cota 
4170c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof)
4171c3fac113SEmilio G. Cota {
4172c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, false, true);
4173c3fac113SEmilio G. Cota }
4174c3fac113SEmilio G. Cota 
4175d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
4176c3fac113SEmilio G. Cota {
4177c3fac113SEmilio G. Cota     TCGProfile prof = {};
4178c3fac113SEmilio G. Cota     int i;
4179c3fac113SEmilio G. Cota 
4180c3fac113SEmilio G. Cota     tcg_profile_snapshot_table(&prof);
4181c3fac113SEmilio G. Cota     for (i = 0; i < NB_OPS; i++) {
4182d4c51a0aSMarkus Armbruster         qemu_printf("%s %" PRId64 "\n", tcg_op_defs[i].name,
4183c3fac113SEmilio G. Cota                     prof.table_op_count[i]);
4184c896fe29Sbellard     }
4185c896fe29Sbellard }
418672fd2efbSEmilio G. Cota 
418772fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
418872fd2efbSEmilio G. Cota {
4189d73415a3SStefan Hajnoczi     unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
419072fd2efbSEmilio G. Cota     unsigned int i;
419172fd2efbSEmilio G. Cota     int64_t ret = 0;
419272fd2efbSEmilio G. Cota 
419372fd2efbSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
4194d73415a3SStefan Hajnoczi         const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
419572fd2efbSEmilio G. Cota         const TCGProfile *prof = &s->prof;
419672fd2efbSEmilio G. Cota 
4197d73415a3SStefan Hajnoczi         ret += qatomic_read(&prof->cpu_exec_time);
419872fd2efbSEmilio G. Cota     }
419972fd2efbSEmilio G. Cota     return ret;
420072fd2efbSEmilio G. Cota }
4201246ae24dSMax Filippov #else
4202d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
4203246ae24dSMax Filippov {
4204d4c51a0aSMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4205246ae24dSMax Filippov }
420672fd2efbSEmilio G. Cota 
420772fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
420872fd2efbSEmilio G. Cota {
420972fd2efbSEmilio G. Cota     error_report("%s: TCG profiler not compiled", __func__);
421072fd2efbSEmilio G. Cota     exit(EXIT_FAILURE);
421172fd2efbSEmilio G. Cota }
4212c896fe29Sbellard #endif
4213c896fe29Sbellard 
4214c896fe29Sbellard 
42155bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
4216c896fe29Sbellard {
4217c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER
4218c3fac113SEmilio G. Cota     TCGProfile *prof = &s->prof;
4219c3fac113SEmilio G. Cota #endif
422015fa08f8SRichard Henderson     int i, num_insns;
422115fa08f8SRichard Henderson     TCGOp *op;
4222c896fe29Sbellard 
422304fe6400SRichard Henderson #ifdef CONFIG_PROFILER
422404fe6400SRichard Henderson     {
4225c1f543b7SEmilio G. Cota         int n = 0;
422604fe6400SRichard Henderson 
422715fa08f8SRichard Henderson         QTAILQ_FOREACH(op, &s->ops, link) {
422815fa08f8SRichard Henderson             n++;
422915fa08f8SRichard Henderson         }
4230d73415a3SStefan Hajnoczi         qatomic_set(&prof->op_count, prof->op_count + n);
4231c3fac113SEmilio G. Cota         if (n > prof->op_count_max) {
4232d73415a3SStefan Hajnoczi             qatomic_set(&prof->op_count_max, n);
423304fe6400SRichard Henderson         }
423404fe6400SRichard Henderson 
423504fe6400SRichard Henderson         n = s->nb_temps;
4236d73415a3SStefan Hajnoczi         qatomic_set(&prof->temp_count, prof->temp_count + n);
4237c3fac113SEmilio G. Cota         if (n > prof->temp_count_max) {
4238d73415a3SStefan Hajnoczi             qatomic_set(&prof->temp_count_max, n);
423904fe6400SRichard Henderson         }
424004fe6400SRichard Henderson     }
424104fe6400SRichard Henderson #endif
424204fe6400SRichard Henderson 
4243c896fe29Sbellard #ifdef DEBUG_DISAS
4244d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
4245d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
4246fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
424793fcfe39Saliguori         qemu_log("OP:\n");
42481894f69aSRichard Henderson         tcg_dump_ops(s, false);
424993fcfe39Saliguori         qemu_log("\n");
4250fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
4251c896fe29Sbellard     }
4252c896fe29Sbellard #endif
4253c896fe29Sbellard 
4254bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
4255bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
4256bef16ab4SRichard Henderson     {
4257bef16ab4SRichard Henderson         TCGLabel *l;
4258bef16ab4SRichard Henderson         bool error = false;
4259bef16ab4SRichard Henderson 
4260bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
4261bef16ab4SRichard Henderson             if (unlikely(!l->present) && l->refs) {
4262bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
4263bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
4264bef16ab4SRichard Henderson                 error = true;
4265bef16ab4SRichard Henderson             }
4266bef16ab4SRichard Henderson         }
4267bef16ab4SRichard Henderson         assert(!error);
4268bef16ab4SRichard Henderson     }
4269bef16ab4SRichard Henderson #endif
4270bef16ab4SRichard Henderson 
4271c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
4272d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
4273c5cc28ffSAurelien Jarno #endif
4274c5cc28ffSAurelien Jarno 
42758f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
4276c45cb8bbSRichard Henderson     tcg_optimize(s);
42778f2e8c07SKirill Batuzov #endif
42788f2e8c07SKirill Batuzov 
4279a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4280d73415a3SStefan Hajnoczi     qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
4281d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time - profile_getclock());
4282a23a9ec6Sbellard #endif
4283c5cc28ffSAurelien Jarno 
4284b4fc67c7SRichard Henderson     reachable_code_pass(s);
4285b83eabeaSRichard Henderson     liveness_pass_1(s);
42865a18407fSRichard Henderson 
42875a18407fSRichard Henderson     if (s->nb_indirects > 0) {
42885a18407fSRichard Henderson #ifdef DEBUG_DISAS
42895a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
42905a18407fSRichard Henderson                      && qemu_log_in_addr_range(tb->pc))) {
4291fc59d2d8SRobert Foley             FILE *logfile = qemu_log_lock();
42925a18407fSRichard Henderson             qemu_log("OP before indirect lowering:\n");
42931894f69aSRichard Henderson             tcg_dump_ops(s, false);
42945a18407fSRichard Henderson             qemu_log("\n");
4295fc59d2d8SRobert Foley             qemu_log_unlock(logfile);
42965a18407fSRichard Henderson         }
42975a18407fSRichard Henderson #endif
42985a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
4299b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
43005a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
4301b83eabeaSRichard Henderson             liveness_pass_1(s);
43025a18407fSRichard Henderson         }
43035a18407fSRichard Henderson     }
4304c5cc28ffSAurelien Jarno 
4305a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4306d73415a3SStefan Hajnoczi     qatomic_set(&prof->la_time, prof->la_time + profile_getclock());
4307a23a9ec6Sbellard #endif
4308c896fe29Sbellard 
4309c896fe29Sbellard #ifdef DEBUG_DISAS
4310d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
4311d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
4312fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
4313c5cc28ffSAurelien Jarno         qemu_log("OP after optimization and liveness analysis:\n");
43141894f69aSRichard Henderson         tcg_dump_ops(s, true);
431593fcfe39Saliguori         qemu_log("\n");
4316fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
4317c896fe29Sbellard     }
4318c896fe29Sbellard #endif
4319c896fe29Sbellard 
4320c896fe29Sbellard     tcg_reg_alloc_start(s);
4321c896fe29Sbellard 
4322db0c51a3SRichard Henderson     /*
4323db0c51a3SRichard Henderson      * Reset the buffer pointers when restarting after overflow.
4324db0c51a3SRichard Henderson      * TODO: Move this into translate-all.c with the rest of the
4325db0c51a3SRichard Henderson      * buffer management.  Having only this done here is confusing.
4326db0c51a3SRichard Henderson      */
4327db0c51a3SRichard Henderson     s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr);
4328db0c51a3SRichard Henderson     s->code_ptr = s->code_buf;
4329c896fe29Sbellard 
4330659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
43316001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
4332659ef5cbSRichard Henderson #endif
433357a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
433457a26946SRichard Henderson     s->pool_labels = NULL;
433557a26946SRichard Henderson #endif
43369ecefc84SRichard Henderson 
4337fca8a500SRichard Henderson     num_insns = -1;
433815fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
4339c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
4340b3db8758Sblueswir1 
4341c896fe29Sbellard #ifdef CONFIG_PROFILER
4342d73415a3SStefan Hajnoczi         qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
4343c896fe29Sbellard #endif
4344c45cb8bbSRichard Henderson 
4345c896fe29Sbellard         switch (opc) {
4346c896fe29Sbellard         case INDEX_op_mov_i32:
4347c896fe29Sbellard         case INDEX_op_mov_i64:
4348d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
4349dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
4350c896fe29Sbellard             break;
4351e8996ee0Sbellard         case INDEX_op_movi_i32:
4352e8996ee0Sbellard         case INDEX_op_movi_i64:
4353d2fd745fSRichard Henderson         case INDEX_op_dupi_vec:
4354dd186292SRichard Henderson             tcg_reg_alloc_movi(s, op);
4355e8996ee0Sbellard             break;
4356bab1671fSRichard Henderson         case INDEX_op_dup_vec:
4357bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
4358bab1671fSRichard Henderson             break;
4359765b842aSRichard Henderson         case INDEX_op_insn_start:
4360fca8a500SRichard Henderson             if (num_insns >= 0) {
43619f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
43629f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
43639f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
43649f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
4365fca8a500SRichard Henderson             }
4366fca8a500SRichard Henderson             num_insns++;
4367bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
4368bad729e2SRichard Henderson                 target_ulong a;
4369bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
4370efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
4371bad729e2SRichard Henderson #else
4372efee3746SRichard Henderson                 a = op->args[i];
4373bad729e2SRichard Henderson #endif
4374fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
4375bad729e2SRichard Henderson             }
4376c896fe29Sbellard             break;
43775ff9d6a4Sbellard         case INDEX_op_discard:
437843439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
43795ff9d6a4Sbellard             break;
4380c896fe29Sbellard         case INDEX_op_set_label:
4381e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
438292ab8e7dSRichard Henderson             tcg_out_label(s, arg_label(op->args[0]));
4383c896fe29Sbellard             break;
4384c896fe29Sbellard         case INDEX_op_call:
4385dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
4386c45cb8bbSRichard Henderson             break;
4387c896fe29Sbellard         default:
438825c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
4389be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
4390c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
4391c896fe29Sbellard                faster to have specialized register allocator functions for
4392c896fe29Sbellard                some common argument patterns */
4393dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
4394c896fe29Sbellard             break;
4395c896fe29Sbellard         }
43968d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
4397c896fe29Sbellard         check_regs(s);
4398c896fe29Sbellard #endif
4399b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
4400b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
4401b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
4402b125f9dcSRichard Henderson            generating code without having to check during generation.  */
4403644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
4404b125f9dcSRichard Henderson             return -1;
4405b125f9dcSRichard Henderson         }
44066e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
44076e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
44086e6c4efeSRichard Henderson             return -2;
44096e6c4efeSRichard Henderson         }
4410c896fe29Sbellard     }
4411fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
4412fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
4413c45cb8bbSRichard Henderson 
4414b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
4415659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
4416aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
4417aeee05f5SRichard Henderson     if (i < 0) {
4418aeee05f5SRichard Henderson         return i;
441923dceda6SRichard Henderson     }
4420659ef5cbSRichard Henderson #endif
442157a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
44221768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
44231768987bSRichard Henderson     if (i < 0) {
44241768987bSRichard Henderson         return i;
442557a26946SRichard Henderson     }
442657a26946SRichard Henderson #endif
44277ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
44287ecd02a0SRichard Henderson         return -2;
44297ecd02a0SRichard Henderson     }
4430c896fe29Sbellard 
4431df5d2b16SRichard Henderson #ifndef CONFIG_TCG_INTERPRETER
4432c896fe29Sbellard     /* flush instruction cache */
4433db0c51a3SRichard Henderson     flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
4434db0c51a3SRichard Henderson                         (uintptr_t)s->code_buf,
44351da8de39SRichard Henderson                         tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
4436df5d2b16SRichard Henderson #endif
44372aeabc08SStefan Weil 
44381813e175SRichard Henderson     return tcg_current_code_size(s);
4439c896fe29Sbellard }
4440c896fe29Sbellard 
4441a23a9ec6Sbellard #ifdef CONFIG_PROFILER
44423de2faa9SMarkus Armbruster void tcg_dump_info(void)
4443a23a9ec6Sbellard {
4444c3fac113SEmilio G. Cota     TCGProfile prof = {};
4445c3fac113SEmilio G. Cota     const TCGProfile *s;
4446c3fac113SEmilio G. Cota     int64_t tb_count;
4447c3fac113SEmilio G. Cota     int64_t tb_div_count;
4448c3fac113SEmilio G. Cota     int64_t tot;
4449c3fac113SEmilio G. Cota 
4450c3fac113SEmilio G. Cota     tcg_profile_snapshot_counters(&prof);
4451c3fac113SEmilio G. Cota     s = &prof;
4452c3fac113SEmilio G. Cota     tb_count = s->tb_count;
4453c3fac113SEmilio G. Cota     tb_div_count = tb_count ? tb_count : 1;
4454c3fac113SEmilio G. Cota     tot = s->interm_time + s->code_time;
4455a23a9ec6Sbellard 
44563de2faa9SMarkus Armbruster     qemu_printf("JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
4457a23a9ec6Sbellard                 tot, tot / 2.4e9);
44583de2faa9SMarkus Armbruster     qemu_printf("translated TBs      %" PRId64 " (aborted=%" PRId64
44593de2faa9SMarkus Armbruster                 " %0.1f%%)\n",
4460fca8a500SRichard Henderson                 tb_count, s->tb_count1 - tb_count,
4461fca8a500SRichard Henderson                 (double)(s->tb_count1 - s->tb_count)
4462fca8a500SRichard Henderson                 / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
44633de2faa9SMarkus Armbruster     qemu_printf("avg ops/TB          %0.1f max=%d\n",
4464fca8a500SRichard Henderson                 (double)s->op_count / tb_div_count, s->op_count_max);
44653de2faa9SMarkus Armbruster     qemu_printf("deleted ops/TB      %0.2f\n",
4466fca8a500SRichard Henderson                 (double)s->del_op_count / tb_div_count);
44673de2faa9SMarkus Armbruster     qemu_printf("avg temps/TB        %0.2f max=%d\n",
4468fca8a500SRichard Henderson                 (double)s->temp_count / tb_div_count, s->temp_count_max);
44693de2faa9SMarkus Armbruster     qemu_printf("avg host code/TB    %0.1f\n",
4470fca8a500SRichard Henderson                 (double)s->code_out_len / tb_div_count);
44713de2faa9SMarkus Armbruster     qemu_printf("avg search data/TB  %0.1f\n",
4472fca8a500SRichard Henderson                 (double)s->search_out_len / tb_div_count);
4473a23a9ec6Sbellard 
44743de2faa9SMarkus Armbruster     qemu_printf("cycles/op           %0.1f\n",
4475a23a9ec6Sbellard                 s->op_count ? (double)tot / s->op_count : 0);
44763de2faa9SMarkus Armbruster     qemu_printf("cycles/in byte      %0.1f\n",
4477a23a9ec6Sbellard                 s->code_in_len ? (double)tot / s->code_in_len : 0);
44783de2faa9SMarkus Armbruster     qemu_printf("cycles/out byte     %0.1f\n",
4479a23a9ec6Sbellard                 s->code_out_len ? (double)tot / s->code_out_len : 0);
44803de2faa9SMarkus Armbruster     qemu_printf("cycles/search byte     %0.1f\n",
4481fca8a500SRichard Henderson                 s->search_out_len ? (double)tot / s->search_out_len : 0);
4482fca8a500SRichard Henderson     if (tot == 0) {
4483a23a9ec6Sbellard         tot = 1;
4484fca8a500SRichard Henderson     }
44853de2faa9SMarkus Armbruster     qemu_printf("  gen_interm time   %0.1f%%\n",
4486a23a9ec6Sbellard                 (double)s->interm_time / tot * 100.0);
44873de2faa9SMarkus Armbruster     qemu_printf("  gen_code time     %0.1f%%\n",
4488a23a9ec6Sbellard                 (double)s->code_time / tot * 100.0);
44893de2faa9SMarkus Armbruster     qemu_printf("optim./code time    %0.1f%%\n",
4490c5cc28ffSAurelien Jarno                 (double)s->opt_time / (s->code_time ? s->code_time : 1)
4491c5cc28ffSAurelien Jarno                 * 100.0);
44923de2faa9SMarkus Armbruster     qemu_printf("liveness/code time  %0.1f%%\n",
4493a23a9ec6Sbellard                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
44943de2faa9SMarkus Armbruster     qemu_printf("cpu_restore count   %" PRId64 "\n",
4495a23a9ec6Sbellard                 s->restore_count);
44963de2faa9SMarkus Armbruster     qemu_printf("  avg cycles        %0.1f\n",
4497a23a9ec6Sbellard                 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
4498a23a9ec6Sbellard }
4499a23a9ec6Sbellard #else
45003de2faa9SMarkus Armbruster void tcg_dump_info(void)
4501a23a9ec6Sbellard {
45023de2faa9SMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4503a23a9ec6Sbellard }
4504a23a9ec6Sbellard #endif
4505813da627SRichard Henderson 
4506813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
45075872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
45085872bbf2SRichard Henderson 
45095872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
45105872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
45115872bbf2SRichard Henderson 
45125872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
45135872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
45145872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
45155872bbf2SRichard Henderson 
45165872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
45175872bbf2SRichard Henderson */
4518813da627SRichard Henderson 
4519813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
4520813da627SRichard Henderson typedef enum {
4521813da627SRichard Henderson     JIT_NOACTION = 0,
4522813da627SRichard Henderson     JIT_REGISTER_FN,
4523813da627SRichard Henderson     JIT_UNREGISTER_FN
4524813da627SRichard Henderson } jit_actions_t;
4525813da627SRichard Henderson 
4526813da627SRichard Henderson struct jit_code_entry {
4527813da627SRichard Henderson     struct jit_code_entry *next_entry;
4528813da627SRichard Henderson     struct jit_code_entry *prev_entry;
4529813da627SRichard Henderson     const void *symfile_addr;
4530813da627SRichard Henderson     uint64_t symfile_size;
4531813da627SRichard Henderson };
4532813da627SRichard Henderson 
4533813da627SRichard Henderson struct jit_descriptor {
4534813da627SRichard Henderson     uint32_t version;
4535813da627SRichard Henderson     uint32_t action_flag;
4536813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
4537813da627SRichard Henderson     struct jit_code_entry *first_entry;
4538813da627SRichard Henderson };
4539813da627SRichard Henderson 
4540813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
4541813da627SRichard Henderson void __jit_debug_register_code(void)
4542813da627SRichard Henderson {
4543813da627SRichard Henderson     asm("");
4544813da627SRichard Henderson }
4545813da627SRichard Henderson 
4546813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
4547813da627SRichard Henderson    the version before we can set it.  */
4548813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
4549813da627SRichard Henderson 
4550813da627SRichard Henderson /* End GDB interface.  */
4551813da627SRichard Henderson 
4552813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
4553813da627SRichard Henderson {
4554813da627SRichard Henderson     const char *p = strtab + 1;
4555813da627SRichard Henderson 
4556813da627SRichard Henderson     while (1) {
4557813da627SRichard Henderson         if (strcmp(p, str) == 0) {
4558813da627SRichard Henderson             return p - strtab;
4559813da627SRichard Henderson         }
4560813da627SRichard Henderson         p += strlen(p) + 1;
4561813da627SRichard Henderson     }
4562813da627SRichard Henderson }
4563813da627SRichard Henderson 
4564755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf_ptr, size_t buf_size,
45652c90784aSRichard Henderson                                  const void *debug_frame,
45662c90784aSRichard Henderson                                  size_t debug_frame_size)
4567813da627SRichard Henderson {
45685872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
45695872bbf2SRichard Henderson         uint32_t  len;
45705872bbf2SRichard Henderson         uint16_t  version;
45715872bbf2SRichard Henderson         uint32_t  abbrev;
45725872bbf2SRichard Henderson         uint8_t   ptr_size;
45735872bbf2SRichard Henderson         uint8_t   cu_die;
45745872bbf2SRichard Henderson         uint16_t  cu_lang;
45755872bbf2SRichard Henderson         uintptr_t cu_low_pc;
45765872bbf2SRichard Henderson         uintptr_t cu_high_pc;
45775872bbf2SRichard Henderson         uint8_t   fn_die;
45785872bbf2SRichard Henderson         char      fn_name[16];
45795872bbf2SRichard Henderson         uintptr_t fn_low_pc;
45805872bbf2SRichard Henderson         uintptr_t fn_high_pc;
45815872bbf2SRichard Henderson         uint8_t   cu_eoc;
45825872bbf2SRichard Henderson     };
4583813da627SRichard Henderson 
4584813da627SRichard Henderson     struct ElfImage {
4585813da627SRichard Henderson         ElfW(Ehdr) ehdr;
4586813da627SRichard Henderson         ElfW(Phdr) phdr;
45875872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
45885872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
45895872bbf2SRichard Henderson         struct DebugInfo di;
45905872bbf2SRichard Henderson         uint8_t    da[24];
45915872bbf2SRichard Henderson         char       str[80];
45925872bbf2SRichard Henderson     };
45935872bbf2SRichard Henderson 
45945872bbf2SRichard Henderson     struct ElfImage *img;
45955872bbf2SRichard Henderson 
45965872bbf2SRichard Henderson     static const struct ElfImage img_template = {
45975872bbf2SRichard Henderson         .ehdr = {
45985872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
45995872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
46005872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
46015872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
46025872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
46035872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
46045872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
46055872bbf2SRichard Henderson             .e_type = ET_EXEC,
46065872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
46075872bbf2SRichard Henderson             .e_version = EV_CURRENT,
46085872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
46095872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
46105872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
46115872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
46125872bbf2SRichard Henderson             .e_phnum = 1,
46135872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
46145872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
46155872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
4616abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
4617abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
4618abbb3eaeSRichard Henderson #endif
4619abbb3eaeSRichard Henderson #ifdef ELF_OSABI
4620abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
4621abbb3eaeSRichard Henderson #endif
46225872bbf2SRichard Henderson         },
46235872bbf2SRichard Henderson         .phdr = {
46245872bbf2SRichard Henderson             .p_type = PT_LOAD,
46255872bbf2SRichard Henderson             .p_flags = PF_X,
46265872bbf2SRichard Henderson         },
46275872bbf2SRichard Henderson         .shdr = {
46285872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
46295872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
46305872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
46315872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
46325872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
46335872bbf2SRichard Henderson             [1] = { /* .text */
46345872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
46355872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
46365872bbf2SRichard Henderson             },
46375872bbf2SRichard Henderson             [2] = { /* .debug_info */
46385872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
46395872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
46405872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
46415872bbf2SRichard Henderson             },
46425872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
46435872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
46445872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
46455872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
46465872bbf2SRichard Henderson             },
46475872bbf2SRichard Henderson             [4] = { /* .debug_frame */
46485872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
46495872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
46505872bbf2SRichard Henderson             },
46515872bbf2SRichard Henderson             [5] = { /* .symtab */
46525872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
46535872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
46545872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
46555872bbf2SRichard Henderson                 .sh_info = 1,
46565872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
46575872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
46585872bbf2SRichard Henderson             },
46595872bbf2SRichard Henderson             [6] = { /* .strtab */
46605872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
46615872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
46625872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
46635872bbf2SRichard Henderson             }
46645872bbf2SRichard Henderson         },
46655872bbf2SRichard Henderson         .sym = {
46665872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
46675872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
46685872bbf2SRichard Henderson                 .st_shndx = 1,
46695872bbf2SRichard Henderson             }
46705872bbf2SRichard Henderson         },
46715872bbf2SRichard Henderson         .di = {
46725872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
46735872bbf2SRichard Henderson             .version = 2,
46745872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
46755872bbf2SRichard Henderson             .cu_die = 1,
46765872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
46775872bbf2SRichard Henderson             .fn_die = 2,
46785872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
46795872bbf2SRichard Henderson         },
46805872bbf2SRichard Henderson         .da = {
46815872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
46825872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
46835872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
46845872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
46855872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
46865872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
46875872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
46885872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
46895872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
46905872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
46915872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
46925872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
46935872bbf2SRichard Henderson             0           /* no more abbrev */
46945872bbf2SRichard Henderson         },
46955872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
46965872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
4697813da627SRichard Henderson     };
4698813da627SRichard Henderson 
4699813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
4700813da627SRichard Henderson     static struct jit_code_entry one_entry;
4701813da627SRichard Henderson 
47025872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
4703813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
47042c90784aSRichard Henderson     DebugFrameHeader *dfh;
4705813da627SRichard Henderson 
47065872bbf2SRichard Henderson     img = g_malloc(img_size);
47075872bbf2SRichard Henderson     *img = img_template;
4708813da627SRichard Henderson 
47095872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
47105872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
47115872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
4712813da627SRichard Henderson 
47135872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
47145872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
47155872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
4716813da627SRichard Henderson 
47175872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
47185872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
47195872bbf2SRichard Henderson 
47205872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
47215872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
47225872bbf2SRichard Henderson 
47235872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
47245872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
47255872bbf2SRichard Henderson 
47265872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
47275872bbf2SRichard Henderson     img->sym[1].st_value = buf;
47285872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
47295872bbf2SRichard Henderson 
47305872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
473145aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
47325872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
473345aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
4734813da627SRichard Henderson 
47352c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
47362c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
47372c90784aSRichard Henderson     dfh->fde.func_start = buf;
47382c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
47392c90784aSRichard Henderson 
4740813da627SRichard Henderson #ifdef DEBUG_JIT
4741813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
4742813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
4743813da627SRichard Henderson     {
4744813da627SRichard Henderson         FILE *f = fopen("/tmp/qemu.jit", "w+b");
4745813da627SRichard Henderson         if (f) {
47465872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
4747813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
4748813da627SRichard Henderson             }
4749813da627SRichard Henderson             fclose(f);
4750813da627SRichard Henderson         }
4751813da627SRichard Henderson     }
4752813da627SRichard Henderson #endif
4753813da627SRichard Henderson 
4754813da627SRichard Henderson     one_entry.symfile_addr = img;
4755813da627SRichard Henderson     one_entry.symfile_size = img_size;
4756813da627SRichard Henderson 
4757813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
4758813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
4759813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
4760813da627SRichard Henderson     __jit_debug_register_code();
4761813da627SRichard Henderson }
4762813da627SRichard Henderson #else
47635872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
47645872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
4765813da627SRichard Henderson 
4766755bf9e5SRichard Henderson static void tcg_register_jit_int(const void *buf, size_t size,
47672c90784aSRichard Henderson                                  const void *debug_frame,
47682c90784aSRichard Henderson                                  size_t debug_frame_size)
4769813da627SRichard Henderson {
4770813da627SRichard Henderson }
4771813da627SRichard Henderson 
4772755bf9e5SRichard Henderson void tcg_register_jit(const void *buf, size_t buf_size)
4773813da627SRichard Henderson {
4774813da627SRichard Henderson }
4775813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
4776db432672SRichard Henderson 
4777db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
4778db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
4779db432672SRichard Henderson {
4780db432672SRichard Henderson     g_assert_not_reached();
4781db432672SRichard Henderson }
4782db432672SRichard Henderson #endif
4783