xref: /openbmc/qemu/tcg/tcg.c (revision 38b47b19)
1c896fe29Sbellard /*
2c896fe29Sbellard  * Tiny Code Generator for QEMU
3c896fe29Sbellard  *
4c896fe29Sbellard  * Copyright (c) 2008 Fabrice Bellard
5c896fe29Sbellard  *
6c896fe29Sbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
7c896fe29Sbellard  * of this software and associated documentation files (the "Software"), to deal
8c896fe29Sbellard  * in the Software without restriction, including without limitation the rights
9c896fe29Sbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10c896fe29Sbellard  * copies of the Software, and to permit persons to whom the Software is
11c896fe29Sbellard  * furnished to do so, subject to the following conditions:
12c896fe29Sbellard  *
13c896fe29Sbellard  * The above copyright notice and this permission notice shall be included in
14c896fe29Sbellard  * all copies or substantial portions of the Software.
15c896fe29Sbellard  *
16c896fe29Sbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17c896fe29Sbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18c896fe29Sbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19c896fe29Sbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20c896fe29Sbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21c896fe29Sbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22c896fe29Sbellard  * THE SOFTWARE.
23c896fe29Sbellard  */
24c896fe29Sbellard 
25c896fe29Sbellard /* define it to use liveness analysis (better code) */
268f2e8c07SKirill Batuzov #define USE_TCG_OPTIMIZATIONS
27c896fe29Sbellard 
28757e725bSPeter Maydell #include "qemu/osdep.h"
29cca82982Saurel32 
30813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB.  */
31813da627SRichard Henderson #undef DEBUG_JIT
32813da627SRichard Henderson 
3372fd2efbSEmilio G. Cota #include "qemu/error-report.h"
34f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
351de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
36d4c51a0aSMarkus Armbruster #include "qemu/qemu-print.h"
371de7afc9SPaolo Bonzini #include "qemu/timer.h"
38c896fe29Sbellard 
39c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU
40c896fe29Sbellard    CPU definitions. Currently they are used for qemu_ld/st
41c896fe29Sbellard    instructions */
42c896fe29Sbellard #define NO_CPU_IO_DEFS
43c896fe29Sbellard #include "cpu.h"
44c896fe29Sbellard 
4563c91552SPaolo Bonzini #include "exec/exec-all.h"
4663c91552SPaolo Bonzini 
475cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY)
485cc8767dSLike Xu #include "hw/boards.h"
495cc8767dSLike Xu #endif
505cc8767dSLike Xu 
51c896fe29Sbellard #include "tcg-op.h"
52813da627SRichard Henderson 
53edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX
54813da627SRichard Henderson # define ELF_CLASS  ELFCLASS32
55edee2579SRichard Henderson #else
56edee2579SRichard Henderson # define ELF_CLASS  ELFCLASS64
57813da627SRichard Henderson #endif
58813da627SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
59813da627SRichard Henderson # define ELF_DATA   ELFDATA2MSB
60813da627SRichard Henderson #else
61813da627SRichard Henderson # define ELF_DATA   ELFDATA2LSB
62813da627SRichard Henderson #endif
63813da627SRichard Henderson 
64c896fe29Sbellard #include "elf.h"
65508127e2SPaolo Bonzini #include "exec/log.h"
663468b59eSEmilio G. Cota #include "sysemu/sysemu.h"
67c896fe29Sbellard 
68ce151109SPeter Maydell /* Forward declarations for functions declared in tcg-target.inc.c and
69ce151109SPeter Maydell    used here. */
70e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s);
71f69d277eSRichard Henderson static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode);
72e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
736ac17786SRichard Henderson static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
742ba7fae2SRichard Henderson                         intptr_t value, intptr_t addend);
75c896fe29Sbellard 
76497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts.  */
77497a22ebSRichard Henderson typedef struct {
78497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
79497a22ebSRichard Henderson     uint32_t id;
80497a22ebSRichard Henderson     uint8_t version;
81497a22ebSRichard Henderson     char augmentation[1];
82497a22ebSRichard Henderson     uint8_t code_align;
83497a22ebSRichard Henderson     uint8_t data_align;
84497a22ebSRichard Henderson     uint8_t return_column;
85497a22ebSRichard Henderson } DebugFrameCIE;
86497a22ebSRichard Henderson 
87497a22ebSRichard Henderson typedef struct QEMU_PACKED {
88497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
89497a22ebSRichard Henderson     uint32_t cie_offset;
90edee2579SRichard Henderson     uintptr_t func_start;
91edee2579SRichard Henderson     uintptr_t func_len;
92497a22ebSRichard Henderson } DebugFrameFDEHeader;
93497a22ebSRichard Henderson 
942c90784aSRichard Henderson typedef struct QEMU_PACKED {
952c90784aSRichard Henderson     DebugFrameCIE cie;
962c90784aSRichard Henderson     DebugFrameFDEHeader fde;
972c90784aSRichard Henderson } DebugFrameHeader;
982c90784aSRichard Henderson 
99813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size,
1002c90784aSRichard Henderson                                  const void *debug_frame,
1012c90784aSRichard Henderson                                  size_t debug_frame_size)
102813da627SRichard Henderson     __attribute__((unused));
103813da627SRichard Henderson 
104ce151109SPeter Maydell /* Forward declarations for functions declared and used in tcg-target.inc.c. */
105069ea736SRichard Henderson static const char *target_parse_constraint(TCGArgConstraint *ct,
106069ea736SRichard Henderson                                            const char *ct_str, TCGType type);
1072a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
108a05b5b9bSRichard Henderson                        intptr_t arg2);
10978113e83SRichard Henderson static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
110c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1112a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
112c0ad3001SStefan Weil static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
113c0ad3001SStefan Weil                        const int *const_args);
114d2fd745fSRichard Henderson #if TCG_TARGET_MAYBE_vec
115e7632cfaSRichard Henderson static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
116e7632cfaSRichard Henderson                             TCGReg dst, TCGReg src);
117d6ecb4a9SRichard Henderson static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
118d6ecb4a9SRichard Henderson                              TCGReg dst, TCGReg base, intptr_t offset);
119e7632cfaSRichard Henderson static void tcg_out_dupi_vec(TCGContext *s, TCGType type,
120e7632cfaSRichard Henderson                              TCGReg dst, tcg_target_long arg);
121d2fd745fSRichard Henderson static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl,
122d2fd745fSRichard Henderson                            unsigned vece, const TCGArg *args,
123d2fd745fSRichard Henderson                            const int *const_args);
124d2fd745fSRichard Henderson #else
125e7632cfaSRichard Henderson static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
126e7632cfaSRichard Henderson                                    TCGReg dst, TCGReg src)
127e7632cfaSRichard Henderson {
128e7632cfaSRichard Henderson     g_assert_not_reached();
129e7632cfaSRichard Henderson }
130d6ecb4a9SRichard Henderson static inline bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
131d6ecb4a9SRichard Henderson                                     TCGReg dst, TCGReg base, intptr_t offset)
132d6ecb4a9SRichard Henderson {
133d6ecb4a9SRichard Henderson     g_assert_not_reached();
134d6ecb4a9SRichard Henderson }
135e7632cfaSRichard Henderson static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type,
136e7632cfaSRichard Henderson                                     TCGReg dst, tcg_target_long arg)
137e7632cfaSRichard Henderson {
138e7632cfaSRichard Henderson     g_assert_not_reached();
139e7632cfaSRichard Henderson }
140d2fd745fSRichard Henderson static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl,
141d2fd745fSRichard Henderson                                   unsigned vece, const TCGArg *args,
142d2fd745fSRichard Henderson                                   const int *const_args)
143d2fd745fSRichard Henderson {
144d2fd745fSRichard Henderson     g_assert_not_reached();
145d2fd745fSRichard Henderson }
146d2fd745fSRichard Henderson #endif
1472a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
148a05b5b9bSRichard Henderson                        intptr_t arg2);
14959d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
15059d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
151cf066674SRichard Henderson static void tcg_out_call(TCGContext *s, tcg_insn_unit *target);
152f6c6afc1SRichard Henderson static int tcg_target_const_match(tcg_target_long val, TCGType type,
153c0ad3001SStefan Weil                                   const TCGArgConstraint *arg_ct);
154659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
155aeee05f5SRichard Henderson static int tcg_out_ldst_finalize(TCGContext *s);
156659ef5cbSRichard Henderson #endif
157c896fe29Sbellard 
158a505785cSEmilio G. Cota #define TCG_HIGHWATER 1024
159a505785cSEmilio G. Cota 
160df2cce29SEmilio G. Cota static TCGContext **tcg_ctxs;
161df2cce29SEmilio G. Cota static unsigned int n_tcg_ctxs;
1621c2adb95SRichard Henderson TCGv_env cpu_env = 0;
163df2cce29SEmilio G. Cota 
164be2cdc5eSEmilio G. Cota struct tcg_region_tree {
165be2cdc5eSEmilio G. Cota     QemuMutex lock;
166be2cdc5eSEmilio G. Cota     GTree *tree;
167be2cdc5eSEmilio G. Cota     /* padding to avoid false sharing is computed at run-time */
168be2cdc5eSEmilio G. Cota };
169be2cdc5eSEmilio G. Cota 
170e8feb96fSEmilio G. Cota /*
171e8feb96fSEmilio G. Cota  * We divide code_gen_buffer into equally-sized "regions" that TCG threads
172e8feb96fSEmilio G. Cota  * dynamically allocate from as demand dictates. Given appropriate region
173e8feb96fSEmilio G. Cota  * sizing, this minimizes flushes even when some TCG threads generate a lot
174e8feb96fSEmilio G. Cota  * more code than others.
175e8feb96fSEmilio G. Cota  */
176e8feb96fSEmilio G. Cota struct tcg_region_state {
177e8feb96fSEmilio G. Cota     QemuMutex lock;
178e8feb96fSEmilio G. Cota 
179e8feb96fSEmilio G. Cota     /* fields set at init time */
180e8feb96fSEmilio G. Cota     void *start;
181e8feb96fSEmilio G. Cota     void *start_aligned;
182e8feb96fSEmilio G. Cota     void *end;
183e8feb96fSEmilio G. Cota     size_t n;
184e8feb96fSEmilio G. Cota     size_t size; /* size of one region */
185e8feb96fSEmilio G. Cota     size_t stride; /* .size + guard size */
186e8feb96fSEmilio G. Cota 
187e8feb96fSEmilio G. Cota     /* fields protected by the lock */
188e8feb96fSEmilio G. Cota     size_t current; /* current region index */
189e8feb96fSEmilio G. Cota     size_t agg_size_full; /* aggregate size of full regions */
190e8feb96fSEmilio G. Cota };
191e8feb96fSEmilio G. Cota 
192e8feb96fSEmilio G. Cota static struct tcg_region_state region;
193be2cdc5eSEmilio G. Cota /*
194be2cdc5eSEmilio G. Cota  * This is an array of struct tcg_region_tree's, with padding.
195be2cdc5eSEmilio G. Cota  * We use void * to simplify the computation of region_trees[i]; each
196be2cdc5eSEmilio G. Cota  * struct is found every tree_size bytes.
197be2cdc5eSEmilio G. Cota  */
198be2cdc5eSEmilio G. Cota static void *region_trees;
199be2cdc5eSEmilio G. Cota static size_t tree_size;
200d2fd745fSRichard Henderson static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
201b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
202c896fe29Sbellard 
2031813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
2044196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
205c896fe29Sbellard {
206c896fe29Sbellard     *s->code_ptr++ = v;
207c896fe29Sbellard }
208c896fe29Sbellard 
2094196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
2104196dca6SPeter Maydell                                                       uint8_t v)
2115c53bb81SPeter Maydell {
2121813e175SRichard Henderson     *p = v;
2135c53bb81SPeter Maydell }
2141813e175SRichard Henderson #endif
2155c53bb81SPeter Maydell 
2161813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
2174196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
218c896fe29Sbellard {
2191813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2201813e175SRichard Henderson         *s->code_ptr++ = v;
2211813e175SRichard Henderson     } else {
2221813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2234387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2241813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
2251813e175SRichard Henderson     }
226c896fe29Sbellard }
227c896fe29Sbellard 
2284196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
2294196dca6SPeter Maydell                                                        uint16_t v)
2305c53bb81SPeter Maydell {
2311813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
2321813e175SRichard Henderson         *p = v;
2331813e175SRichard Henderson     } else {
2345c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2355c53bb81SPeter Maydell     }
2361813e175SRichard Henderson }
2371813e175SRichard Henderson #endif
2385c53bb81SPeter Maydell 
2391813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
2404196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
241c896fe29Sbellard {
2421813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2431813e175SRichard Henderson         *s->code_ptr++ = v;
2441813e175SRichard Henderson     } else {
2451813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2464387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2471813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
2481813e175SRichard Henderson     }
249c896fe29Sbellard }
250c896fe29Sbellard 
2514196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
2524196dca6SPeter Maydell                                                        uint32_t v)
2535c53bb81SPeter Maydell {
2541813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
2551813e175SRichard Henderson         *p = v;
2561813e175SRichard Henderson     } else {
2575c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2585c53bb81SPeter Maydell     }
2591813e175SRichard Henderson }
2601813e175SRichard Henderson #endif
2615c53bb81SPeter Maydell 
2621813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
2634196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
264ac26eb69SRichard Henderson {
2651813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2661813e175SRichard Henderson         *s->code_ptr++ = v;
2671813e175SRichard Henderson     } else {
2681813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
2694387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
2701813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
2711813e175SRichard Henderson     }
272ac26eb69SRichard Henderson }
273ac26eb69SRichard Henderson 
2744196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
2754196dca6SPeter Maydell                                                        uint64_t v)
2765c53bb81SPeter Maydell {
2771813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
2781813e175SRichard Henderson         *p = v;
2791813e175SRichard Henderson     } else {
2805c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2815c53bb81SPeter Maydell     }
2821813e175SRichard Henderson }
2831813e175SRichard Henderson #endif
2845c53bb81SPeter Maydell 
285c896fe29Sbellard /* label relocation processing */
286c896fe29Sbellard 
2871813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
288bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
289c896fe29Sbellard {
2907ecd02a0SRichard Henderson     TCGRelocation *r = tcg_malloc(sizeof(TCGRelocation));
291c896fe29Sbellard 
292c896fe29Sbellard     r->type = type;
293c896fe29Sbellard     r->ptr = code_ptr;
294c896fe29Sbellard     r->addend = addend;
2957ecd02a0SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
296c896fe29Sbellard }
297c896fe29Sbellard 
298bec16311SRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr)
299c896fe29Sbellard {
300eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
301c896fe29Sbellard     l->has_value = 1;
3021813e175SRichard Henderson     l->u.value_ptr = ptr;
303c896fe29Sbellard }
304c896fe29Sbellard 
30542a268c2SRichard Henderson TCGLabel *gen_new_label(void)
306c896fe29Sbellard {
307b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
30851e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
309c896fe29Sbellard 
3107ecd02a0SRichard Henderson     memset(l, 0, sizeof(TCGLabel));
3117ecd02a0SRichard Henderson     l->id = s->nb_labels++;
3127ecd02a0SRichard Henderson     QSIMPLEQ_INIT(&l->relocs);
3137ecd02a0SRichard Henderson 
314bef16ab4SRichard Henderson     QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
31542a268c2SRichard Henderson 
31642a268c2SRichard Henderson     return l;
317c896fe29Sbellard }
318c896fe29Sbellard 
3197ecd02a0SRichard Henderson static bool tcg_resolve_relocs(TCGContext *s)
3207ecd02a0SRichard Henderson {
3217ecd02a0SRichard Henderson     TCGLabel *l;
3227ecd02a0SRichard Henderson 
3237ecd02a0SRichard Henderson     QSIMPLEQ_FOREACH(l, &s->labels, next) {
3247ecd02a0SRichard Henderson         TCGRelocation *r;
3257ecd02a0SRichard Henderson         uintptr_t value = l->u.value;
3267ecd02a0SRichard Henderson 
3277ecd02a0SRichard Henderson         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
3287ecd02a0SRichard Henderson             if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
3297ecd02a0SRichard Henderson                 return false;
3307ecd02a0SRichard Henderson             }
3317ecd02a0SRichard Henderson         }
3327ecd02a0SRichard Henderson     }
3337ecd02a0SRichard Henderson     return true;
3347ecd02a0SRichard Henderson }
3357ecd02a0SRichard Henderson 
3369f754620SRichard Henderson static void set_jmp_reset_offset(TCGContext *s, int which)
3379f754620SRichard Henderson {
3389f754620SRichard Henderson     size_t off = tcg_current_code_size(s);
3399f754620SRichard Henderson     s->tb_jmp_reset_offset[which] = off;
3409f754620SRichard Henderson     /* Make sure that we didn't overflow the stored offset.  */
3419f754620SRichard Henderson     assert(s->tb_jmp_reset_offset[which] == off);
3429f754620SRichard Henderson }
3439f754620SRichard Henderson 
344ce151109SPeter Maydell #include "tcg-target.inc.c"
345c896fe29Sbellard 
346be2cdc5eSEmilio G. Cota /* compare a pointer @ptr and a tb_tc @s */
347be2cdc5eSEmilio G. Cota static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s)
348be2cdc5eSEmilio G. Cota {
349be2cdc5eSEmilio G. Cota     if (ptr >= s->ptr + s->size) {
350be2cdc5eSEmilio G. Cota         return 1;
351be2cdc5eSEmilio G. Cota     } else if (ptr < s->ptr) {
352be2cdc5eSEmilio G. Cota         return -1;
353be2cdc5eSEmilio G. Cota     }
354be2cdc5eSEmilio G. Cota     return 0;
355be2cdc5eSEmilio G. Cota }
356be2cdc5eSEmilio G. Cota 
357be2cdc5eSEmilio G. Cota static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp)
358be2cdc5eSEmilio G. Cota {
359be2cdc5eSEmilio G. Cota     const struct tb_tc *a = ap;
360be2cdc5eSEmilio G. Cota     const struct tb_tc *b = bp;
361be2cdc5eSEmilio G. Cota 
362be2cdc5eSEmilio G. Cota     /*
363be2cdc5eSEmilio G. Cota      * When both sizes are set, we know this isn't a lookup.
364be2cdc5eSEmilio G. Cota      * This is the most likely case: every TB must be inserted; lookups
365be2cdc5eSEmilio G. Cota      * are a lot less frequent.
366be2cdc5eSEmilio G. Cota      */
367be2cdc5eSEmilio G. Cota     if (likely(a->size && b->size)) {
368be2cdc5eSEmilio G. Cota         if (a->ptr > b->ptr) {
369be2cdc5eSEmilio G. Cota             return 1;
370be2cdc5eSEmilio G. Cota         } else if (a->ptr < b->ptr) {
371be2cdc5eSEmilio G. Cota             return -1;
372be2cdc5eSEmilio G. Cota         }
373be2cdc5eSEmilio G. Cota         /* a->ptr == b->ptr should happen only on deletions */
374be2cdc5eSEmilio G. Cota         g_assert(a->size == b->size);
375be2cdc5eSEmilio G. Cota         return 0;
376be2cdc5eSEmilio G. Cota     }
377be2cdc5eSEmilio G. Cota     /*
378be2cdc5eSEmilio G. Cota      * All lookups have either .size field set to 0.
379be2cdc5eSEmilio G. Cota      * From the glib sources we see that @ap is always the lookup key. However
380be2cdc5eSEmilio G. Cota      * the docs provide no guarantee, so we just mark this case as likely.
381be2cdc5eSEmilio G. Cota      */
382be2cdc5eSEmilio G. Cota     if (likely(a->size == 0)) {
383be2cdc5eSEmilio G. Cota         return ptr_cmp_tb_tc(a->ptr, b);
384be2cdc5eSEmilio G. Cota     }
385be2cdc5eSEmilio G. Cota     return ptr_cmp_tb_tc(b->ptr, a);
386be2cdc5eSEmilio G. Cota }
387be2cdc5eSEmilio G. Cota 
388be2cdc5eSEmilio G. Cota static void tcg_region_trees_init(void)
389be2cdc5eSEmilio G. Cota {
390be2cdc5eSEmilio G. Cota     size_t i;
391be2cdc5eSEmilio G. Cota 
392be2cdc5eSEmilio G. Cota     tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize);
393be2cdc5eSEmilio G. Cota     region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size);
394be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
395be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
396be2cdc5eSEmilio G. Cota 
397be2cdc5eSEmilio G. Cota         qemu_mutex_init(&rt->lock);
398be2cdc5eSEmilio G. Cota         rt->tree = g_tree_new(tb_tc_cmp);
399be2cdc5eSEmilio G. Cota     }
400be2cdc5eSEmilio G. Cota }
401be2cdc5eSEmilio G. Cota 
402be2cdc5eSEmilio G. Cota static struct tcg_region_tree *tc_ptr_to_region_tree(void *p)
403be2cdc5eSEmilio G. Cota {
404be2cdc5eSEmilio G. Cota     size_t region_idx;
405be2cdc5eSEmilio G. Cota 
406be2cdc5eSEmilio G. Cota     if (p < region.start_aligned) {
407be2cdc5eSEmilio G. Cota         region_idx = 0;
408be2cdc5eSEmilio G. Cota     } else {
409be2cdc5eSEmilio G. Cota         ptrdiff_t offset = p - region.start_aligned;
410be2cdc5eSEmilio G. Cota 
411be2cdc5eSEmilio G. Cota         if (offset > region.stride * (region.n - 1)) {
412be2cdc5eSEmilio G. Cota             region_idx = region.n - 1;
413be2cdc5eSEmilio G. Cota         } else {
414be2cdc5eSEmilio G. Cota             region_idx = offset / region.stride;
415be2cdc5eSEmilio G. Cota         }
416be2cdc5eSEmilio G. Cota     }
417be2cdc5eSEmilio G. Cota     return region_trees + region_idx * tree_size;
418be2cdc5eSEmilio G. Cota }
419be2cdc5eSEmilio G. Cota 
420be2cdc5eSEmilio G. Cota void tcg_tb_insert(TranslationBlock *tb)
421be2cdc5eSEmilio G. Cota {
422be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
423be2cdc5eSEmilio G. Cota 
424be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
425be2cdc5eSEmilio G. Cota     g_tree_insert(rt->tree, &tb->tc, tb);
426be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
427be2cdc5eSEmilio G. Cota }
428be2cdc5eSEmilio G. Cota 
429be2cdc5eSEmilio G. Cota void tcg_tb_remove(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_remove(rt->tree, &tb->tc);
435be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
436be2cdc5eSEmilio G. Cota }
437be2cdc5eSEmilio G. Cota 
438be2cdc5eSEmilio G. Cota /*
439be2cdc5eSEmilio G. Cota  * Find the TB 'tb' such that
440be2cdc5eSEmilio G. Cota  * tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size
441be2cdc5eSEmilio G. Cota  * Return NULL if not found.
442be2cdc5eSEmilio G. Cota  */
443be2cdc5eSEmilio G. Cota TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr)
444be2cdc5eSEmilio G. Cota {
445be2cdc5eSEmilio G. Cota     struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr);
446be2cdc5eSEmilio G. Cota     TranslationBlock *tb;
447be2cdc5eSEmilio G. Cota     struct tb_tc s = { .ptr = (void *)tc_ptr };
448be2cdc5eSEmilio G. Cota 
449be2cdc5eSEmilio G. Cota     qemu_mutex_lock(&rt->lock);
450be2cdc5eSEmilio G. Cota     tb = g_tree_lookup(rt->tree, &s);
451be2cdc5eSEmilio G. Cota     qemu_mutex_unlock(&rt->lock);
452be2cdc5eSEmilio G. Cota     return tb;
453be2cdc5eSEmilio G. Cota }
454be2cdc5eSEmilio G. Cota 
455be2cdc5eSEmilio G. Cota static void tcg_region_tree_lock_all(void)
456be2cdc5eSEmilio G. Cota {
457be2cdc5eSEmilio G. Cota     size_t i;
458be2cdc5eSEmilio G. Cota 
459be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
460be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
461be2cdc5eSEmilio G. Cota 
462be2cdc5eSEmilio G. Cota         qemu_mutex_lock(&rt->lock);
463be2cdc5eSEmilio G. Cota     }
464be2cdc5eSEmilio G. Cota }
465be2cdc5eSEmilio G. Cota 
466be2cdc5eSEmilio G. Cota static void tcg_region_tree_unlock_all(void)
467be2cdc5eSEmilio G. Cota {
468be2cdc5eSEmilio G. Cota     size_t i;
469be2cdc5eSEmilio G. Cota 
470be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
471be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
472be2cdc5eSEmilio G. Cota 
473be2cdc5eSEmilio G. Cota         qemu_mutex_unlock(&rt->lock);
474be2cdc5eSEmilio G. Cota     }
475be2cdc5eSEmilio G. Cota }
476be2cdc5eSEmilio G. Cota 
477be2cdc5eSEmilio G. Cota void tcg_tb_foreach(GTraverseFunc func, gpointer user_data)
478be2cdc5eSEmilio G. Cota {
479be2cdc5eSEmilio G. Cota     size_t i;
480be2cdc5eSEmilio G. Cota 
481be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
482be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
483be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
484be2cdc5eSEmilio G. Cota 
485be2cdc5eSEmilio G. Cota         g_tree_foreach(rt->tree, func, user_data);
486be2cdc5eSEmilio G. Cota     }
487be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
488be2cdc5eSEmilio G. Cota }
489be2cdc5eSEmilio G. Cota 
490be2cdc5eSEmilio G. Cota size_t tcg_nb_tbs(void)
491be2cdc5eSEmilio G. Cota {
492be2cdc5eSEmilio G. Cota     size_t nb_tbs = 0;
493be2cdc5eSEmilio G. Cota     size_t i;
494be2cdc5eSEmilio G. Cota 
495be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
496be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
497be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
498be2cdc5eSEmilio G. Cota 
499be2cdc5eSEmilio G. Cota         nb_tbs += g_tree_nnodes(rt->tree);
500be2cdc5eSEmilio G. Cota     }
501be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
502be2cdc5eSEmilio G. Cota     return nb_tbs;
503be2cdc5eSEmilio G. Cota }
504be2cdc5eSEmilio G. Cota 
505be2cdc5eSEmilio G. Cota static void tcg_region_tree_reset_all(void)
506be2cdc5eSEmilio G. Cota {
507be2cdc5eSEmilio G. Cota     size_t i;
508be2cdc5eSEmilio G. Cota 
509be2cdc5eSEmilio G. Cota     tcg_region_tree_lock_all();
510be2cdc5eSEmilio G. Cota     for (i = 0; i < region.n; i++) {
511be2cdc5eSEmilio G. Cota         struct tcg_region_tree *rt = region_trees + i * tree_size;
512be2cdc5eSEmilio G. Cota 
513be2cdc5eSEmilio G. Cota         /* Increment the refcount first so that destroy acts as a reset */
514be2cdc5eSEmilio G. Cota         g_tree_ref(rt->tree);
515be2cdc5eSEmilio G. Cota         g_tree_destroy(rt->tree);
516be2cdc5eSEmilio G. Cota     }
517be2cdc5eSEmilio G. Cota     tcg_region_tree_unlock_all();
518be2cdc5eSEmilio G. Cota }
519be2cdc5eSEmilio G. Cota 
520e8feb96fSEmilio G. Cota static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend)
521e8feb96fSEmilio G. Cota {
522e8feb96fSEmilio G. Cota     void *start, *end;
523e8feb96fSEmilio G. Cota 
524e8feb96fSEmilio G. Cota     start = region.start_aligned + curr_region * region.stride;
525e8feb96fSEmilio G. Cota     end = start + region.size;
526e8feb96fSEmilio G. Cota 
527e8feb96fSEmilio G. Cota     if (curr_region == 0) {
528e8feb96fSEmilio G. Cota         start = region.start;
529e8feb96fSEmilio G. Cota     }
530e8feb96fSEmilio G. Cota     if (curr_region == region.n - 1) {
531e8feb96fSEmilio G. Cota         end = region.end;
532e8feb96fSEmilio G. Cota     }
533e8feb96fSEmilio G. Cota 
534e8feb96fSEmilio G. Cota     *pstart = start;
535e8feb96fSEmilio G. Cota     *pend = end;
536e8feb96fSEmilio G. Cota }
537e8feb96fSEmilio G. Cota 
538e8feb96fSEmilio G. Cota static void tcg_region_assign(TCGContext *s, size_t curr_region)
539e8feb96fSEmilio G. Cota {
540e8feb96fSEmilio G. Cota     void *start, *end;
541e8feb96fSEmilio G. Cota 
542e8feb96fSEmilio G. Cota     tcg_region_bounds(curr_region, &start, &end);
543e8feb96fSEmilio G. Cota 
544e8feb96fSEmilio G. Cota     s->code_gen_buffer = start;
545e8feb96fSEmilio G. Cota     s->code_gen_ptr = start;
546e8feb96fSEmilio G. Cota     s->code_gen_buffer_size = end - start;
547e8feb96fSEmilio G. Cota     s->code_gen_highwater = end - TCG_HIGHWATER;
548e8feb96fSEmilio G. Cota }
549e8feb96fSEmilio G. Cota 
550e8feb96fSEmilio G. Cota static bool tcg_region_alloc__locked(TCGContext *s)
551e8feb96fSEmilio G. Cota {
552e8feb96fSEmilio G. Cota     if (region.current == region.n) {
553e8feb96fSEmilio G. Cota         return true;
554e8feb96fSEmilio G. Cota     }
555e8feb96fSEmilio G. Cota     tcg_region_assign(s, region.current);
556e8feb96fSEmilio G. Cota     region.current++;
557e8feb96fSEmilio G. Cota     return false;
558e8feb96fSEmilio G. Cota }
559e8feb96fSEmilio G. Cota 
560e8feb96fSEmilio G. Cota /*
561e8feb96fSEmilio G. Cota  * Request a new region once the one in use has filled up.
562e8feb96fSEmilio G. Cota  * Returns true on error.
563e8feb96fSEmilio G. Cota  */
564e8feb96fSEmilio G. Cota static bool tcg_region_alloc(TCGContext *s)
565e8feb96fSEmilio G. Cota {
566e8feb96fSEmilio G. Cota     bool err;
567e8feb96fSEmilio G. Cota     /* read the region size now; alloc__locked will overwrite it on success */
568e8feb96fSEmilio G. Cota     size_t size_full = s->code_gen_buffer_size;
569e8feb96fSEmilio G. Cota 
570e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
571e8feb96fSEmilio G. Cota     err = tcg_region_alloc__locked(s);
572e8feb96fSEmilio G. Cota     if (!err) {
573e8feb96fSEmilio G. Cota         region.agg_size_full += size_full - TCG_HIGHWATER;
574e8feb96fSEmilio G. Cota     }
575e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
576e8feb96fSEmilio G. Cota     return err;
577e8feb96fSEmilio G. Cota }
578e8feb96fSEmilio G. Cota 
579e8feb96fSEmilio G. Cota /*
580e8feb96fSEmilio G. Cota  * Perform a context's first region allocation.
581e8feb96fSEmilio G. Cota  * This function does _not_ increment region.agg_size_full.
582e8feb96fSEmilio G. Cota  */
583e8feb96fSEmilio G. Cota static inline bool tcg_region_initial_alloc__locked(TCGContext *s)
584e8feb96fSEmilio G. Cota {
585e8feb96fSEmilio G. Cota     return tcg_region_alloc__locked(s);
586e8feb96fSEmilio G. Cota }
587e8feb96fSEmilio G. Cota 
588e8feb96fSEmilio G. Cota /* Call from a safe-work context */
589e8feb96fSEmilio G. Cota void tcg_region_reset_all(void)
590e8feb96fSEmilio G. Cota {
5913468b59eSEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
592e8feb96fSEmilio G. Cota     unsigned int i;
593e8feb96fSEmilio G. Cota 
594e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
595e8feb96fSEmilio G. Cota     region.current = 0;
596e8feb96fSEmilio G. Cota     region.agg_size_full = 0;
597e8feb96fSEmilio G. Cota 
5983468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
5993468b59eSEmilio G. Cota         TCGContext *s = atomic_read(&tcg_ctxs[i]);
6003468b59eSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(s);
601e8feb96fSEmilio G. Cota 
602e8feb96fSEmilio G. Cota         g_assert(!err);
603e8feb96fSEmilio G. Cota     }
604e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
605be2cdc5eSEmilio G. Cota 
606be2cdc5eSEmilio G. Cota     tcg_region_tree_reset_all();
607e8feb96fSEmilio G. Cota }
608e8feb96fSEmilio G. Cota 
6093468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
6103468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
6113468b59eSEmilio G. Cota {
6123468b59eSEmilio G. Cota     return 1;
6133468b59eSEmilio G. Cota }
6143468b59eSEmilio G. Cota #else
6153468b59eSEmilio G. Cota /*
6163468b59eSEmilio G. Cota  * It is likely that some vCPUs will translate more code than others, so we
6173468b59eSEmilio G. Cota  * first try to set more regions than max_cpus, with those regions being of
6183468b59eSEmilio G. Cota  * reasonable size. If that's not possible we make do by evenly dividing
6193468b59eSEmilio G. Cota  * the code_gen_buffer among the vCPUs.
6203468b59eSEmilio G. Cota  */
6213468b59eSEmilio G. Cota static size_t tcg_n_regions(void)
6223468b59eSEmilio G. Cota {
6233468b59eSEmilio G. Cota     size_t i;
6243468b59eSEmilio G. Cota 
6253468b59eSEmilio G. Cota     /* Use a single region if all we have is one vCPU thread */
6265cc8767dSLike Xu #if !defined(CONFIG_USER_ONLY)
6275cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
6285cc8767dSLike Xu     unsigned int max_cpus = ms->smp.max_cpus;
6295cc8767dSLike Xu #endif
6303468b59eSEmilio G. Cota     if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) {
6313468b59eSEmilio G. Cota         return 1;
6323468b59eSEmilio G. Cota     }
6333468b59eSEmilio G. Cota 
6343468b59eSEmilio G. Cota     /* Try to have more regions than max_cpus, with each region being >= 2 MB */
6353468b59eSEmilio G. Cota     for (i = 8; i > 0; i--) {
6363468b59eSEmilio G. Cota         size_t regions_per_thread = i;
6373468b59eSEmilio G. Cota         size_t region_size;
6383468b59eSEmilio G. Cota 
6393468b59eSEmilio G. Cota         region_size = tcg_init_ctx.code_gen_buffer_size;
6403468b59eSEmilio G. Cota         region_size /= max_cpus * regions_per_thread;
6413468b59eSEmilio G. Cota 
6423468b59eSEmilio G. Cota         if (region_size >= 2 * 1024u * 1024) {
6433468b59eSEmilio G. Cota             return max_cpus * regions_per_thread;
6443468b59eSEmilio G. Cota         }
6453468b59eSEmilio G. Cota     }
6463468b59eSEmilio G. Cota     /* If we can't, then just allocate one region per vCPU thread */
6473468b59eSEmilio G. Cota     return max_cpus;
6483468b59eSEmilio G. Cota }
6493468b59eSEmilio G. Cota #endif
6503468b59eSEmilio G. Cota 
651e8feb96fSEmilio G. Cota /*
652e8feb96fSEmilio G. Cota  * Initializes region partitioning.
653e8feb96fSEmilio G. Cota  *
654e8feb96fSEmilio G. Cota  * Called at init time from the parent thread (i.e. the one calling
655e8feb96fSEmilio G. Cota  * tcg_context_init), after the target's TCG globals have been set.
6563468b59eSEmilio G. Cota  *
6573468b59eSEmilio G. Cota  * Region partitioning works by splitting code_gen_buffer into separate regions,
6583468b59eSEmilio G. Cota  * and then assigning regions to TCG threads so that the threads can translate
6593468b59eSEmilio G. Cota  * code in parallel without synchronization.
6603468b59eSEmilio G. Cota  *
6613468b59eSEmilio G. Cota  * In softmmu the number of TCG threads is bounded by max_cpus, so we use at
6623468b59eSEmilio G. Cota  * least max_cpus regions in MTTCG. In !MTTCG we use a single region.
6633468b59eSEmilio G. Cota  * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...])
6643468b59eSEmilio G. Cota  * must have been parsed before calling this function, since it calls
6653468b59eSEmilio G. Cota  * qemu_tcg_mttcg_enabled().
6663468b59eSEmilio G. Cota  *
6673468b59eSEmilio G. Cota  * In user-mode we use a single region.  Having multiple regions in user-mode
6683468b59eSEmilio G. Cota  * is not supported, because the number of vCPU threads (recall that each thread
6693468b59eSEmilio G. Cota  * spawned by the guest corresponds to a vCPU thread) is only bounded by the
6703468b59eSEmilio G. Cota  * OS, and usually this number is huge (tens of thousands is not uncommon).
6713468b59eSEmilio G. Cota  * Thus, given this large bound on the number of vCPU threads and the fact
6723468b59eSEmilio G. Cota  * that code_gen_buffer is allocated at compile-time, we cannot guarantee
6733468b59eSEmilio G. Cota  * that the availability of at least one region per vCPU thread.
6743468b59eSEmilio G. Cota  *
6753468b59eSEmilio G. Cota  * However, this user-mode limitation is unlikely to be a significant problem
6763468b59eSEmilio G. Cota  * in practice. Multi-threaded guests share most if not all of their translated
6773468b59eSEmilio G. Cota  * code, which makes parallel code generation less appealing than in softmmu.
678e8feb96fSEmilio G. Cota  */
679e8feb96fSEmilio G. Cota void tcg_region_init(void)
680e8feb96fSEmilio G. Cota {
681e8feb96fSEmilio G. Cota     void *buf = tcg_init_ctx.code_gen_buffer;
682e8feb96fSEmilio G. Cota     void *aligned;
683e8feb96fSEmilio G. Cota     size_t size = tcg_init_ctx.code_gen_buffer_size;
684e8feb96fSEmilio G. Cota     size_t page_size = qemu_real_host_page_size;
685e8feb96fSEmilio G. Cota     size_t region_size;
686e8feb96fSEmilio G. Cota     size_t n_regions;
687e8feb96fSEmilio G. Cota     size_t i;
688e8feb96fSEmilio G. Cota 
6893468b59eSEmilio G. Cota     n_regions = tcg_n_regions();
690e8feb96fSEmilio G. Cota 
691e8feb96fSEmilio G. Cota     /* The first region will be 'aligned - buf' bytes larger than the others */
692e8feb96fSEmilio G. Cota     aligned = QEMU_ALIGN_PTR_UP(buf, page_size);
693e8feb96fSEmilio G. Cota     g_assert(aligned < tcg_init_ctx.code_gen_buffer + size);
694e8feb96fSEmilio G. Cota     /*
695e8feb96fSEmilio G. Cota      * Make region_size a multiple of page_size, using aligned as the start.
696e8feb96fSEmilio G. Cota      * As a result of this we might end up with a few extra pages at the end of
697e8feb96fSEmilio G. Cota      * the buffer; we will assign those to the last region.
698e8feb96fSEmilio G. Cota      */
699e8feb96fSEmilio G. Cota     region_size = (size - (aligned - buf)) / n_regions;
700e8feb96fSEmilio G. Cota     region_size = QEMU_ALIGN_DOWN(region_size, page_size);
701e8feb96fSEmilio G. Cota 
702e8feb96fSEmilio G. Cota     /* A region must have at least 2 pages; one code, one guard */
703e8feb96fSEmilio G. Cota     g_assert(region_size >= 2 * page_size);
704e8feb96fSEmilio G. Cota 
705e8feb96fSEmilio G. Cota     /* init the region struct */
706e8feb96fSEmilio G. Cota     qemu_mutex_init(&region.lock);
707e8feb96fSEmilio G. Cota     region.n = n_regions;
708e8feb96fSEmilio G. Cota     region.size = region_size - page_size;
709e8feb96fSEmilio G. Cota     region.stride = region_size;
710e8feb96fSEmilio G. Cota     region.start = buf;
711e8feb96fSEmilio G. Cota     region.start_aligned = aligned;
712e8feb96fSEmilio G. Cota     /* page-align the end, since its last page will be a guard page */
713e8feb96fSEmilio G. Cota     region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size);
714e8feb96fSEmilio G. Cota     /* account for that last guard page */
715e8feb96fSEmilio G. Cota     region.end -= page_size;
716e8feb96fSEmilio G. Cota 
717e8feb96fSEmilio G. Cota     /* set guard pages */
718e8feb96fSEmilio G. Cota     for (i = 0; i < region.n; i++) {
719e8feb96fSEmilio G. Cota         void *start, *end;
720e8feb96fSEmilio G. Cota         int rc;
721e8feb96fSEmilio G. Cota 
722e8feb96fSEmilio G. Cota         tcg_region_bounds(i, &start, &end);
723e8feb96fSEmilio G. Cota         rc = qemu_mprotect_none(end, page_size);
724e8feb96fSEmilio G. Cota         g_assert(!rc);
725e8feb96fSEmilio G. Cota     }
726e8feb96fSEmilio G. Cota 
727be2cdc5eSEmilio G. Cota     tcg_region_trees_init();
728be2cdc5eSEmilio G. Cota 
7293468b59eSEmilio G. Cota     /* In user-mode we support only one ctx, so do the initial allocation now */
7303468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
731e8feb96fSEmilio G. Cota     {
732e8feb96fSEmilio G. Cota         bool err = tcg_region_initial_alloc__locked(tcg_ctx);
733e8feb96fSEmilio G. Cota 
734e8feb96fSEmilio G. Cota         g_assert(!err);
735e8feb96fSEmilio G. Cota     }
7363468b59eSEmilio G. Cota #endif
737e8feb96fSEmilio G. Cota }
738e8feb96fSEmilio G. Cota 
739*38b47b19SEmilio G. Cota static void alloc_tcg_plugin_context(TCGContext *s)
740*38b47b19SEmilio G. Cota {
741*38b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
742*38b47b19SEmilio G. Cota     s->plugin_tb = g_new0(struct qemu_plugin_tb, 1);
743*38b47b19SEmilio G. Cota     s->plugin_tb->insns =
744*38b47b19SEmilio G. Cota         g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn);
745*38b47b19SEmilio G. Cota #endif
746*38b47b19SEmilio G. Cota }
747*38b47b19SEmilio G. Cota 
748e8feb96fSEmilio G. Cota /*
7493468b59eSEmilio G. Cota  * All TCG threads except the parent (i.e. the one that called tcg_context_init
7503468b59eSEmilio G. Cota  * and registered the target's TCG globals) must register with this function
7513468b59eSEmilio G. Cota  * before initiating translation.
7523468b59eSEmilio G. Cota  *
7533468b59eSEmilio G. Cota  * In user-mode we just point tcg_ctx to tcg_init_ctx. See the documentation
7543468b59eSEmilio G. Cota  * of tcg_region_init() for the reasoning behind this.
7553468b59eSEmilio G. Cota  *
7563468b59eSEmilio G. Cota  * In softmmu each caller registers its context in tcg_ctxs[]. Note that in
7573468b59eSEmilio G. Cota  * softmmu tcg_ctxs[] does not track tcg_ctx_init, since the initial context
7583468b59eSEmilio G. Cota  * is not used anymore for translation once this function is called.
7593468b59eSEmilio G. Cota  *
7603468b59eSEmilio G. Cota  * Not tracking tcg_init_ctx in tcg_ctxs[] in softmmu keeps code that iterates
7613468b59eSEmilio G. Cota  * over the array (e.g. tcg_code_size() the same for both softmmu and user-mode.
7623468b59eSEmilio G. Cota  */
7633468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
7643468b59eSEmilio G. Cota void tcg_register_thread(void)
7653468b59eSEmilio G. Cota {
7663468b59eSEmilio G. Cota     tcg_ctx = &tcg_init_ctx;
7673468b59eSEmilio G. Cota }
7683468b59eSEmilio G. Cota #else
7693468b59eSEmilio G. Cota void tcg_register_thread(void)
7703468b59eSEmilio G. Cota {
7715cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
7723468b59eSEmilio G. Cota     TCGContext *s = g_malloc(sizeof(*s));
7733468b59eSEmilio G. Cota     unsigned int i, n;
7743468b59eSEmilio G. Cota     bool err;
7753468b59eSEmilio G. Cota 
7763468b59eSEmilio G. Cota     *s = tcg_init_ctx;
7773468b59eSEmilio G. Cota 
7783468b59eSEmilio G. Cota     /* Relink mem_base.  */
7793468b59eSEmilio G. Cota     for (i = 0, n = tcg_init_ctx.nb_globals; i < n; ++i) {
7803468b59eSEmilio G. Cota         if (tcg_init_ctx.temps[i].mem_base) {
7813468b59eSEmilio G. Cota             ptrdiff_t b = tcg_init_ctx.temps[i].mem_base - tcg_init_ctx.temps;
7823468b59eSEmilio G. Cota             tcg_debug_assert(b >= 0 && b < n);
7833468b59eSEmilio G. Cota             s->temps[i].mem_base = &s->temps[b];
7843468b59eSEmilio G. Cota         }
7853468b59eSEmilio G. Cota     }
7863468b59eSEmilio G. Cota 
7873468b59eSEmilio G. Cota     /* Claim an entry in tcg_ctxs */
7883468b59eSEmilio G. Cota     n = atomic_fetch_inc(&n_tcg_ctxs);
7895cc8767dSLike Xu     g_assert(n < ms->smp.max_cpus);
7903468b59eSEmilio G. Cota     atomic_set(&tcg_ctxs[n], s);
7913468b59eSEmilio G. Cota 
792*38b47b19SEmilio G. Cota     if (n > 0) {
793*38b47b19SEmilio G. Cota         alloc_tcg_plugin_context(s);
794*38b47b19SEmilio G. Cota     }
795*38b47b19SEmilio G. Cota 
7963468b59eSEmilio G. Cota     tcg_ctx = s;
7973468b59eSEmilio G. Cota     qemu_mutex_lock(&region.lock);
7983468b59eSEmilio G. Cota     err = tcg_region_initial_alloc__locked(tcg_ctx);
7993468b59eSEmilio G. Cota     g_assert(!err);
8003468b59eSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
8013468b59eSEmilio G. Cota }
8023468b59eSEmilio G. Cota #endif /* !CONFIG_USER_ONLY */
8033468b59eSEmilio G. Cota 
8043468b59eSEmilio G. Cota /*
805e8feb96fSEmilio G. Cota  * Returns the size (in bytes) of all translated code (i.e. from all regions)
806e8feb96fSEmilio G. Cota  * currently in the cache.
807e8feb96fSEmilio G. Cota  * See also: tcg_code_capacity()
808e8feb96fSEmilio G. Cota  * Do not confuse with tcg_current_code_size(); that one applies to a single
809e8feb96fSEmilio G. Cota  * TCG context.
810e8feb96fSEmilio G. Cota  */
811e8feb96fSEmilio G. Cota size_t tcg_code_size(void)
812e8feb96fSEmilio G. Cota {
8133468b59eSEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
814e8feb96fSEmilio G. Cota     unsigned int i;
815e8feb96fSEmilio G. Cota     size_t total;
816e8feb96fSEmilio G. Cota 
817e8feb96fSEmilio G. Cota     qemu_mutex_lock(&region.lock);
818e8feb96fSEmilio G. Cota     total = region.agg_size_full;
8193468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
8203468b59eSEmilio G. Cota         const TCGContext *s = atomic_read(&tcg_ctxs[i]);
821e8feb96fSEmilio G. Cota         size_t size;
822e8feb96fSEmilio G. Cota 
823e8feb96fSEmilio G. Cota         size = atomic_read(&s->code_gen_ptr) - s->code_gen_buffer;
824e8feb96fSEmilio G. Cota         g_assert(size <= s->code_gen_buffer_size);
825e8feb96fSEmilio G. Cota         total += size;
826e8feb96fSEmilio G. Cota     }
827e8feb96fSEmilio G. Cota     qemu_mutex_unlock(&region.lock);
828e8feb96fSEmilio G. Cota     return total;
829e8feb96fSEmilio G. Cota }
830e8feb96fSEmilio G. Cota 
831e8feb96fSEmilio G. Cota /*
832e8feb96fSEmilio G. Cota  * Returns the code capacity (in bytes) of the entire cache, i.e. including all
833e8feb96fSEmilio G. Cota  * regions.
834e8feb96fSEmilio G. Cota  * See also: tcg_code_size()
835e8feb96fSEmilio G. Cota  */
836e8feb96fSEmilio G. Cota size_t tcg_code_capacity(void)
837e8feb96fSEmilio G. Cota {
838e8feb96fSEmilio G. Cota     size_t guard_size, capacity;
839e8feb96fSEmilio G. Cota 
840e8feb96fSEmilio G. Cota     /* no need for synchronization; these variables are set at init time */
841e8feb96fSEmilio G. Cota     guard_size = region.stride - region.size;
842e8feb96fSEmilio G. Cota     capacity = region.end + guard_size - region.start;
843e8feb96fSEmilio G. Cota     capacity -= region.n * (guard_size + TCG_HIGHWATER);
844e8feb96fSEmilio G. Cota     return capacity;
845e8feb96fSEmilio G. Cota }
846e8feb96fSEmilio G. Cota 
847128ed227SEmilio G. Cota size_t tcg_tb_phys_invalidate_count(void)
848128ed227SEmilio G. Cota {
849128ed227SEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
850128ed227SEmilio G. Cota     unsigned int i;
851128ed227SEmilio G. Cota     size_t total = 0;
852128ed227SEmilio G. Cota 
853128ed227SEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
854128ed227SEmilio G. Cota         const TCGContext *s = atomic_read(&tcg_ctxs[i]);
855128ed227SEmilio G. Cota 
856128ed227SEmilio G. Cota         total += atomic_read(&s->tb_phys_invalidate_count);
857128ed227SEmilio G. Cota     }
858128ed227SEmilio G. Cota     return total;
859128ed227SEmilio G. Cota }
860128ed227SEmilio G. Cota 
861c896fe29Sbellard /* pool based memory allocation */
862c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
863c896fe29Sbellard {
864c896fe29Sbellard     TCGPool *p;
865c896fe29Sbellard     int pool_size;
866c896fe29Sbellard 
867c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
868c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
8697267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
870c896fe29Sbellard         p->size = size;
8714055299eSKirill Batuzov         p->next = s->pool_first_large;
8724055299eSKirill Batuzov         s->pool_first_large = p;
8734055299eSKirill Batuzov         return p->data;
874c896fe29Sbellard     } else {
875c896fe29Sbellard         p = s->pool_current;
876c896fe29Sbellard         if (!p) {
877c896fe29Sbellard             p = s->pool_first;
878c896fe29Sbellard             if (!p)
879c896fe29Sbellard                 goto new_pool;
880c896fe29Sbellard         } else {
881c896fe29Sbellard             if (!p->next) {
882c896fe29Sbellard             new_pool:
883c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
8847267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
885c896fe29Sbellard                 p->size = pool_size;
886c896fe29Sbellard                 p->next = NULL;
887c896fe29Sbellard                 if (s->pool_current)
888c896fe29Sbellard                     s->pool_current->next = p;
889c896fe29Sbellard                 else
890c896fe29Sbellard                     s->pool_first = p;
891c896fe29Sbellard             } else {
892c896fe29Sbellard                 p = p->next;
893c896fe29Sbellard             }
894c896fe29Sbellard         }
895c896fe29Sbellard     }
896c896fe29Sbellard     s->pool_current = p;
897c896fe29Sbellard     s->pool_cur = p->data + size;
898c896fe29Sbellard     s->pool_end = p->data + p->size;
899c896fe29Sbellard     return p->data;
900c896fe29Sbellard }
901c896fe29Sbellard 
902c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
903c896fe29Sbellard {
9044055299eSKirill Batuzov     TCGPool *p, *t;
9054055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
9064055299eSKirill Batuzov         t = p->next;
9074055299eSKirill Batuzov         g_free(p);
9084055299eSKirill Batuzov     }
9094055299eSKirill Batuzov     s->pool_first_large = NULL;
910c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
911c896fe29Sbellard     s->pool_current = NULL;
912c896fe29Sbellard }
913c896fe29Sbellard 
914100b5e01SRichard Henderson typedef struct TCGHelperInfo {
915100b5e01SRichard Henderson     void *func;
916100b5e01SRichard Henderson     const char *name;
917afb49896SRichard Henderson     unsigned flags;
918afb49896SRichard Henderson     unsigned sizemask;
919100b5e01SRichard Henderson } TCGHelperInfo;
920100b5e01SRichard Henderson 
9212ef6175aSRichard Henderson #include "exec/helper-proto.h"
9222ef6175aSRichard Henderson 
923100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = {
9242ef6175aSRichard Henderson #include "exec/helper-tcg.h"
925100b5e01SRichard Henderson };
926619205fdSEmilio G. Cota static GHashTable *helper_table;
927100b5e01SRichard Henderson 
92891478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
929f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
9301c2adb95SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
9311c2adb95SRichard Henderson                                             TCGReg reg, const char *name);
93291478cefSRichard Henderson 
933c896fe29Sbellard void tcg_context_init(TCGContext *s)
934c896fe29Sbellard {
935100b5e01SRichard Henderson     int op, total_args, n, i;
936c896fe29Sbellard     TCGOpDef *def;
937c896fe29Sbellard     TCGArgConstraint *args_ct;
938c896fe29Sbellard     int *sorted_args;
9391c2adb95SRichard Henderson     TCGTemp *ts;
940c896fe29Sbellard 
941c896fe29Sbellard     memset(s, 0, sizeof(*s));
942c896fe29Sbellard     s->nb_globals = 0;
943c896fe29Sbellard 
944c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
945c896fe29Sbellard        space */
946c896fe29Sbellard     total_args = 0;
947c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
948c896fe29Sbellard         def = &tcg_op_defs[op];
949c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
950c896fe29Sbellard         total_args += n;
951c896fe29Sbellard     }
952c896fe29Sbellard 
9537267c094SAnthony Liguori     args_ct = g_malloc(sizeof(TCGArgConstraint) * total_args);
9547267c094SAnthony Liguori     sorted_args = g_malloc(sizeof(int) * total_args);
955c896fe29Sbellard 
956c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
957c896fe29Sbellard         def = &tcg_op_defs[op];
958c896fe29Sbellard         def->args_ct = args_ct;
959c896fe29Sbellard         def->sorted_args = sorted_args;
960c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
961c896fe29Sbellard         sorted_args += n;
962c896fe29Sbellard         args_ct += n;
963c896fe29Sbellard     }
964c896fe29Sbellard 
9655cd8f621SRichard Henderson     /* Register helpers.  */
96684fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
967619205fdSEmilio G. Cota     helper_table = g_hash_table_new(NULL, NULL);
96884fd9dd3SRichard Henderson 
969100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
97084fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
97172866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
972100b5e01SRichard Henderson     }
9735cd8f621SRichard Henderson 
974c896fe29Sbellard     tcg_target_init(s);
975f69d277eSRichard Henderson     process_op_defs(s);
97691478cefSRichard Henderson 
97791478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
97891478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
97991478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
98091478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
98191478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
98291478cefSRichard Henderson             break;
98391478cefSRichard Henderson         }
98491478cefSRichard Henderson     }
98591478cefSRichard Henderson     for (i = 0; i < n; ++i) {
98691478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
98791478cefSRichard Henderson     }
98891478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
98991478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
99091478cefSRichard Henderson     }
991b1311c4aSEmilio G. Cota 
992*38b47b19SEmilio G. Cota     alloc_tcg_plugin_context(s);
993*38b47b19SEmilio G. Cota 
994b1311c4aSEmilio G. Cota     tcg_ctx = s;
9953468b59eSEmilio G. Cota     /*
9963468b59eSEmilio G. Cota      * In user-mode we simply share the init context among threads, since we
9973468b59eSEmilio G. Cota      * use a single region. See the documentation tcg_region_init() for the
9983468b59eSEmilio G. Cota      * reasoning behind this.
9993468b59eSEmilio G. Cota      * In softmmu we will have at most max_cpus TCG threads.
10003468b59eSEmilio G. Cota      */
10013468b59eSEmilio G. Cota #ifdef CONFIG_USER_ONLY
1002df2cce29SEmilio G. Cota     tcg_ctxs = &tcg_ctx;
1003df2cce29SEmilio G. Cota     n_tcg_ctxs = 1;
10043468b59eSEmilio G. Cota #else
10055cc8767dSLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
10065cc8767dSLike Xu     unsigned int max_cpus = ms->smp.max_cpus;
10073468b59eSEmilio G. Cota     tcg_ctxs = g_new(TCGContext *, max_cpus);
10083468b59eSEmilio G. Cota #endif
10091c2adb95SRichard Henderson 
10101c2adb95SRichard Henderson     tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
10111c2adb95SRichard Henderson     ts = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, TCG_AREG0, "env");
10121c2adb95SRichard Henderson     cpu_env = temp_tcgv_ptr(ts);
10139002ec79SRichard Henderson }
1014b03cce8eSbellard 
10156e3b2bfdSEmilio G. Cota /*
10166e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
10176e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
10186e3b2bfdSEmilio G. Cota  */
10196e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
10206e3b2bfdSEmilio G. Cota {
10216e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
10226e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
10236e3b2bfdSEmilio G. Cota     void *next;
10246e3b2bfdSEmilio G. Cota 
1025e8feb96fSEmilio G. Cota  retry:
10266e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
10276e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
10286e3b2bfdSEmilio G. Cota 
10296e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
1030e8feb96fSEmilio G. Cota         if (tcg_region_alloc(s)) {
10316e3b2bfdSEmilio G. Cota             return NULL;
10326e3b2bfdSEmilio G. Cota         }
1033e8feb96fSEmilio G. Cota         goto retry;
1034e8feb96fSEmilio G. Cota     }
1035e8feb96fSEmilio G. Cota     atomic_set(&s->code_gen_ptr, next);
103657a26946SRichard Henderson     s->data_gen_ptr = NULL;
10376e3b2bfdSEmilio G. Cota     return tb;
10386e3b2bfdSEmilio G. Cota }
10396e3b2bfdSEmilio G. Cota 
10409002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
10419002ec79SRichard Henderson {
10428163b749SRichard Henderson     size_t prologue_size, total_size;
10438163b749SRichard Henderson     void *buf0, *buf1;
10448163b749SRichard Henderson 
10458163b749SRichard Henderson     /* Put the prologue at the beginning of code_gen_buffer.  */
10468163b749SRichard Henderson     buf0 = s->code_gen_buffer;
10475b38ee31SRichard Henderson     total_size = s->code_gen_buffer_size;
10488163b749SRichard Henderson     s->code_ptr = buf0;
10498163b749SRichard Henderson     s->code_buf = buf0;
10505b38ee31SRichard Henderson     s->data_gen_ptr = NULL;
10518163b749SRichard Henderson     s->code_gen_prologue = buf0;
10528163b749SRichard Henderson 
10535b38ee31SRichard Henderson     /* Compute a high-water mark, at which we voluntarily flush the buffer
10545b38ee31SRichard Henderson        and start over.  The size here is arbitrary, significantly larger
10555b38ee31SRichard Henderson        than we expect the code generation for any one opcode to require.  */
10565b38ee31SRichard Henderson     s->code_gen_highwater = s->code_gen_buffer + (total_size - TCG_HIGHWATER);
10575b38ee31SRichard Henderson 
10585b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
10595b38ee31SRichard Henderson     s->pool_labels = NULL;
10605b38ee31SRichard Henderson #endif
10615b38ee31SRichard Henderson 
10628163b749SRichard Henderson     /* Generate the prologue.  */
1063b03cce8eSbellard     tcg_target_qemu_prologue(s);
10645b38ee31SRichard Henderson 
10655b38ee31SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
10665b38ee31SRichard Henderson     /* Allow the prologue to put e.g. guest_base into a pool entry.  */
10675b38ee31SRichard Henderson     {
10681768987bSRichard Henderson         int result = tcg_out_pool_finalize(s);
10691768987bSRichard Henderson         tcg_debug_assert(result == 0);
10705b38ee31SRichard Henderson     }
10715b38ee31SRichard Henderson #endif
10725b38ee31SRichard Henderson 
10738163b749SRichard Henderson     buf1 = s->code_ptr;
10748163b749SRichard Henderson     flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1);
10758163b749SRichard Henderson 
10768163b749SRichard Henderson     /* Deduct the prologue from the buffer.  */
10778163b749SRichard Henderson     prologue_size = tcg_current_code_size(s);
10788163b749SRichard Henderson     s->code_gen_ptr = buf1;
10798163b749SRichard Henderson     s->code_gen_buffer = buf1;
10808163b749SRichard Henderson     s->code_buf = buf1;
10815b38ee31SRichard Henderson     total_size -= prologue_size;
10828163b749SRichard Henderson     s->code_gen_buffer_size = total_size;
10838163b749SRichard Henderson 
10848163b749SRichard Henderson     tcg_register_jit(s->code_gen_buffer, total_size);
1085d6b64b2bSRichard Henderson 
1086d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
1087d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
10881ee73216SRichard Henderson         qemu_log_lock();
10898163b749SRichard Henderson         qemu_log("PROLOGUE: [size=%zu]\n", prologue_size);
10905b38ee31SRichard Henderson         if (s->data_gen_ptr) {
10915b38ee31SRichard Henderson             size_t code_size = s->data_gen_ptr - buf0;
10925b38ee31SRichard Henderson             size_t data_size = prologue_size - code_size;
10935b38ee31SRichard Henderson             size_t i;
10945b38ee31SRichard Henderson 
10955b38ee31SRichard Henderson             log_disas(buf0, code_size);
10965b38ee31SRichard Henderson 
10975b38ee31SRichard Henderson             for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
10985b38ee31SRichard Henderson                 if (sizeof(tcg_target_ulong) == 8) {
10995b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",
11005b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
11015b38ee31SRichard Henderson                              *(uint64_t *)(s->data_gen_ptr + i));
11025b38ee31SRichard Henderson                 } else {
11035b38ee31SRichard Henderson                     qemu_log("0x%08" PRIxPTR ":  .long  0x%08x\n",
11045b38ee31SRichard Henderson                              (uintptr_t)s->data_gen_ptr + i,
11055b38ee31SRichard Henderson                              *(uint32_t *)(s->data_gen_ptr + i));
11065b38ee31SRichard Henderson                 }
11075b38ee31SRichard Henderson             }
11085b38ee31SRichard Henderson         } else {
11098163b749SRichard Henderson             log_disas(buf0, prologue_size);
11105b38ee31SRichard Henderson         }
1111d6b64b2bSRichard Henderson         qemu_log("\n");
1112d6b64b2bSRichard Henderson         qemu_log_flush();
11131ee73216SRichard Henderson         qemu_log_unlock();
1114d6b64b2bSRichard Henderson     }
1115d6b64b2bSRichard Henderson #endif
1116cedbcb01SEmilio G. Cota 
1117cedbcb01SEmilio G. Cota     /* Assert that goto_ptr is implemented completely.  */
1118cedbcb01SEmilio G. Cota     if (TCG_TARGET_HAS_goto_ptr) {
1119cedbcb01SEmilio G. Cota         tcg_debug_assert(s->code_gen_epilogue != NULL);
1120cedbcb01SEmilio G. Cota     }
1121c896fe29Sbellard }
1122c896fe29Sbellard 
1123c896fe29Sbellard void tcg_func_start(TCGContext *s)
1124c896fe29Sbellard {
1125c896fe29Sbellard     tcg_pool_reset(s);
1126c896fe29Sbellard     s->nb_temps = s->nb_globals;
11270ec9eabcSRichard Henderson 
11280ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
11290ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
11300ec9eabcSRichard Henderson 
1131abebf925SRichard Henderson     s->nb_ops = 0;
1132c896fe29Sbellard     s->nb_labels = 0;
1133c896fe29Sbellard     s->current_frame_offset = s->frame_start;
1134c896fe29Sbellard 
11350a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
11360a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
11370a209d4bSRichard Henderson #endif
11380a209d4bSRichard Henderson 
113915fa08f8SRichard Henderson     QTAILQ_INIT(&s->ops);
114015fa08f8SRichard Henderson     QTAILQ_INIT(&s->free_ops);
1141bef16ab4SRichard Henderson     QSIMPLEQ_INIT(&s->labels);
1142c896fe29Sbellard }
1143c896fe29Sbellard 
11447ca4b752SRichard Henderson static inline TCGTemp *tcg_temp_alloc(TCGContext *s)
11457ca4b752SRichard Henderson {
11467ca4b752SRichard Henderson     int n = s->nb_temps++;
11477ca4b752SRichard Henderson     tcg_debug_assert(n < TCG_MAX_TEMPS);
11487ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
11497ca4b752SRichard Henderson }
11507ca4b752SRichard Henderson 
11517ca4b752SRichard Henderson static inline TCGTemp *tcg_global_alloc(TCGContext *s)
11527ca4b752SRichard Henderson {
1153fa477d25SRichard Henderson     TCGTemp *ts;
1154fa477d25SRichard Henderson 
11557ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
11567ca4b752SRichard Henderson     s->nb_globals++;
1157fa477d25SRichard Henderson     ts = tcg_temp_alloc(s);
1158fa477d25SRichard Henderson     ts->temp_global = 1;
1159fa477d25SRichard Henderson 
1160fa477d25SRichard Henderson     return ts;
1161c896fe29Sbellard }
1162c896fe29Sbellard 
1163085272b3SRichard Henderson static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
1164b6638662SRichard Henderson                                             TCGReg reg, const char *name)
1165c896fe29Sbellard {
1166c896fe29Sbellard     TCGTemp *ts;
1167c896fe29Sbellard 
1168b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
1169c896fe29Sbellard         tcg_abort();
1170b3a62939SRichard Henderson     }
11717ca4b752SRichard Henderson 
11727ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
1173c896fe29Sbellard     ts->base_type = type;
1174c896fe29Sbellard     ts->type = type;
1175c896fe29Sbellard     ts->fixed_reg = 1;
1176c896fe29Sbellard     ts->reg = reg;
1177c896fe29Sbellard     ts->name = name;
1178c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
11797ca4b752SRichard Henderson 
1180085272b3SRichard Henderson     return ts;
1181a7812ae4Spbrook }
1182a7812ae4Spbrook 
1183b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
1184a7812ae4Spbrook {
1185b3a62939SRichard Henderson     s->frame_start = start;
1186b3a62939SRichard Henderson     s->frame_end = start + size;
1187085272b3SRichard Henderson     s->frame_temp
1188085272b3SRichard Henderson         = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
1189b3a62939SRichard Henderson }
1190a7812ae4Spbrook 
1191085272b3SRichard Henderson TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
1192e1ccc054SRichard Henderson                                      intptr_t offset, const char *name)
1193c896fe29Sbellard {
1194b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1195dc41aa7dSRichard Henderson     TCGTemp *base_ts = tcgv_ptr_temp(base);
11967ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
1197b3915dbbSRichard Henderson     int indirect_reg = 0, bigendian = 0;
11987ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
11997ca4b752SRichard Henderson     bigendian = 1;
12007ca4b752SRichard Henderson #endif
1201c896fe29Sbellard 
1202b3915dbbSRichard Henderson     if (!base_ts->fixed_reg) {
12035a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
12045a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
1205b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
12065a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
12075a18407fSRichard Henderson                             ? 2 : 1);
12085a18407fSRichard Henderson         indirect_reg = 1;
1209b3915dbbSRichard Henderson     }
1210b3915dbbSRichard Henderson 
12117ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
12127ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
1213c896fe29Sbellard         char buf[64];
12147ca4b752SRichard Henderson 
12157ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
1216c896fe29Sbellard         ts->type = TCG_TYPE_I32;
1217b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1218c896fe29Sbellard         ts->mem_allocated = 1;
1219b3a62939SRichard Henderson         ts->mem_base = base_ts;
12207ca4b752SRichard Henderson         ts->mem_offset = offset + bigendian * 4;
1221c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1222c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
1223c896fe29Sbellard         ts->name = strdup(buf);
1224c896fe29Sbellard 
12257ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
12267ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
12277ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
1228b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
12297ca4b752SRichard Henderson         ts2->mem_allocated = 1;
12307ca4b752SRichard Henderson         ts2->mem_base = base_ts;
12317ca4b752SRichard Henderson         ts2->mem_offset = offset + (1 - bigendian) * 4;
1232c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
1233c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
1234120c1084SRichard Henderson         ts2->name = strdup(buf);
12357ca4b752SRichard Henderson     } else {
1236c896fe29Sbellard         ts->base_type = type;
1237c896fe29Sbellard         ts->type = type;
1238b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
1239c896fe29Sbellard         ts->mem_allocated = 1;
1240b3a62939SRichard Henderson         ts->mem_base = base_ts;
1241c896fe29Sbellard         ts->mem_offset = offset;
1242c896fe29Sbellard         ts->name = name;
1243c896fe29Sbellard     }
1244085272b3SRichard Henderson     return ts;
1245c896fe29Sbellard }
1246c896fe29Sbellard 
12475bfa8034SRichard Henderson TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local)
1248c896fe29Sbellard {
1249b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1250c896fe29Sbellard     TCGTemp *ts;
1251641d5fbeSbellard     int idx, k;
1252c896fe29Sbellard 
12530ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
12540ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
12550ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
12560ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
12570ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
12580ec9eabcSRichard Henderson 
1259e8996ee0Sbellard         ts = &s->temps[idx];
1260e8996ee0Sbellard         ts->temp_allocated = 1;
12617ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
12627ca4b752SRichard Henderson         tcg_debug_assert(ts->temp_local == temp_local);
1263e8996ee0Sbellard     } else {
12647ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
12657ca4b752SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
12667ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
12677ca4b752SRichard Henderson 
1268c896fe29Sbellard             ts->base_type = type;
1269c896fe29Sbellard             ts->type = TCG_TYPE_I32;
1270e8996ee0Sbellard             ts->temp_allocated = 1;
1271641d5fbeSbellard             ts->temp_local = temp_local;
12727ca4b752SRichard Henderson 
12737ca4b752SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
12747ca4b752SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
12757ca4b752SRichard Henderson             ts2->type = TCG_TYPE_I32;
12767ca4b752SRichard Henderson             ts2->temp_allocated = 1;
12777ca4b752SRichard Henderson             ts2->temp_local = temp_local;
12787ca4b752SRichard Henderson         } else {
1279c896fe29Sbellard             ts->base_type = type;
1280c896fe29Sbellard             ts->type = type;
1281e8996ee0Sbellard             ts->temp_allocated = 1;
1282641d5fbeSbellard             ts->temp_local = temp_local;
1283c896fe29Sbellard         }
1284e8996ee0Sbellard     }
128527bfd83cSPeter Maydell 
128627bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
128727bfd83cSPeter Maydell     s->temps_in_use++;
128827bfd83cSPeter Maydell #endif
1289085272b3SRichard Henderson     return ts;
1290c896fe29Sbellard }
1291c896fe29Sbellard 
1292d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec(TCGType type)
1293d2fd745fSRichard Henderson {
1294d2fd745fSRichard Henderson     TCGTemp *t;
1295d2fd745fSRichard Henderson 
1296d2fd745fSRichard Henderson #ifdef CONFIG_DEBUG_TCG
1297d2fd745fSRichard Henderson     switch (type) {
1298d2fd745fSRichard Henderson     case TCG_TYPE_V64:
1299d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v64);
1300d2fd745fSRichard Henderson         break;
1301d2fd745fSRichard Henderson     case TCG_TYPE_V128:
1302d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v128);
1303d2fd745fSRichard Henderson         break;
1304d2fd745fSRichard Henderson     case TCG_TYPE_V256:
1305d2fd745fSRichard Henderson         assert(TCG_TARGET_HAS_v256);
1306d2fd745fSRichard Henderson         break;
1307d2fd745fSRichard Henderson     default:
1308d2fd745fSRichard Henderson         g_assert_not_reached();
1309d2fd745fSRichard Henderson     }
1310d2fd745fSRichard Henderson #endif
1311d2fd745fSRichard Henderson 
1312d2fd745fSRichard Henderson     t = tcg_temp_new_internal(type, 0);
1313d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1314d2fd745fSRichard Henderson }
1315d2fd745fSRichard Henderson 
1316d2fd745fSRichard Henderson /* Create a new temp of the same type as an existing temp.  */
1317d2fd745fSRichard Henderson TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
1318d2fd745fSRichard Henderson {
1319d2fd745fSRichard Henderson     TCGTemp *t = tcgv_vec_temp(match);
1320d2fd745fSRichard Henderson 
1321d2fd745fSRichard Henderson     tcg_debug_assert(t->temp_allocated != 0);
1322d2fd745fSRichard Henderson 
1323d2fd745fSRichard Henderson     t = tcg_temp_new_internal(t->base_type, 0);
1324d2fd745fSRichard Henderson     return temp_tcgv_vec(t);
1325d2fd745fSRichard Henderson }
1326d2fd745fSRichard Henderson 
13275bfa8034SRichard Henderson void tcg_temp_free_internal(TCGTemp *ts)
1328c896fe29Sbellard {
1329b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
1330085272b3SRichard Henderson     int k, idx;
1331c896fe29Sbellard 
133227bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
133327bfd83cSPeter Maydell     s->temps_in_use--;
133427bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
133527bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
133627bfd83cSPeter Maydell     }
133727bfd83cSPeter Maydell #endif
133827bfd83cSPeter Maydell 
1339085272b3SRichard Henderson     tcg_debug_assert(ts->temp_global == 0);
1340eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
1341e8996ee0Sbellard     ts->temp_allocated = 0;
13420ec9eabcSRichard Henderson 
1343085272b3SRichard Henderson     idx = temp_idx(ts);
134418d13fa2SAlexander Graf     k = ts->base_type + (ts->temp_local ? TCG_TYPE_COUNT : 0);
13450ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
1346e8996ee0Sbellard }
1347e8996ee0Sbellard 
1348a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
1349a7812ae4Spbrook {
1350a7812ae4Spbrook     TCGv_i32 t0;
1351a7812ae4Spbrook     t0 = tcg_temp_new_i32();
1352e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
1353e8996ee0Sbellard     return t0;
1354c896fe29Sbellard }
1355c896fe29Sbellard 
1356a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
1357c896fe29Sbellard {
1358a7812ae4Spbrook     TCGv_i64 t0;
1359a7812ae4Spbrook     t0 = tcg_temp_new_i64();
1360e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
1361e8996ee0Sbellard     return t0;
1362c896fe29Sbellard }
1363c896fe29Sbellard 
1364a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
1365bdffd4a9Saurel32 {
1366a7812ae4Spbrook     TCGv_i32 t0;
1367a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
1368bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
1369bdffd4a9Saurel32     return t0;
1370bdffd4a9Saurel32 }
1371bdffd4a9Saurel32 
1372a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
1373bdffd4a9Saurel32 {
1374a7812ae4Spbrook     TCGv_i64 t0;
1375a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
1376bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
1377bdffd4a9Saurel32     return t0;
1378bdffd4a9Saurel32 }
1379bdffd4a9Saurel32 
138027bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
138127bfd83cSPeter Maydell void tcg_clear_temp_count(void)
138227bfd83cSPeter Maydell {
1383b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
138427bfd83cSPeter Maydell     s->temps_in_use = 0;
138527bfd83cSPeter Maydell }
138627bfd83cSPeter Maydell 
138727bfd83cSPeter Maydell int tcg_check_temp_count(void)
138827bfd83cSPeter Maydell {
1389b1311c4aSEmilio G. Cota     TCGContext *s = tcg_ctx;
139027bfd83cSPeter Maydell     if (s->temps_in_use) {
139127bfd83cSPeter Maydell         /* Clear the count so that we don't give another
139227bfd83cSPeter Maydell          * warning immediately next time around.
139327bfd83cSPeter Maydell          */
139427bfd83cSPeter Maydell         s->temps_in_use = 0;
139527bfd83cSPeter Maydell         return 1;
139627bfd83cSPeter Maydell     }
139727bfd83cSPeter Maydell     return 0;
139827bfd83cSPeter Maydell }
139927bfd83cSPeter Maydell #endif
140027bfd83cSPeter Maydell 
1401be0f34b5SRichard Henderson /* Return true if OP may appear in the opcode stream.
1402be0f34b5SRichard Henderson    Test the runtime variable that controls each opcode.  */
1403be0f34b5SRichard Henderson bool tcg_op_supported(TCGOpcode op)
1404be0f34b5SRichard Henderson {
1405d2fd745fSRichard Henderson     const bool have_vec
1406d2fd745fSRichard Henderson         = TCG_TARGET_HAS_v64 | TCG_TARGET_HAS_v128 | TCG_TARGET_HAS_v256;
1407d2fd745fSRichard Henderson 
1408be0f34b5SRichard Henderson     switch (op) {
1409be0f34b5SRichard Henderson     case INDEX_op_discard:
1410be0f34b5SRichard Henderson     case INDEX_op_set_label:
1411be0f34b5SRichard Henderson     case INDEX_op_call:
1412be0f34b5SRichard Henderson     case INDEX_op_br:
1413be0f34b5SRichard Henderson     case INDEX_op_mb:
1414be0f34b5SRichard Henderson     case INDEX_op_insn_start:
1415be0f34b5SRichard Henderson     case INDEX_op_exit_tb:
1416be0f34b5SRichard Henderson     case INDEX_op_goto_tb:
1417be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i32:
1418be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i32:
1419be0f34b5SRichard Henderson     case INDEX_op_qemu_ld_i64:
1420be0f34b5SRichard Henderson     case INDEX_op_qemu_st_i64:
1421be0f34b5SRichard Henderson         return true;
1422be0f34b5SRichard Henderson 
1423be0f34b5SRichard Henderson     case INDEX_op_goto_ptr:
1424be0f34b5SRichard Henderson         return TCG_TARGET_HAS_goto_ptr;
1425be0f34b5SRichard Henderson 
1426be0f34b5SRichard Henderson     case INDEX_op_mov_i32:
1427be0f34b5SRichard Henderson     case INDEX_op_movi_i32:
1428be0f34b5SRichard Henderson     case INDEX_op_setcond_i32:
1429be0f34b5SRichard Henderson     case INDEX_op_brcond_i32:
1430be0f34b5SRichard Henderson     case INDEX_op_ld8u_i32:
1431be0f34b5SRichard Henderson     case INDEX_op_ld8s_i32:
1432be0f34b5SRichard Henderson     case INDEX_op_ld16u_i32:
1433be0f34b5SRichard Henderson     case INDEX_op_ld16s_i32:
1434be0f34b5SRichard Henderson     case INDEX_op_ld_i32:
1435be0f34b5SRichard Henderson     case INDEX_op_st8_i32:
1436be0f34b5SRichard Henderson     case INDEX_op_st16_i32:
1437be0f34b5SRichard Henderson     case INDEX_op_st_i32:
1438be0f34b5SRichard Henderson     case INDEX_op_add_i32:
1439be0f34b5SRichard Henderson     case INDEX_op_sub_i32:
1440be0f34b5SRichard Henderson     case INDEX_op_mul_i32:
1441be0f34b5SRichard Henderson     case INDEX_op_and_i32:
1442be0f34b5SRichard Henderson     case INDEX_op_or_i32:
1443be0f34b5SRichard Henderson     case INDEX_op_xor_i32:
1444be0f34b5SRichard Henderson     case INDEX_op_shl_i32:
1445be0f34b5SRichard Henderson     case INDEX_op_shr_i32:
1446be0f34b5SRichard Henderson     case INDEX_op_sar_i32:
1447be0f34b5SRichard Henderson         return true;
1448be0f34b5SRichard Henderson 
1449be0f34b5SRichard Henderson     case INDEX_op_movcond_i32:
1450be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i32;
1451be0f34b5SRichard Henderson     case INDEX_op_div_i32:
1452be0f34b5SRichard Henderson     case INDEX_op_divu_i32:
1453be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i32;
1454be0f34b5SRichard Henderson     case INDEX_op_rem_i32:
1455be0f34b5SRichard Henderson     case INDEX_op_remu_i32:
1456be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i32;
1457be0f34b5SRichard Henderson     case INDEX_op_div2_i32:
1458be0f34b5SRichard Henderson     case INDEX_op_divu2_i32:
1459be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i32;
1460be0f34b5SRichard Henderson     case INDEX_op_rotl_i32:
1461be0f34b5SRichard Henderson     case INDEX_op_rotr_i32:
1462be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i32;
1463be0f34b5SRichard Henderson     case INDEX_op_deposit_i32:
1464be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i32;
1465be0f34b5SRichard Henderson     case INDEX_op_extract_i32:
1466be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i32;
1467be0f34b5SRichard Henderson     case INDEX_op_sextract_i32:
1468be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i32;
1469fce1296fSRichard Henderson     case INDEX_op_extract2_i32:
1470fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i32;
1471be0f34b5SRichard Henderson     case INDEX_op_add2_i32:
1472be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i32;
1473be0f34b5SRichard Henderson     case INDEX_op_sub2_i32:
1474be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i32;
1475be0f34b5SRichard Henderson     case INDEX_op_mulu2_i32:
1476be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i32;
1477be0f34b5SRichard Henderson     case INDEX_op_muls2_i32:
1478be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i32;
1479be0f34b5SRichard Henderson     case INDEX_op_muluh_i32:
1480be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i32;
1481be0f34b5SRichard Henderson     case INDEX_op_mulsh_i32:
1482be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i32;
1483be0f34b5SRichard Henderson     case INDEX_op_ext8s_i32:
1484be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i32;
1485be0f34b5SRichard Henderson     case INDEX_op_ext16s_i32:
1486be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i32;
1487be0f34b5SRichard Henderson     case INDEX_op_ext8u_i32:
1488be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i32;
1489be0f34b5SRichard Henderson     case INDEX_op_ext16u_i32:
1490be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i32;
1491be0f34b5SRichard Henderson     case INDEX_op_bswap16_i32:
1492be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i32;
1493be0f34b5SRichard Henderson     case INDEX_op_bswap32_i32:
1494be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i32;
1495be0f34b5SRichard Henderson     case INDEX_op_not_i32:
1496be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i32;
1497be0f34b5SRichard Henderson     case INDEX_op_neg_i32:
1498be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i32;
1499be0f34b5SRichard Henderson     case INDEX_op_andc_i32:
1500be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i32;
1501be0f34b5SRichard Henderson     case INDEX_op_orc_i32:
1502be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i32;
1503be0f34b5SRichard Henderson     case INDEX_op_eqv_i32:
1504be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i32;
1505be0f34b5SRichard Henderson     case INDEX_op_nand_i32:
1506be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i32;
1507be0f34b5SRichard Henderson     case INDEX_op_nor_i32:
1508be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i32;
1509be0f34b5SRichard Henderson     case INDEX_op_clz_i32:
1510be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i32;
1511be0f34b5SRichard Henderson     case INDEX_op_ctz_i32:
1512be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i32;
1513be0f34b5SRichard Henderson     case INDEX_op_ctpop_i32:
1514be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i32;
1515be0f34b5SRichard Henderson 
1516be0f34b5SRichard Henderson     case INDEX_op_brcond2_i32:
1517be0f34b5SRichard Henderson     case INDEX_op_setcond2_i32:
1518be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 32;
1519be0f34b5SRichard Henderson 
1520be0f34b5SRichard Henderson     case INDEX_op_mov_i64:
1521be0f34b5SRichard Henderson     case INDEX_op_movi_i64:
1522be0f34b5SRichard Henderson     case INDEX_op_setcond_i64:
1523be0f34b5SRichard Henderson     case INDEX_op_brcond_i64:
1524be0f34b5SRichard Henderson     case INDEX_op_ld8u_i64:
1525be0f34b5SRichard Henderson     case INDEX_op_ld8s_i64:
1526be0f34b5SRichard Henderson     case INDEX_op_ld16u_i64:
1527be0f34b5SRichard Henderson     case INDEX_op_ld16s_i64:
1528be0f34b5SRichard Henderson     case INDEX_op_ld32u_i64:
1529be0f34b5SRichard Henderson     case INDEX_op_ld32s_i64:
1530be0f34b5SRichard Henderson     case INDEX_op_ld_i64:
1531be0f34b5SRichard Henderson     case INDEX_op_st8_i64:
1532be0f34b5SRichard Henderson     case INDEX_op_st16_i64:
1533be0f34b5SRichard Henderson     case INDEX_op_st32_i64:
1534be0f34b5SRichard Henderson     case INDEX_op_st_i64:
1535be0f34b5SRichard Henderson     case INDEX_op_add_i64:
1536be0f34b5SRichard Henderson     case INDEX_op_sub_i64:
1537be0f34b5SRichard Henderson     case INDEX_op_mul_i64:
1538be0f34b5SRichard Henderson     case INDEX_op_and_i64:
1539be0f34b5SRichard Henderson     case INDEX_op_or_i64:
1540be0f34b5SRichard Henderson     case INDEX_op_xor_i64:
1541be0f34b5SRichard Henderson     case INDEX_op_shl_i64:
1542be0f34b5SRichard Henderson     case INDEX_op_shr_i64:
1543be0f34b5SRichard Henderson     case INDEX_op_sar_i64:
1544be0f34b5SRichard Henderson     case INDEX_op_ext_i32_i64:
1545be0f34b5SRichard Henderson     case INDEX_op_extu_i32_i64:
1546be0f34b5SRichard Henderson         return TCG_TARGET_REG_BITS == 64;
1547be0f34b5SRichard Henderson 
1548be0f34b5SRichard Henderson     case INDEX_op_movcond_i64:
1549be0f34b5SRichard Henderson         return TCG_TARGET_HAS_movcond_i64;
1550be0f34b5SRichard Henderson     case INDEX_op_div_i64:
1551be0f34b5SRichard Henderson     case INDEX_op_divu_i64:
1552be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div_i64;
1553be0f34b5SRichard Henderson     case INDEX_op_rem_i64:
1554be0f34b5SRichard Henderson     case INDEX_op_remu_i64:
1555be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rem_i64;
1556be0f34b5SRichard Henderson     case INDEX_op_div2_i64:
1557be0f34b5SRichard Henderson     case INDEX_op_divu2_i64:
1558be0f34b5SRichard Henderson         return TCG_TARGET_HAS_div2_i64;
1559be0f34b5SRichard Henderson     case INDEX_op_rotl_i64:
1560be0f34b5SRichard Henderson     case INDEX_op_rotr_i64:
1561be0f34b5SRichard Henderson         return TCG_TARGET_HAS_rot_i64;
1562be0f34b5SRichard Henderson     case INDEX_op_deposit_i64:
1563be0f34b5SRichard Henderson         return TCG_TARGET_HAS_deposit_i64;
1564be0f34b5SRichard Henderson     case INDEX_op_extract_i64:
1565be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extract_i64;
1566be0f34b5SRichard Henderson     case INDEX_op_sextract_i64:
1567be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sextract_i64;
1568fce1296fSRichard Henderson     case INDEX_op_extract2_i64:
1569fce1296fSRichard Henderson         return TCG_TARGET_HAS_extract2_i64;
1570be0f34b5SRichard Henderson     case INDEX_op_extrl_i64_i32:
1571be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrl_i64_i32;
1572be0f34b5SRichard Henderson     case INDEX_op_extrh_i64_i32:
1573be0f34b5SRichard Henderson         return TCG_TARGET_HAS_extrh_i64_i32;
1574be0f34b5SRichard Henderson     case INDEX_op_ext8s_i64:
1575be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8s_i64;
1576be0f34b5SRichard Henderson     case INDEX_op_ext16s_i64:
1577be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16s_i64;
1578be0f34b5SRichard Henderson     case INDEX_op_ext32s_i64:
1579be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32s_i64;
1580be0f34b5SRichard Henderson     case INDEX_op_ext8u_i64:
1581be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext8u_i64;
1582be0f34b5SRichard Henderson     case INDEX_op_ext16u_i64:
1583be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext16u_i64;
1584be0f34b5SRichard Henderson     case INDEX_op_ext32u_i64:
1585be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ext32u_i64;
1586be0f34b5SRichard Henderson     case INDEX_op_bswap16_i64:
1587be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap16_i64;
1588be0f34b5SRichard Henderson     case INDEX_op_bswap32_i64:
1589be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap32_i64;
1590be0f34b5SRichard Henderson     case INDEX_op_bswap64_i64:
1591be0f34b5SRichard Henderson         return TCG_TARGET_HAS_bswap64_i64;
1592be0f34b5SRichard Henderson     case INDEX_op_not_i64:
1593be0f34b5SRichard Henderson         return TCG_TARGET_HAS_not_i64;
1594be0f34b5SRichard Henderson     case INDEX_op_neg_i64:
1595be0f34b5SRichard Henderson         return TCG_TARGET_HAS_neg_i64;
1596be0f34b5SRichard Henderson     case INDEX_op_andc_i64:
1597be0f34b5SRichard Henderson         return TCG_TARGET_HAS_andc_i64;
1598be0f34b5SRichard Henderson     case INDEX_op_orc_i64:
1599be0f34b5SRichard Henderson         return TCG_TARGET_HAS_orc_i64;
1600be0f34b5SRichard Henderson     case INDEX_op_eqv_i64:
1601be0f34b5SRichard Henderson         return TCG_TARGET_HAS_eqv_i64;
1602be0f34b5SRichard Henderson     case INDEX_op_nand_i64:
1603be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nand_i64;
1604be0f34b5SRichard Henderson     case INDEX_op_nor_i64:
1605be0f34b5SRichard Henderson         return TCG_TARGET_HAS_nor_i64;
1606be0f34b5SRichard Henderson     case INDEX_op_clz_i64:
1607be0f34b5SRichard Henderson         return TCG_TARGET_HAS_clz_i64;
1608be0f34b5SRichard Henderson     case INDEX_op_ctz_i64:
1609be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctz_i64;
1610be0f34b5SRichard Henderson     case INDEX_op_ctpop_i64:
1611be0f34b5SRichard Henderson         return TCG_TARGET_HAS_ctpop_i64;
1612be0f34b5SRichard Henderson     case INDEX_op_add2_i64:
1613be0f34b5SRichard Henderson         return TCG_TARGET_HAS_add2_i64;
1614be0f34b5SRichard Henderson     case INDEX_op_sub2_i64:
1615be0f34b5SRichard Henderson         return TCG_TARGET_HAS_sub2_i64;
1616be0f34b5SRichard Henderson     case INDEX_op_mulu2_i64:
1617be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulu2_i64;
1618be0f34b5SRichard Henderson     case INDEX_op_muls2_i64:
1619be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muls2_i64;
1620be0f34b5SRichard Henderson     case INDEX_op_muluh_i64:
1621be0f34b5SRichard Henderson         return TCG_TARGET_HAS_muluh_i64;
1622be0f34b5SRichard Henderson     case INDEX_op_mulsh_i64:
1623be0f34b5SRichard Henderson         return TCG_TARGET_HAS_mulsh_i64;
1624be0f34b5SRichard Henderson 
1625d2fd745fSRichard Henderson     case INDEX_op_mov_vec:
1626d2fd745fSRichard Henderson     case INDEX_op_dup_vec:
1627d2fd745fSRichard Henderson     case INDEX_op_dupi_vec:
162837ee55a0SRichard Henderson     case INDEX_op_dupm_vec:
1629d2fd745fSRichard Henderson     case INDEX_op_ld_vec:
1630d2fd745fSRichard Henderson     case INDEX_op_st_vec:
1631d2fd745fSRichard Henderson     case INDEX_op_add_vec:
1632d2fd745fSRichard Henderson     case INDEX_op_sub_vec:
1633d2fd745fSRichard Henderson     case INDEX_op_and_vec:
1634d2fd745fSRichard Henderson     case INDEX_op_or_vec:
1635d2fd745fSRichard Henderson     case INDEX_op_xor_vec:
1636212be173SRichard Henderson     case INDEX_op_cmp_vec:
1637d2fd745fSRichard Henderson         return have_vec;
1638d2fd745fSRichard Henderson     case INDEX_op_dup2_vec:
1639d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_REG_BITS == 32;
1640d2fd745fSRichard Henderson     case INDEX_op_not_vec:
1641d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_not_vec;
1642d2fd745fSRichard Henderson     case INDEX_op_neg_vec:
1643d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_neg_vec;
1644bcefc902SRichard Henderson     case INDEX_op_abs_vec:
1645bcefc902SRichard Henderson         return have_vec && TCG_TARGET_HAS_abs_vec;
1646d2fd745fSRichard Henderson     case INDEX_op_andc_vec:
1647d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_andc_vec;
1648d2fd745fSRichard Henderson     case INDEX_op_orc_vec:
1649d2fd745fSRichard Henderson         return have_vec && TCG_TARGET_HAS_orc_vec;
16503774030aSRichard Henderson     case INDEX_op_mul_vec:
16513774030aSRichard Henderson         return have_vec && TCG_TARGET_HAS_mul_vec;
1652d0ec9796SRichard Henderson     case INDEX_op_shli_vec:
1653d0ec9796SRichard Henderson     case INDEX_op_shri_vec:
1654d0ec9796SRichard Henderson     case INDEX_op_sari_vec:
1655d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shi_vec;
1656d0ec9796SRichard Henderson     case INDEX_op_shls_vec:
1657d0ec9796SRichard Henderson     case INDEX_op_shrs_vec:
1658d0ec9796SRichard Henderson     case INDEX_op_sars_vec:
1659d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shs_vec;
1660d0ec9796SRichard Henderson     case INDEX_op_shlv_vec:
1661d0ec9796SRichard Henderson     case INDEX_op_shrv_vec:
1662d0ec9796SRichard Henderson     case INDEX_op_sarv_vec:
1663d0ec9796SRichard Henderson         return have_vec && TCG_TARGET_HAS_shv_vec;
16648afaf050SRichard Henderson     case INDEX_op_ssadd_vec:
16658afaf050SRichard Henderson     case INDEX_op_usadd_vec:
16668afaf050SRichard Henderson     case INDEX_op_sssub_vec:
16678afaf050SRichard Henderson     case INDEX_op_ussub_vec:
16688afaf050SRichard Henderson         return have_vec && TCG_TARGET_HAS_sat_vec;
1669dd0a0fcdSRichard Henderson     case INDEX_op_smin_vec:
1670dd0a0fcdSRichard Henderson     case INDEX_op_umin_vec:
1671dd0a0fcdSRichard Henderson     case INDEX_op_smax_vec:
1672dd0a0fcdSRichard Henderson     case INDEX_op_umax_vec:
1673dd0a0fcdSRichard Henderson         return have_vec && TCG_TARGET_HAS_minmax_vec;
167438dc1294SRichard Henderson     case INDEX_op_bitsel_vec:
167538dc1294SRichard Henderson         return have_vec && TCG_TARGET_HAS_bitsel_vec;
1676f75da298SRichard Henderson     case INDEX_op_cmpsel_vec:
1677f75da298SRichard Henderson         return have_vec && TCG_TARGET_HAS_cmpsel_vec;
1678d2fd745fSRichard Henderson 
1679db432672SRichard Henderson     default:
1680db432672SRichard Henderson         tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS);
1681db432672SRichard Henderson         return true;
1682be0f34b5SRichard Henderson     }
1683be0f34b5SRichard Henderson }
1684be0f34b5SRichard Henderson 
168539cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment
168639cf05d3Sbellard    and endian swap. Maybe it would be better to do the alignment
168739cf05d3Sbellard    and endian swap in tcg_reg_alloc_call(). */
1688ae8b75dcSRichard Henderson void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
1689c896fe29Sbellard {
169075e8b9b7SRichard Henderson     int i, real_args, nb_rets, pi;
1691bbb8a1b4SRichard Henderson     unsigned sizemask, flags;
1692afb49896SRichard Henderson     TCGHelperInfo *info;
169375e8b9b7SRichard Henderson     TCGOp *op;
1694afb49896SRichard Henderson 
1695619205fdSEmilio G. Cota     info = g_hash_table_lookup(helper_table, (gpointer)func);
1696bbb8a1b4SRichard Henderson     flags = info->flags;
1697bbb8a1b4SRichard Henderson     sizemask = info->sizemask;
16982bece2c8SRichard Henderson 
1699*38b47b19SEmilio G. Cota #ifdef CONFIG_PLUGIN
1700*38b47b19SEmilio G. Cota     /* detect non-plugin helpers */
1701*38b47b19SEmilio G. Cota     if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) {
1702*38b47b19SEmilio G. Cota         tcg_ctx->plugin_insn->calls_helpers = true;
1703*38b47b19SEmilio G. Cota     }
1704*38b47b19SEmilio G. Cota #endif
1705*38b47b19SEmilio G. Cota 
170634b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
170734b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
170834b1a49cSRichard Henderson     /* We have 64-bit values in one register, but need to pass as two
170934b1a49cSRichard Henderson        separate parameters.  Split them.  */
171034b1a49cSRichard Henderson     int orig_sizemask = sizemask;
171134b1a49cSRichard Henderson     int orig_nargs = nargs;
171234b1a49cSRichard Henderson     TCGv_i64 retl, reth;
1713ae8b75dcSRichard Henderson     TCGTemp *split_args[MAX_OPC_PARAM];
171434b1a49cSRichard Henderson 
1715f764718dSRichard Henderson     retl = NULL;
1716f764718dSRichard Henderson     reth = NULL;
171734b1a49cSRichard Henderson     if (sizemask != 0) {
171834b1a49cSRichard Henderson         for (i = real_args = 0; i < nargs; ++i) {
171934b1a49cSRichard Henderson             int is_64bit = sizemask & (1 << (i+1)*2);
172034b1a49cSRichard Henderson             if (is_64bit) {
1721085272b3SRichard Henderson                 TCGv_i64 orig = temp_tcgv_i64(args[i]);
172234b1a49cSRichard Henderson                 TCGv_i32 h = tcg_temp_new_i32();
172334b1a49cSRichard Henderson                 TCGv_i32 l = tcg_temp_new_i32();
172434b1a49cSRichard Henderson                 tcg_gen_extr_i64_i32(l, h, orig);
1725ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(h);
1726ae8b75dcSRichard Henderson                 split_args[real_args++] = tcgv_i32_temp(l);
172734b1a49cSRichard Henderson             } else {
172834b1a49cSRichard Henderson                 split_args[real_args++] = args[i];
172934b1a49cSRichard Henderson             }
173034b1a49cSRichard Henderson         }
173134b1a49cSRichard Henderson         nargs = real_args;
173234b1a49cSRichard Henderson         args = split_args;
173334b1a49cSRichard Henderson         sizemask = 0;
173434b1a49cSRichard Henderson     }
173534b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
17362bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
17372bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
17382bece2c8SRichard Henderson         int is_signed = sizemask & (2 << (i+1)*2);
17392bece2c8SRichard Henderson         if (!is_64bit) {
17402bece2c8SRichard Henderson             TCGv_i64 temp = tcg_temp_new_i64();
1741085272b3SRichard Henderson             TCGv_i64 orig = temp_tcgv_i64(args[i]);
17422bece2c8SRichard Henderson             if (is_signed) {
17432bece2c8SRichard Henderson                 tcg_gen_ext32s_i64(temp, orig);
17442bece2c8SRichard Henderson             } else {
17452bece2c8SRichard Henderson                 tcg_gen_ext32u_i64(temp, orig);
17462bece2c8SRichard Henderson             }
1747ae8b75dcSRichard Henderson             args[i] = tcgv_i64_temp(temp);
17482bece2c8SRichard Henderson         }
17492bece2c8SRichard Henderson     }
17502bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
17512bece2c8SRichard Henderson 
175215fa08f8SRichard Henderson     op = tcg_emit_op(INDEX_op_call);
175375e8b9b7SRichard Henderson 
175475e8b9b7SRichard Henderson     pi = 0;
1755ae8b75dcSRichard Henderson     if (ret != NULL) {
175634b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
175734b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
175834b1a49cSRichard Henderson         if (orig_sizemask & 1) {
175934b1a49cSRichard Henderson             /* The 32-bit ABI is going to return the 64-bit value in
176034b1a49cSRichard Henderson                the %o0/%o1 register pair.  Prepare for this by using
176134b1a49cSRichard Henderson                two return temporaries, and reassemble below.  */
176234b1a49cSRichard Henderson             retl = tcg_temp_new_i64();
176334b1a49cSRichard Henderson             reth = tcg_temp_new_i64();
1764ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(reth);
1765ae8b75dcSRichard Henderson             op->args[pi++] = tcgv_i64_arg(retl);
176634b1a49cSRichard Henderson             nb_rets = 2;
176734b1a49cSRichard Henderson         } else {
1768ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
176934b1a49cSRichard Henderson             nb_rets = 1;
177034b1a49cSRichard Henderson         }
177134b1a49cSRichard Henderson #else
177234b1a49cSRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) {
177302eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
1774ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1775ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1776a7812ae4Spbrook #else
1777ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1778ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret + 1);
1779a7812ae4Spbrook #endif
1780a7812ae4Spbrook             nb_rets = 2;
178134b1a49cSRichard Henderson         } else {
1782ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(ret);
1783a7812ae4Spbrook             nb_rets = 1;
1784a7812ae4Spbrook         }
178534b1a49cSRichard Henderson #endif
1786a7812ae4Spbrook     } else {
1787a7812ae4Spbrook         nb_rets = 0;
1788a7812ae4Spbrook     }
1789cd9090aaSRichard Henderson     TCGOP_CALLO(op) = nb_rets;
179075e8b9b7SRichard Henderson 
1791a7812ae4Spbrook     real_args = 0;
1792a7812ae4Spbrook     for (i = 0; i < nargs; i++) {
17932bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
1794bbb8a1b4SRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
179539cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS
179639cf05d3Sbellard             /* some targets want aligned 64 bit args */
1797ebd486d5Smalc             if (real_args & 1) {
179875e8b9b7SRichard Henderson                 op->args[pi++] = TCG_CALL_DUMMY_ARG;
1799ebd486d5Smalc                 real_args++;
180039cf05d3Sbellard             }
180139cf05d3Sbellard #endif
18023f90f252SRichard Henderson            /* If stack grows up, then we will be placing successive
18033f90f252SRichard Henderson               arguments at lower addresses, which means we need to
18043f90f252SRichard Henderson               reverse the order compared to how we would normally
18053f90f252SRichard Henderson               treat either big or little-endian.  For those arguments
18063f90f252SRichard Henderson               that will wind up in registers, this still works for
18073f90f252SRichard Henderson               HPPA (the only current STACK_GROWSUP target) since the
18083f90f252SRichard Henderson               argument registers are *also* allocated in decreasing
18093f90f252SRichard Henderson               order.  If another such target is added, this logic may
18103f90f252SRichard Henderson               have to get more complicated to differentiate between
18113f90f252SRichard Henderson               stack arguments and register arguments.  */
181202eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
1813ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1814ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1815c896fe29Sbellard #else
1816ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i]);
1817ae8b75dcSRichard Henderson             op->args[pi++] = temp_arg(args[i] + 1);
1818c896fe29Sbellard #endif
1819a7812ae4Spbrook             real_args += 2;
18202bece2c8SRichard Henderson             continue;
18212bece2c8SRichard Henderson         }
18222bece2c8SRichard Henderson 
1823ae8b75dcSRichard Henderson         op->args[pi++] = temp_arg(args[i]);
1824a7812ae4Spbrook         real_args++;
1825c896fe29Sbellard     }
182675e8b9b7SRichard Henderson     op->args[pi++] = (uintptr_t)func;
182775e8b9b7SRichard Henderson     op->args[pi++] = flags;
1828cd9090aaSRichard Henderson     TCGOP_CALLI(op) = real_args;
1829a7812ae4Spbrook 
183075e8b9b7SRichard Henderson     /* Make sure the fields didn't overflow.  */
1831cd9090aaSRichard Henderson     tcg_debug_assert(TCGOP_CALLI(op) == real_args);
183275e8b9b7SRichard Henderson     tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
18332bece2c8SRichard Henderson 
183434b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
183534b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
183634b1a49cSRichard Henderson     /* Free all of the parts we allocated above.  */
183734b1a49cSRichard Henderson     for (i = real_args = 0; i < orig_nargs; ++i) {
183834b1a49cSRichard Henderson         int is_64bit = orig_sizemask & (1 << (i+1)*2);
183934b1a49cSRichard Henderson         if (is_64bit) {
1840085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
1841085272b3SRichard Henderson             tcg_temp_free_internal(args[real_args++]);
184234b1a49cSRichard Henderson         } else {
184334b1a49cSRichard Henderson             real_args++;
184434b1a49cSRichard Henderson         }
184534b1a49cSRichard Henderson     }
184634b1a49cSRichard Henderson     if (orig_sizemask & 1) {
184734b1a49cSRichard Henderson         /* The 32-bit ABI returned two 32-bit pieces.  Re-assemble them.
184834b1a49cSRichard Henderson            Note that describing these as TCGv_i64 eliminates an unnecessary
184934b1a49cSRichard Henderson            zero-extension that tcg_gen_concat_i32_i64 would create.  */
1850085272b3SRichard Henderson         tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth);
185134b1a49cSRichard Henderson         tcg_temp_free_i64(retl);
185234b1a49cSRichard Henderson         tcg_temp_free_i64(reth);
185334b1a49cSRichard Henderson     }
185434b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
18552bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
18562bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
18572bece2c8SRichard Henderson         if (!is_64bit) {
1858085272b3SRichard Henderson             tcg_temp_free_internal(args[i]);
18592bece2c8SRichard Henderson         }
18602bece2c8SRichard Henderson     }
18612bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
1862a7812ae4Spbrook }
1863c896fe29Sbellard 
18648fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
1865c896fe29Sbellard {
1866ac3b8891SRichard Henderson     int i, n;
1867c896fe29Sbellard     TCGTemp *ts;
1868ac3b8891SRichard Henderson 
1869ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
1870c896fe29Sbellard         ts = &s->temps[i];
1871ac3b8891SRichard Henderson         ts->val_type = (ts->fixed_reg ? TEMP_VAL_REG : TEMP_VAL_MEM);
1872c896fe29Sbellard     }
1873ac3b8891SRichard Henderson     for (n = s->nb_temps; i < n; i++) {
1874e8996ee0Sbellard         ts = &s->temps[i];
1875ac3b8891SRichard Henderson         ts->val_type = (ts->temp_local ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
1876e8996ee0Sbellard         ts->mem_allocated = 0;
1877e8996ee0Sbellard         ts->fixed_reg = 0;
1878e8996ee0Sbellard     }
1879f8b2f202SRichard Henderson 
1880f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
1881c896fe29Sbellard }
1882c896fe29Sbellard 
1883f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
1884f8b2f202SRichard Henderson                                  TCGTemp *ts)
1885c896fe29Sbellard {
18861807f4c4SRichard Henderson     int idx = temp_idx(ts);
1887ac56dd48Spbrook 
1888fa477d25SRichard Henderson     if (ts->temp_global) {
1889ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
1890f8b2f202SRichard Henderson     } else if (ts->temp_local) {
1891641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
1892f8b2f202SRichard Henderson     } else {
1893ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
1894c896fe29Sbellard     }
1895c896fe29Sbellard     return buf;
1896c896fe29Sbellard }
1897c896fe29Sbellard 
189843439139SRichard Henderson static char *tcg_get_arg_str(TCGContext *s, char *buf,
189943439139SRichard Henderson                              int buf_size, TCGArg arg)
1900f8b2f202SRichard Henderson {
190143439139SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg));
1902f8b2f202SRichard Henderson }
1903f8b2f202SRichard Henderson 
19046e085f72SRichard Henderson /* Find helper name.  */
19056e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val)
1906e8996ee0Sbellard {
19076e085f72SRichard Henderson     const char *ret = NULL;
1908619205fdSEmilio G. Cota     if (helper_table) {
1909619205fdSEmilio G. Cota         TCGHelperInfo *info = g_hash_table_lookup(helper_table, (gpointer)val);
191072866e82SRichard Henderson         if (info) {
191172866e82SRichard Henderson             ret = info->name;
191272866e82SRichard Henderson         }
1913e8996ee0Sbellard     }
19146e085f72SRichard Henderson     return ret;
19154dc81f28Sbellard }
19164dc81f28Sbellard 
1917f48f3edeSblueswir1 static const char * const cond_name[] =
1918f48f3edeSblueswir1 {
19190aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
19200aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
1921f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
1922f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
1923f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
1924f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
1925f48f3edeSblueswir1     [TCG_COND_LE] = "le",
1926f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
1927f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
1928f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
1929f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
1930f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
1931f48f3edeSblueswir1 };
1932f48f3edeSblueswir1 
1933f713d6adSRichard Henderson static const char * const ldst_name[] =
1934f713d6adSRichard Henderson {
1935f713d6adSRichard Henderson     [MO_UB]   = "ub",
1936f713d6adSRichard Henderson     [MO_SB]   = "sb",
1937f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
1938f713d6adSRichard Henderson     [MO_LESW] = "lesw",
1939f713d6adSRichard Henderson     [MO_LEUL] = "leul",
1940f713d6adSRichard Henderson     [MO_LESL] = "lesl",
1941f713d6adSRichard Henderson     [MO_LEQ]  = "leq",
1942f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
1943f713d6adSRichard Henderson     [MO_BESW] = "besw",
1944f713d6adSRichard Henderson     [MO_BEUL] = "beul",
1945f713d6adSRichard Henderson     [MO_BESL] = "besl",
1946f713d6adSRichard Henderson     [MO_BEQ]  = "beq",
1947f713d6adSRichard Henderson };
1948f713d6adSRichard Henderson 
19491f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
195052bf9771Stony.nguyen@bt.com #ifdef TARGET_ALIGNED_ONLY
19511f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
19521f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
19531f00b27fSSergey Sorokin #else
19541f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
19551f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
19561f00b27fSSergey Sorokin #endif
19571f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
19581f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
19591f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
19601f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
19611f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
19621f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
19631f00b27fSSergey Sorokin };
19641f00b27fSSergey Sorokin 
1965b016486eSRichard Henderson static inline bool tcg_regset_single(TCGRegSet d)
1966b016486eSRichard Henderson {
1967b016486eSRichard Henderson     return (d & (d - 1)) == 0;
1968b016486eSRichard Henderson }
1969b016486eSRichard Henderson 
1970b016486eSRichard Henderson static inline TCGReg tcg_regset_first(TCGRegSet d)
1971b016486eSRichard Henderson {
1972b016486eSRichard Henderson     if (TCG_TARGET_NB_REGS <= 32) {
1973b016486eSRichard Henderson         return ctz32(d);
1974b016486eSRichard Henderson     } else {
1975b016486eSRichard Henderson         return ctz64(d);
1976b016486eSRichard Henderson     }
1977b016486eSRichard Henderson }
1978b016486eSRichard Henderson 
19791894f69aSRichard Henderson static void tcg_dump_ops(TCGContext *s, bool have_prefs)
1980c896fe29Sbellard {
1981c896fe29Sbellard     char buf[128];
1982c45cb8bbSRichard Henderson     TCGOp *op;
1983c896fe29Sbellard 
198415fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
1985c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
1986c45cb8bbSRichard Henderson         const TCGOpDef *def;
1987c45cb8bbSRichard Henderson         TCGOpcode c;
1988bdfb460eSRichard Henderson         int col = 0;
1989c45cb8bbSRichard Henderson 
1990c45cb8bbSRichard Henderson         c = op->opc;
1991c896fe29Sbellard         def = &tcg_op_defs[c];
1992c45cb8bbSRichard Henderson 
1993765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
1994b016486eSRichard Henderson             nb_oargs = 0;
199515fa08f8SRichard Henderson             col += qemu_log("\n ----");
19969aef40edSRichard Henderson 
19979aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
19989aef40edSRichard Henderson                 target_ulong a;
19997e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
2000efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
20017e4597d7Sbellard #else
2002efee3746SRichard Henderson                 a = op->args[i];
20037e4597d7Sbellard #endif
2004bdfb460eSRichard Henderson                 col += qemu_log(" " TARGET_FMT_lx, a);
2005eeacee4dSBlue Swirl             }
20067e4597d7Sbellard         } else if (c == INDEX_op_call) {
2007c896fe29Sbellard             /* variable number of arguments */
2008cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2009cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2010c896fe29Sbellard             nb_cargs = def->nb_cargs;
2011b03cce8eSbellard 
2012cf066674SRichard Henderson             /* function name, flags, out args */
2013bdfb460eSRichard Henderson             col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name,
2014efee3746SRichard Henderson                             tcg_find_helper(s, op->args[nb_oargs + nb_iargs]),
2015efee3746SRichard Henderson                             op->args[nb_oargs + nb_iargs + 1], nb_oargs);
2016b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
201743439139SRichard Henderson                 col += qemu_log(",%s", tcg_get_arg_str(s, buf, sizeof(buf),
2018efee3746SRichard Henderson                                                        op->args[i]));
2019b03cce8eSbellard             }
2020cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
2021efee3746SRichard Henderson                 TCGArg arg = op->args[nb_oargs + i];
2022cf066674SRichard Henderson                 const char *t = "<dummy>";
2023cf066674SRichard Henderson                 if (arg != TCG_CALL_DUMMY_ARG) {
202443439139SRichard Henderson                     t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
2025b03cce8eSbellard                 }
2026bdfb460eSRichard Henderson                 col += qemu_log(",%s", t);
2027e8996ee0Sbellard             }
2028b03cce8eSbellard         } else {
2029bdfb460eSRichard Henderson             col += qemu_log(" %s ", def->name);
2030c45cb8bbSRichard Henderson 
2031c896fe29Sbellard             nb_oargs = def->nb_oargs;
2032c896fe29Sbellard             nb_iargs = def->nb_iargs;
2033c896fe29Sbellard             nb_cargs = def->nb_cargs;
2034c896fe29Sbellard 
2035d2fd745fSRichard Henderson             if (def->flags & TCG_OPF_VECTOR) {
2036d2fd745fSRichard Henderson                 col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op),
2037d2fd745fSRichard Henderson                                 8 << TCGOP_VECE(op));
2038d2fd745fSRichard Henderson             }
2039d2fd745fSRichard Henderson 
2040c896fe29Sbellard             k = 0;
2041c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
2042eeacee4dSBlue Swirl                 if (k != 0) {
2043bdfb460eSRichard Henderson                     col += qemu_log(",");
2044eeacee4dSBlue Swirl                 }
204543439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2046efee3746SRichard Henderson                                                       op->args[k++]));
2047c896fe29Sbellard             }
2048c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
2049eeacee4dSBlue Swirl                 if (k != 0) {
2050bdfb460eSRichard Henderson                     col += qemu_log(",");
2051eeacee4dSBlue Swirl                 }
205243439139SRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str(s, buf, sizeof(buf),
2053efee3746SRichard Henderson                                                       op->args[k++]));
2054c896fe29Sbellard             }
2055be210acbSRichard Henderson             switch (c) {
2056be210acbSRichard Henderson             case INDEX_op_brcond_i32:
2057ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
2058ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
2059be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
2060be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
2061ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
2062be210acbSRichard Henderson             case INDEX_op_setcond_i64:
2063ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
2064212be173SRichard Henderson             case INDEX_op_cmp_vec:
2065f75da298SRichard Henderson             case INDEX_op_cmpsel_vec:
2066efee3746SRichard Henderson                 if (op->args[k] < ARRAY_SIZE(cond_name)
2067efee3746SRichard Henderson                     && cond_name[op->args[k]]) {
2068efee3746SRichard Henderson                     col += qemu_log(",%s", cond_name[op->args[k++]]);
2069eeacee4dSBlue Swirl                 } else {
2070efee3746SRichard Henderson                     col += qemu_log(",$0x%" TCG_PRIlx, op->args[k++]);
2071eeacee4dSBlue Swirl                 }
2072f48f3edeSblueswir1                 i = 1;
2073be210acbSRichard Henderson                 break;
2074f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
2075f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
2076f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
2077f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
207859227d5dSRichard Henderson                 {
2079efee3746SRichard Henderson                     TCGMemOpIdx oi = op->args[k++];
208014776ab5STony Nguyen                     MemOp op = get_memop(oi);
208159227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
208259227d5dSRichard Henderson 
208359c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
2084bdfb460eSRichard Henderson                         col += qemu_log(",$0x%x,%u", op, ix);
208559c4b7e8SRichard Henderson                     } else {
20861f00b27fSSergey Sorokin                         const char *s_al, *s_op;
20871f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
208859c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
2089bdfb460eSRichard Henderson                         col += qemu_log(",%s%s,%u", s_al, s_op, ix);
2090f713d6adSRichard Henderson                     }
2091f713d6adSRichard Henderson                     i = 1;
209259227d5dSRichard Henderson                 }
2093f713d6adSRichard Henderson                 break;
2094be210acbSRichard Henderson             default:
2095f48f3edeSblueswir1                 i = 0;
2096be210acbSRichard Henderson                 break;
2097be210acbSRichard Henderson             }
209851e3972cSRichard Henderson             switch (c) {
209951e3972cSRichard Henderson             case INDEX_op_set_label:
210051e3972cSRichard Henderson             case INDEX_op_br:
210151e3972cSRichard Henderson             case INDEX_op_brcond_i32:
210251e3972cSRichard Henderson             case INDEX_op_brcond_i64:
210351e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
2104efee3746SRichard Henderson                 col += qemu_log("%s$L%d", k ? "," : "",
2105efee3746SRichard Henderson                                 arg_label(op->args[k])->id);
210651e3972cSRichard Henderson                 i++, k++;
210751e3972cSRichard Henderson                 break;
210851e3972cSRichard Henderson             default:
210951e3972cSRichard Henderson                 break;
2110eeacee4dSBlue Swirl             }
211151e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
2112efee3746SRichard Henderson                 col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]);
2113bdfb460eSRichard Henderson             }
2114bdfb460eSRichard Henderson         }
2115bdfb460eSRichard Henderson 
21161894f69aSRichard Henderson         if (have_prefs || op->life) {
21171894f69aSRichard Henderson             for (; col < 40; ++col) {
2118bdfb460eSRichard Henderson                 putc(' ', qemu_logfile);
2119bdfb460eSRichard Henderson             }
21201894f69aSRichard Henderson         }
21211894f69aSRichard Henderson 
21221894f69aSRichard Henderson         if (op->life) {
21231894f69aSRichard Henderson             unsigned life = op->life;
2124bdfb460eSRichard Henderson 
2125bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
2126bdfb460eSRichard Henderson                 qemu_log("  sync:");
2127bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
2128bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
2129bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2130bdfb460eSRichard Henderson                     }
2131bdfb460eSRichard Henderson                 }
2132bdfb460eSRichard Henderson             }
2133bdfb460eSRichard Henderson             life /= DEAD_ARG;
2134bdfb460eSRichard Henderson             if (life) {
2135bdfb460eSRichard Henderson                 qemu_log("  dead:");
2136bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
2137bdfb460eSRichard Henderson                     if (life & 1) {
2138bdfb460eSRichard Henderson                         qemu_log(" %d", i);
2139bdfb460eSRichard Henderson                     }
2140bdfb460eSRichard Henderson                 }
2141c896fe29Sbellard             }
2142b03cce8eSbellard         }
21431894f69aSRichard Henderson 
21441894f69aSRichard Henderson         if (have_prefs) {
21451894f69aSRichard Henderson             for (i = 0; i < nb_oargs; ++i) {
21461894f69aSRichard Henderson                 TCGRegSet set = op->output_pref[i];
21471894f69aSRichard Henderson 
21481894f69aSRichard Henderson                 if (i == 0) {
21491894f69aSRichard Henderson                     qemu_log("  pref=");
21501894f69aSRichard Henderson                 } else {
21511894f69aSRichard Henderson                     qemu_log(",");
21521894f69aSRichard Henderson                 }
21531894f69aSRichard Henderson                 if (set == 0) {
21541894f69aSRichard Henderson                     qemu_log("none");
21551894f69aSRichard Henderson                 } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
21561894f69aSRichard Henderson                     qemu_log("all");
21571894f69aSRichard Henderson #ifdef CONFIG_DEBUG_TCG
21581894f69aSRichard Henderson                 } else if (tcg_regset_single(set)) {
21591894f69aSRichard Henderson                     TCGReg reg = tcg_regset_first(set);
21601894f69aSRichard Henderson                     qemu_log("%s", tcg_target_reg_names[reg]);
21611894f69aSRichard Henderson #endif
21621894f69aSRichard Henderson                 } else if (TCG_TARGET_NB_REGS <= 32) {
21631894f69aSRichard Henderson                     qemu_log("%#x", (uint32_t)set);
21641894f69aSRichard Henderson                 } else {
21651894f69aSRichard Henderson                     qemu_log("%#" PRIx64, (uint64_t)set);
21661894f69aSRichard Henderson                 }
21671894f69aSRichard Henderson             }
21681894f69aSRichard Henderson         }
21691894f69aSRichard Henderson 
2170eeacee4dSBlue Swirl         qemu_log("\n");
2171c896fe29Sbellard     }
2172c896fe29Sbellard }
2173c896fe29Sbellard 
2174c896fe29Sbellard /* we give more priority to constraints with less registers */
2175c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
2176c896fe29Sbellard {
2177c896fe29Sbellard     const TCGArgConstraint *arg_ct;
2178c896fe29Sbellard 
2179c896fe29Sbellard     int i, n;
2180c896fe29Sbellard     arg_ct = &def->args_ct[k];
2181c896fe29Sbellard     if (arg_ct->ct & TCG_CT_ALIAS) {
2182c896fe29Sbellard         /* an alias is equivalent to a single register */
2183c896fe29Sbellard         n = 1;
2184c896fe29Sbellard     } else {
2185c896fe29Sbellard         if (!(arg_ct->ct & TCG_CT_REG))
2186c896fe29Sbellard             return 0;
2187c896fe29Sbellard         n = 0;
2188c896fe29Sbellard         for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
2189c896fe29Sbellard             if (tcg_regset_test_reg(arg_ct->u.regs, i))
2190c896fe29Sbellard                 n++;
2191c896fe29Sbellard         }
2192c896fe29Sbellard     }
2193c896fe29Sbellard     return TCG_TARGET_NB_REGS - n + 1;
2194c896fe29Sbellard }
2195c896fe29Sbellard 
2196c896fe29Sbellard /* sort from highest priority to lowest */
2197c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
2198c896fe29Sbellard {
2199c896fe29Sbellard     int i, j, p1, p2, tmp;
2200c896fe29Sbellard 
2201c896fe29Sbellard     for(i = 0; i < n; i++)
2202c896fe29Sbellard         def->sorted_args[start + i] = start + i;
2203c896fe29Sbellard     if (n <= 1)
2204c896fe29Sbellard         return;
2205c896fe29Sbellard     for(i = 0; i < n - 1; i++) {
2206c896fe29Sbellard         for(j = i + 1; j < n; j++) {
2207c896fe29Sbellard             p1 = get_constraint_priority(def, def->sorted_args[start + i]);
2208c896fe29Sbellard             p2 = get_constraint_priority(def, def->sorted_args[start + j]);
2209c896fe29Sbellard             if (p1 < p2) {
2210c896fe29Sbellard                 tmp = def->sorted_args[start + i];
2211c896fe29Sbellard                 def->sorted_args[start + i] = def->sorted_args[start + j];
2212c896fe29Sbellard                 def->sorted_args[start + j] = tmp;
2213c896fe29Sbellard             }
2214c896fe29Sbellard         }
2215c896fe29Sbellard     }
2216c896fe29Sbellard }
2217c896fe29Sbellard 
2218f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
2219c896fe29Sbellard {
2220a9751609SRichard Henderson     TCGOpcode op;
2221c896fe29Sbellard 
2222f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
2223f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
2224f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
2225069ea736SRichard Henderson         TCGType type;
2226069ea736SRichard Henderson         int i, nb_args;
2227f69d277eSRichard Henderson 
2228f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
2229f69d277eSRichard Henderson             continue;
2230f69d277eSRichard Henderson         }
2231f69d277eSRichard Henderson 
2232c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
2233f69d277eSRichard Henderson         if (nb_args == 0) {
2234f69d277eSRichard Henderson             continue;
2235f69d277eSRichard Henderson         }
2236f69d277eSRichard Henderson 
2237f69d277eSRichard Henderson         tdefs = tcg_target_op_def(op);
2238f69d277eSRichard Henderson         /* Missing TCGTargetOpDef entry. */
2239f69d277eSRichard Henderson         tcg_debug_assert(tdefs != NULL);
2240f69d277eSRichard Henderson 
2241069ea736SRichard Henderson         type = (def->flags & TCG_OPF_64BIT ? TCG_TYPE_I64 : TCG_TYPE_I32);
2242c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
2243f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
2244f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
2245eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
2246f69d277eSRichard Henderson 
2247ccb1bb66SRichard Henderson             def->args_ct[i].u.regs = 0;
2248c896fe29Sbellard             def->args_ct[i].ct = 0;
224917280ff4SRichard Henderson             while (*ct_str != '\0') {
225017280ff4SRichard Henderson                 switch(*ct_str) {
225117280ff4SRichard Henderson                 case '0' ... '9':
225217280ff4SRichard Henderson                     {
225317280ff4SRichard Henderson                         int oarg = *ct_str - '0';
225417280ff4SRichard Henderson                         tcg_debug_assert(ct_str == tdefs->args_ct_str[i]);
2255eabb7b91SAurelien Jarno                         tcg_debug_assert(oarg < def->nb_oargs);
2256eabb7b91SAurelien Jarno                         tcg_debug_assert(def->args_ct[oarg].ct & TCG_CT_REG);
225717280ff4SRichard Henderson                         /* TCG_CT_ALIAS is for the output arguments.
225817280ff4SRichard Henderson                            The input is tagged with TCG_CT_IALIAS. */
2259c896fe29Sbellard                         def->args_ct[i] = def->args_ct[oarg];
226017280ff4SRichard Henderson                         def->args_ct[oarg].ct |= TCG_CT_ALIAS;
22615ff9d6a4Sbellard                         def->args_ct[oarg].alias_index = i;
2262c896fe29Sbellard                         def->args_ct[i].ct |= TCG_CT_IALIAS;
22635ff9d6a4Sbellard                         def->args_ct[i].alias_index = oarg;
226417280ff4SRichard Henderson                     }
226517280ff4SRichard Henderson                     ct_str++;
2266c896fe29Sbellard                     break;
226782790a87SRichard Henderson                 case '&':
226882790a87SRichard Henderson                     def->args_ct[i].ct |= TCG_CT_NEWREG;
226982790a87SRichard Henderson                     ct_str++;
227082790a87SRichard Henderson                     break;
2271c896fe29Sbellard                 case 'i':
2272c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
2273c896fe29Sbellard                     ct_str++;
2274c896fe29Sbellard                     break;
2275c896fe29Sbellard                 default:
2276069ea736SRichard Henderson                     ct_str = target_parse_constraint(&def->args_ct[i],
2277069ea736SRichard Henderson                                                      ct_str, type);
2278f69d277eSRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
2279069ea736SRichard Henderson                     tcg_debug_assert(ct_str != NULL);
2280c896fe29Sbellard                 }
2281c896fe29Sbellard             }
2282c896fe29Sbellard         }
2283c896fe29Sbellard 
2284c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
2285eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
2286c68aaa18SStefan Weil 
2287c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
2288c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
2289c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
2290c896fe29Sbellard     }
2291c896fe29Sbellard }
2292c896fe29Sbellard 
22930c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
22940c627cdcSRichard Henderson {
2295d88a117eSRichard Henderson     TCGLabel *label;
2296d88a117eSRichard Henderson 
2297d88a117eSRichard Henderson     switch (op->opc) {
2298d88a117eSRichard Henderson     case INDEX_op_br:
2299d88a117eSRichard Henderson         label = arg_label(op->args[0]);
2300d88a117eSRichard Henderson         label->refs--;
2301d88a117eSRichard Henderson         break;
2302d88a117eSRichard Henderson     case INDEX_op_brcond_i32:
2303d88a117eSRichard Henderson     case INDEX_op_brcond_i64:
2304d88a117eSRichard Henderson         label = arg_label(op->args[3]);
2305d88a117eSRichard Henderson         label->refs--;
2306d88a117eSRichard Henderson         break;
2307d88a117eSRichard Henderson     case INDEX_op_brcond2_i32:
2308d88a117eSRichard Henderson         label = arg_label(op->args[5]);
2309d88a117eSRichard Henderson         label->refs--;
2310d88a117eSRichard Henderson         break;
2311d88a117eSRichard Henderson     default:
2312d88a117eSRichard Henderson         break;
2313d88a117eSRichard Henderson     }
2314d88a117eSRichard Henderson 
231515fa08f8SRichard Henderson     QTAILQ_REMOVE(&s->ops, op, link);
231615fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
2317abebf925SRichard Henderson     s->nb_ops--;
23180c627cdcSRichard Henderson 
23190c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
2320c3fac113SEmilio G. Cota     atomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
23210c627cdcSRichard Henderson #endif
23220c627cdcSRichard Henderson }
23230c627cdcSRichard Henderson 
232415fa08f8SRichard Henderson static TCGOp *tcg_op_alloc(TCGOpcode opc)
232515fa08f8SRichard Henderson {
232615fa08f8SRichard Henderson     TCGContext *s = tcg_ctx;
232715fa08f8SRichard Henderson     TCGOp *op;
232815fa08f8SRichard Henderson 
232915fa08f8SRichard Henderson     if (likely(QTAILQ_EMPTY(&s->free_ops))) {
233015fa08f8SRichard Henderson         op = tcg_malloc(sizeof(TCGOp));
233115fa08f8SRichard Henderson     } else {
233215fa08f8SRichard Henderson         op = QTAILQ_FIRST(&s->free_ops);
233315fa08f8SRichard Henderson         QTAILQ_REMOVE(&s->free_ops, op, link);
233415fa08f8SRichard Henderson     }
233515fa08f8SRichard Henderson     memset(op, 0, offsetof(TCGOp, link));
233615fa08f8SRichard Henderson     op->opc = opc;
2337abebf925SRichard Henderson     s->nb_ops++;
233815fa08f8SRichard Henderson 
233915fa08f8SRichard Henderson     return op;
234015fa08f8SRichard Henderson }
234115fa08f8SRichard Henderson 
234215fa08f8SRichard Henderson TCGOp *tcg_emit_op(TCGOpcode opc)
234315fa08f8SRichard Henderson {
234415fa08f8SRichard Henderson     TCGOp *op = tcg_op_alloc(opc);
234515fa08f8SRichard Henderson     QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
234615fa08f8SRichard Henderson     return op;
234715fa08f8SRichard Henderson }
234815fa08f8SRichard Henderson 
2349ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
23505a18407fSRichard Henderson {
235115fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
235215fa08f8SRichard Henderson     QTAILQ_INSERT_BEFORE(old_op, new_op, link);
23535a18407fSRichard Henderson     return new_op;
23545a18407fSRichard Henderson }
23555a18407fSRichard Henderson 
2356ac1043f6SEmilio G. Cota TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
23575a18407fSRichard Henderson {
235815fa08f8SRichard Henderson     TCGOp *new_op = tcg_op_alloc(opc);
235915fa08f8SRichard Henderson     QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
23605a18407fSRichard Henderson     return new_op;
23615a18407fSRichard Henderson }
23625a18407fSRichard Henderson 
2363b4fc67c7SRichard Henderson /* Reachable analysis : remove unreachable code.  */
2364b4fc67c7SRichard Henderson static void reachable_code_pass(TCGContext *s)
2365b4fc67c7SRichard Henderson {
2366b4fc67c7SRichard Henderson     TCGOp *op, *op_next;
2367b4fc67c7SRichard Henderson     bool dead = false;
2368b4fc67c7SRichard Henderson 
2369b4fc67c7SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
2370b4fc67c7SRichard Henderson         bool remove = dead;
2371b4fc67c7SRichard Henderson         TCGLabel *label;
2372b4fc67c7SRichard Henderson         int call_flags;
2373b4fc67c7SRichard Henderson 
2374b4fc67c7SRichard Henderson         switch (op->opc) {
2375b4fc67c7SRichard Henderson         case INDEX_op_set_label:
2376b4fc67c7SRichard Henderson             label = arg_label(op->args[0]);
2377b4fc67c7SRichard Henderson             if (label->refs == 0) {
2378b4fc67c7SRichard Henderson                 /*
2379b4fc67c7SRichard Henderson                  * While there is an occasional backward branch, virtually
2380b4fc67c7SRichard Henderson                  * all branches generated by the translators are forward.
2381b4fc67c7SRichard Henderson                  * Which means that generally we will have already removed
2382b4fc67c7SRichard Henderson                  * all references to the label that will be, and there is
2383b4fc67c7SRichard Henderson                  * little to be gained by iterating.
2384b4fc67c7SRichard Henderson                  */
2385b4fc67c7SRichard Henderson                 remove = true;
2386b4fc67c7SRichard Henderson             } else {
2387b4fc67c7SRichard Henderson                 /* Once we see a label, insns become live again.  */
2388b4fc67c7SRichard Henderson                 dead = false;
2389b4fc67c7SRichard Henderson                 remove = false;
2390b4fc67c7SRichard Henderson 
2391b4fc67c7SRichard Henderson                 /*
2392b4fc67c7SRichard Henderson                  * Optimization can fold conditional branches to unconditional.
2393b4fc67c7SRichard Henderson                  * If we find a label with one reference which is preceded by
2394b4fc67c7SRichard Henderson                  * an unconditional branch to it, remove both.  This needed to
2395b4fc67c7SRichard Henderson                  * wait until the dead code in between them was removed.
2396b4fc67c7SRichard Henderson                  */
2397b4fc67c7SRichard Henderson                 if (label->refs == 1) {
2398eae3eb3eSPaolo Bonzini                     TCGOp *op_prev = QTAILQ_PREV(op, link);
2399b4fc67c7SRichard Henderson                     if (op_prev->opc == INDEX_op_br &&
2400b4fc67c7SRichard Henderson                         label == arg_label(op_prev->args[0])) {
2401b4fc67c7SRichard Henderson                         tcg_op_remove(s, op_prev);
2402b4fc67c7SRichard Henderson                         remove = true;
2403b4fc67c7SRichard Henderson                     }
2404b4fc67c7SRichard Henderson                 }
2405b4fc67c7SRichard Henderson             }
2406b4fc67c7SRichard Henderson             break;
2407b4fc67c7SRichard Henderson 
2408b4fc67c7SRichard Henderson         case INDEX_op_br:
2409b4fc67c7SRichard Henderson         case INDEX_op_exit_tb:
2410b4fc67c7SRichard Henderson         case INDEX_op_goto_ptr:
2411b4fc67c7SRichard Henderson             /* Unconditional branches; everything following is dead.  */
2412b4fc67c7SRichard Henderson             dead = true;
2413b4fc67c7SRichard Henderson             break;
2414b4fc67c7SRichard Henderson 
2415b4fc67c7SRichard Henderson         case INDEX_op_call:
2416b4fc67c7SRichard Henderson             /* Notice noreturn helper calls, raising exceptions.  */
2417b4fc67c7SRichard Henderson             call_flags = op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1];
2418b4fc67c7SRichard Henderson             if (call_flags & TCG_CALL_NO_RETURN) {
2419b4fc67c7SRichard Henderson                 dead = true;
2420b4fc67c7SRichard Henderson             }
2421b4fc67c7SRichard Henderson             break;
2422b4fc67c7SRichard Henderson 
2423b4fc67c7SRichard Henderson         case INDEX_op_insn_start:
2424b4fc67c7SRichard Henderson             /* Never remove -- we need to keep these for unwind.  */
2425b4fc67c7SRichard Henderson             remove = false;
2426b4fc67c7SRichard Henderson             break;
2427b4fc67c7SRichard Henderson 
2428b4fc67c7SRichard Henderson         default:
2429b4fc67c7SRichard Henderson             break;
2430b4fc67c7SRichard Henderson         }
2431b4fc67c7SRichard Henderson 
2432b4fc67c7SRichard Henderson         if (remove) {
2433b4fc67c7SRichard Henderson             tcg_op_remove(s, op);
2434b4fc67c7SRichard Henderson         }
2435b4fc67c7SRichard Henderson     }
2436b4fc67c7SRichard Henderson }
2437b4fc67c7SRichard Henderson 
2438c70fbf0aSRichard Henderson #define TS_DEAD  1
2439c70fbf0aSRichard Henderson #define TS_MEM   2
2440c70fbf0aSRichard Henderson 
24415a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
24425a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
24435a18407fSRichard Henderson 
244425f49c5fSRichard Henderson /* For liveness_pass_1, the register preferences for a given temp.  */
244525f49c5fSRichard Henderson static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
244625f49c5fSRichard Henderson {
244725f49c5fSRichard Henderson     return ts->state_ptr;
244825f49c5fSRichard Henderson }
244925f49c5fSRichard Henderson 
245025f49c5fSRichard Henderson /* For liveness_pass_1, reset the preferences for a given temp to the
245125f49c5fSRichard Henderson  * maximal regset for its type.
245225f49c5fSRichard Henderson  */
245325f49c5fSRichard Henderson static inline void la_reset_pref(TCGTemp *ts)
245425f49c5fSRichard Henderson {
245525f49c5fSRichard Henderson     *la_temp_pref(ts)
245625f49c5fSRichard Henderson         = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
245725f49c5fSRichard Henderson }
245825f49c5fSRichard Henderson 
24599c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
24609c43b68dSAurelien Jarno    should be in memory. */
24612616c808SRichard Henderson static void la_func_end(TCGContext *s, int ng, int nt)
2462c896fe29Sbellard {
2463b83eabeaSRichard Henderson     int i;
2464b83eabeaSRichard Henderson 
2465b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2466b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
246725f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2468b83eabeaSRichard Henderson     }
2469b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2470b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD;
247125f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2472b83eabeaSRichard Henderson     }
2473c896fe29Sbellard }
2474c896fe29Sbellard 
24759c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
24769c43b68dSAurelien Jarno    and local temps should be in memory. */
24772616c808SRichard Henderson static void la_bb_end(TCGContext *s, int ng, int nt)
2478641d5fbeSbellard {
2479b83eabeaSRichard Henderson     int i;
2480641d5fbeSbellard 
2481b83eabeaSRichard Henderson     for (i = 0; i < ng; ++i) {
2482b83eabeaSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
248325f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2484c70fbf0aSRichard Henderson     }
2485b83eabeaSRichard Henderson     for (i = ng; i < nt; ++i) {
2486b83eabeaSRichard Henderson         s->temps[i].state = (s->temps[i].temp_local
2487b83eabeaSRichard Henderson                              ? TS_DEAD | TS_MEM
2488b83eabeaSRichard Henderson                              : TS_DEAD);
248925f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
2490641d5fbeSbellard     }
2491641d5fbeSbellard }
2492641d5fbeSbellard 
2493f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory.  */
2494f65a061cSRichard Henderson static void la_global_sync(TCGContext *s, int ng)
2495f65a061cSRichard Henderson {
2496f65a061cSRichard Henderson     int i;
2497f65a061cSRichard Henderson 
2498f65a061cSRichard Henderson     for (i = 0; i < ng; ++i) {
249925f49c5fSRichard Henderson         int state = s->temps[i].state;
250025f49c5fSRichard Henderson         s->temps[i].state = state | TS_MEM;
250125f49c5fSRichard Henderson         if (state == TS_DEAD) {
250225f49c5fSRichard Henderson             /* If the global was previously dead, reset prefs.  */
250325f49c5fSRichard Henderson             la_reset_pref(&s->temps[i]);
250425f49c5fSRichard Henderson         }
2505f65a061cSRichard Henderson     }
2506f65a061cSRichard Henderson }
2507f65a061cSRichard Henderson 
2508f65a061cSRichard Henderson /* liveness analysis: sync globals back to memory and kill.  */
2509f65a061cSRichard Henderson static void la_global_kill(TCGContext *s, int ng)
2510f65a061cSRichard Henderson {
2511f65a061cSRichard Henderson     int i;
2512f65a061cSRichard Henderson 
2513f65a061cSRichard Henderson     for (i = 0; i < ng; i++) {
2514f65a061cSRichard Henderson         s->temps[i].state = TS_DEAD | TS_MEM;
251525f49c5fSRichard Henderson         la_reset_pref(&s->temps[i]);
251625f49c5fSRichard Henderson     }
251725f49c5fSRichard Henderson }
251825f49c5fSRichard Henderson 
251925f49c5fSRichard Henderson /* liveness analysis: note live globals crossing calls.  */
252025f49c5fSRichard Henderson static void la_cross_call(TCGContext *s, int nt)
252125f49c5fSRichard Henderson {
252225f49c5fSRichard Henderson     TCGRegSet mask = ~tcg_target_call_clobber_regs;
252325f49c5fSRichard Henderson     int i;
252425f49c5fSRichard Henderson 
252525f49c5fSRichard Henderson     for (i = 0; i < nt; i++) {
252625f49c5fSRichard Henderson         TCGTemp *ts = &s->temps[i];
252725f49c5fSRichard Henderson         if (!(ts->state & TS_DEAD)) {
252825f49c5fSRichard Henderson             TCGRegSet *pset = la_temp_pref(ts);
252925f49c5fSRichard Henderson             TCGRegSet set = *pset;
253025f49c5fSRichard Henderson 
253125f49c5fSRichard Henderson             set &= mask;
253225f49c5fSRichard Henderson             /* If the combination is not possible, restart.  */
253325f49c5fSRichard Henderson             if (set == 0) {
253425f49c5fSRichard Henderson                 set = tcg_target_available_regs[ts->type] & mask;
253525f49c5fSRichard Henderson             }
253625f49c5fSRichard Henderson             *pset = set;
253725f49c5fSRichard Henderson         }
2538f65a061cSRichard Henderson     }
2539f65a061cSRichard Henderson }
2540f65a061cSRichard Henderson 
2541a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
2542c896fe29Sbellard    given input arguments is dead. Instructions updating dead
2543c896fe29Sbellard    temporaries are removed. */
2544b83eabeaSRichard Henderson static void liveness_pass_1(TCGContext *s)
2545c896fe29Sbellard {
2546c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
25472616c808SRichard Henderson     int nb_temps = s->nb_temps;
254815fa08f8SRichard Henderson     TCGOp *op, *op_prev;
254925f49c5fSRichard Henderson     TCGRegSet *prefs;
255025f49c5fSRichard Henderson     int i;
255125f49c5fSRichard Henderson 
255225f49c5fSRichard Henderson     prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
255325f49c5fSRichard Henderson     for (i = 0; i < nb_temps; ++i) {
255425f49c5fSRichard Henderson         s->temps[i].state_ptr = prefs + i;
255525f49c5fSRichard Henderson     }
2556c896fe29Sbellard 
2557ae36a246SRichard Henderson     /* ??? Should be redundant with the exit_tb that ends the TB.  */
25582616c808SRichard Henderson     la_func_end(s, nb_globals, nb_temps);
2559c896fe29Sbellard 
2560eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
256125f49c5fSRichard Henderson         int nb_iargs, nb_oargs;
2562c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
2563c45cb8bbSRichard Henderson         bool have_opc_new2;
2564a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
256525f49c5fSRichard Henderson         TCGTemp *ts;
2566c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2567c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2568c45cb8bbSRichard Henderson 
2569c45cb8bbSRichard Henderson         switch (opc) {
2570c896fe29Sbellard         case INDEX_op_call:
2571c6e113f5Sbellard             {
2572c6e113f5Sbellard                 int call_flags;
257325f49c5fSRichard Henderson                 int nb_call_regs;
2574c6e113f5Sbellard 
2575cd9090aaSRichard Henderson                 nb_oargs = TCGOP_CALLO(op);
2576cd9090aaSRichard Henderson                 nb_iargs = TCGOP_CALLI(op);
2577efee3746SRichard Henderson                 call_flags = op->args[nb_oargs + nb_iargs + 1];
2578c6e113f5Sbellard 
2579c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
258078505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
2581c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
258225f49c5fSRichard Henderson                         ts = arg_temp(op->args[i]);
258325f49c5fSRichard Henderson                         if (ts->state != TS_DEAD) {
2584c6e113f5Sbellard                             goto do_not_remove_call;
2585c6e113f5Sbellard                         }
25869c43b68dSAurelien Jarno                     }
2587c45cb8bbSRichard Henderson                     goto do_remove;
2588152c35aaSRichard Henderson                 }
2589c6e113f5Sbellard             do_not_remove_call:
2590c896fe29Sbellard 
259125f49c5fSRichard Henderson                 /* Output args are dead.  */
2592c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
259325f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
259425f49c5fSRichard Henderson                     if (ts->state & TS_DEAD) {
2595a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
25966b64b624SAurelien Jarno                     }
259725f49c5fSRichard Henderson                     if (ts->state & TS_MEM) {
2598a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
25999c43b68dSAurelien Jarno                     }
260025f49c5fSRichard Henderson                     ts->state = TS_DEAD;
260125f49c5fSRichard Henderson                     la_reset_pref(ts);
260225f49c5fSRichard Henderson 
260325f49c5fSRichard Henderson                     /* Not used -- it will be tcg_target_call_oarg_regs[i].  */
260425f49c5fSRichard Henderson                     op->output_pref[i] = 0;
2605c896fe29Sbellard                 }
2606c896fe29Sbellard 
260778505279SAurelien Jarno                 if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
260878505279SAurelien Jarno                                     TCG_CALL_NO_READ_GLOBALS))) {
2609f65a061cSRichard Henderson                     la_global_kill(s, nb_globals);
2610c70fbf0aSRichard Henderson                 } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
2611f65a061cSRichard Henderson                     la_global_sync(s, nb_globals);
2612b9c18f56Saurel32                 }
2613c896fe29Sbellard 
261425f49c5fSRichard Henderson                 /* Record arguments that die in this helper.  */
2615866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
261625f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
261725f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
2618a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
2619c896fe29Sbellard                     }
2620c896fe29Sbellard                 }
262125f49c5fSRichard Henderson 
262225f49c5fSRichard Henderson                 /* For all live registers, remove call-clobbered prefs.  */
262325f49c5fSRichard Henderson                 la_cross_call(s, nb_temps);
262425f49c5fSRichard Henderson 
262525f49c5fSRichard Henderson                 nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
262625f49c5fSRichard Henderson 
262725f49c5fSRichard Henderson                 /* Input arguments are live for preceding opcodes.  */
262825f49c5fSRichard Henderson                 for (i = 0; i < nb_iargs; i++) {
262925f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
263025f49c5fSRichard Henderson                     if (ts && ts->state & TS_DEAD) {
263125f49c5fSRichard Henderson                         /* For those arguments that die, and will be allocated
263225f49c5fSRichard Henderson                          * in registers, clear the register set for that arg,
263325f49c5fSRichard Henderson                          * to be filled in below.  For args that will be on
263425f49c5fSRichard Henderson                          * the stack, reset to any available reg.
263525f49c5fSRichard Henderson                          */
263625f49c5fSRichard Henderson                         *la_temp_pref(ts)
263725f49c5fSRichard Henderson                             = (i < nb_call_regs ? 0 :
263825f49c5fSRichard Henderson                                tcg_target_available_regs[ts->type]);
263925f49c5fSRichard Henderson                         ts->state &= ~TS_DEAD;
264025f49c5fSRichard Henderson                     }
264125f49c5fSRichard Henderson                 }
264225f49c5fSRichard Henderson 
264325f49c5fSRichard Henderson                 /* For each input argument, add its input register to prefs.
264425f49c5fSRichard Henderson                    If a temp is used once, this produces a single set bit.  */
264525f49c5fSRichard Henderson                 for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) {
264625f49c5fSRichard Henderson                     ts = arg_temp(op->args[i + nb_oargs]);
264725f49c5fSRichard Henderson                     if (ts) {
264825f49c5fSRichard Henderson                         tcg_regset_set_reg(*la_temp_pref(ts),
264925f49c5fSRichard Henderson                                            tcg_target_call_iarg_regs[i]);
2650c70fbf0aSRichard Henderson                     }
2651c19f47bfSAurelien Jarno                 }
2652c6e113f5Sbellard             }
2653c896fe29Sbellard             break;
2654765b842aSRichard Henderson         case INDEX_op_insn_start:
2655c896fe29Sbellard             break;
26565ff9d6a4Sbellard         case INDEX_op_discard:
26575ff9d6a4Sbellard             /* mark the temporary as dead */
265825f49c5fSRichard Henderson             ts = arg_temp(op->args[0]);
265925f49c5fSRichard Henderson             ts->state = TS_DEAD;
266025f49c5fSRichard Henderson             la_reset_pref(ts);
26615ff9d6a4Sbellard             break;
26621305c451SRichard Henderson 
26631305c451SRichard Henderson         case INDEX_op_add2_i32:
2664c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
2665f1fae40cSRichard Henderson             goto do_addsub2;
26661305c451SRichard Henderson         case INDEX_op_sub2_i32:
2667c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
2668f1fae40cSRichard Henderson             goto do_addsub2;
2669f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
2670c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
2671f1fae40cSRichard Henderson             goto do_addsub2;
2672f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
2673c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
2674f1fae40cSRichard Henderson         do_addsub2:
26751305c451SRichard Henderson             nb_iargs = 4;
26761305c451SRichard Henderson             nb_oargs = 2;
26771305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
26781305c451SRichard Henderson                the low part.  The result can be optimized to a simple
26791305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
26801305c451SRichard Henderson                cpu mode is set to 32 bit.  */
2681b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2682b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
26831305c451SRichard Henderson                     goto do_remove;
26841305c451SRichard Henderson                 }
2685c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
2686c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
2687c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2688efee3746SRichard Henderson                 op->args[1] = op->args[2];
2689efee3746SRichard Henderson                 op->args[2] = op->args[4];
26901305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
26911305c451SRichard Henderson                 nb_iargs = 2;
26921305c451SRichard Henderson                 nb_oargs = 1;
26931305c451SRichard Henderson             }
26941305c451SRichard Henderson             goto do_not_remove;
26951305c451SRichard Henderson 
26961414968aSRichard Henderson         case INDEX_op_mulu2_i32:
2697c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2698c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
2699c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
270003271524SRichard Henderson             goto do_mul2;
2701f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
2702c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
2703c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
2704c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
2705f1fae40cSRichard Henderson             goto do_mul2;
2706f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
2707c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2708c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
2709c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
271003271524SRichard Henderson             goto do_mul2;
2711f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
2712c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
2713c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
2714c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
271503271524SRichard Henderson             goto do_mul2;
2716f1fae40cSRichard Henderson         do_mul2:
27171414968aSRichard Henderson             nb_iargs = 2;
27181414968aSRichard Henderson             nb_oargs = 2;
2719b83eabeaSRichard Henderson             if (arg_temp(op->args[1])->state == TS_DEAD) {
2720b83eabeaSRichard Henderson                 if (arg_temp(op->args[0])->state == TS_DEAD) {
272103271524SRichard Henderson                     /* Both parts of the operation are dead.  */
27221414968aSRichard Henderson                     goto do_remove;
27231414968aSRichard Henderson                 }
272403271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
2725c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
2726efee3746SRichard Henderson                 op->args[1] = op->args[2];
2727efee3746SRichard Henderson                 op->args[2] = op->args[3];
2728b83eabeaSRichard Henderson             } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) {
272903271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
2730c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
2731efee3746SRichard Henderson                 op->args[0] = op->args[1];
2732efee3746SRichard Henderson                 op->args[1] = op->args[2];
2733efee3746SRichard Henderson                 op->args[2] = op->args[3];
273403271524SRichard Henderson             } else {
273503271524SRichard Henderson                 goto do_not_remove;
273603271524SRichard Henderson             }
273703271524SRichard Henderson             /* Mark the single-word operation live.  */
27381414968aSRichard Henderson             nb_oargs = 1;
27391414968aSRichard Henderson             goto do_not_remove;
27401414968aSRichard Henderson 
2741c896fe29Sbellard         default:
27421305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
2743c896fe29Sbellard             nb_iargs = def->nb_iargs;
2744c896fe29Sbellard             nb_oargs = def->nb_oargs;
2745c896fe29Sbellard 
2746c896fe29Sbellard             /* Test if the operation can be removed because all
27475ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
27485ff9d6a4Sbellard                implies side effects */
27495ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
2750c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
2751b83eabeaSRichard Henderson                     if (arg_temp(op->args[i])->state != TS_DEAD) {
2752c896fe29Sbellard                         goto do_not_remove;
2753c896fe29Sbellard                     }
27549c43b68dSAurelien Jarno                 }
2755152c35aaSRichard Henderson                 goto do_remove;
2756152c35aaSRichard Henderson             }
2757152c35aaSRichard Henderson             goto do_not_remove;
2758152c35aaSRichard Henderson 
27591305c451SRichard Henderson         do_remove:
27600c627cdcSRichard Henderson             tcg_op_remove(s, op);
2761152c35aaSRichard Henderson             break;
2762152c35aaSRichard Henderson 
2763c896fe29Sbellard         do_not_remove:
2764c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
276525f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
276625f49c5fSRichard Henderson 
276725f49c5fSRichard Henderson                 /* Remember the preference of the uses that followed.  */
276825f49c5fSRichard Henderson                 op->output_pref[i] = *la_temp_pref(ts);
276925f49c5fSRichard Henderson 
277025f49c5fSRichard Henderson                 /* Output args are dead.  */
277125f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2772a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
27736b64b624SAurelien Jarno                 }
277425f49c5fSRichard Henderson                 if (ts->state & TS_MEM) {
2775a1b3c48dSRichard Henderson                     arg_life |= SYNC_ARG << i;
27769c43b68dSAurelien Jarno                 }
277725f49c5fSRichard Henderson                 ts->state = TS_DEAD;
277825f49c5fSRichard Henderson                 la_reset_pref(ts);
2779c896fe29Sbellard             }
2780c896fe29Sbellard 
278125f49c5fSRichard Henderson             /* If end of basic block, update.  */
2782ae36a246SRichard Henderson             if (def->flags & TCG_OPF_BB_EXIT) {
2783ae36a246SRichard Henderson                 la_func_end(s, nb_globals, nb_temps);
2784ae36a246SRichard Henderson             } else if (def->flags & TCG_OPF_BB_END) {
27852616c808SRichard Henderson                 la_bb_end(s, nb_globals, nb_temps);
27863d5c5f87SAurelien Jarno             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
2787f65a061cSRichard Henderson                 la_global_sync(s, nb_globals);
278825f49c5fSRichard Henderson                 if (def->flags & TCG_OPF_CALL_CLOBBER) {
278925f49c5fSRichard Henderson                     la_cross_call(s, nb_temps);
279025f49c5fSRichard Henderson                 }
2791c896fe29Sbellard             }
2792c896fe29Sbellard 
279325f49c5fSRichard Henderson             /* Record arguments that die in this opcode.  */
2794866cb6cbSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
279525f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
279625f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
2797a1b3c48dSRichard Henderson                     arg_life |= DEAD_ARG << i;
2798c896fe29Sbellard                 }
2799c19f47bfSAurelien Jarno             }
280025f49c5fSRichard Henderson 
280125f49c5fSRichard Henderson             /* Input arguments are live for preceding opcodes.  */
2802c19f47bfSAurelien Jarno             for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
280325f49c5fSRichard Henderson                 ts = arg_temp(op->args[i]);
280425f49c5fSRichard Henderson                 if (ts->state & TS_DEAD) {
280525f49c5fSRichard Henderson                     /* For operands that were dead, initially allow
280625f49c5fSRichard Henderson                        all regs for the type.  */
280725f49c5fSRichard Henderson                     *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
280825f49c5fSRichard Henderson                     ts->state &= ~TS_DEAD;
280925f49c5fSRichard Henderson                 }
281025f49c5fSRichard Henderson             }
281125f49c5fSRichard Henderson 
281225f49c5fSRichard Henderson             /* Incorporate constraints for this operand.  */
281325f49c5fSRichard Henderson             switch (opc) {
281425f49c5fSRichard Henderson             case INDEX_op_mov_i32:
281525f49c5fSRichard Henderson             case INDEX_op_mov_i64:
281625f49c5fSRichard Henderson                 /* Note that these are TCG_OPF_NOT_PRESENT and do not
281725f49c5fSRichard Henderson                    have proper constraints.  That said, special case
281825f49c5fSRichard Henderson                    moves to propagate preferences backward.  */
281925f49c5fSRichard Henderson                 if (IS_DEAD_ARG(1)) {
282025f49c5fSRichard Henderson                     *la_temp_pref(arg_temp(op->args[0]))
282125f49c5fSRichard Henderson                         = *la_temp_pref(arg_temp(op->args[1]));
282225f49c5fSRichard Henderson                 }
282325f49c5fSRichard Henderson                 break;
282425f49c5fSRichard Henderson 
282525f49c5fSRichard Henderson             default:
282625f49c5fSRichard Henderson                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
282725f49c5fSRichard Henderson                     const TCGArgConstraint *ct = &def->args_ct[i];
282825f49c5fSRichard Henderson                     TCGRegSet set, *pset;
282925f49c5fSRichard Henderson 
283025f49c5fSRichard Henderson                     ts = arg_temp(op->args[i]);
283125f49c5fSRichard Henderson                     pset = la_temp_pref(ts);
283225f49c5fSRichard Henderson                     set = *pset;
283325f49c5fSRichard Henderson 
283425f49c5fSRichard Henderson                     set &= ct->u.regs;
283525f49c5fSRichard Henderson                     if (ct->ct & TCG_CT_IALIAS) {
283625f49c5fSRichard Henderson                         set &= op->output_pref[ct->alias_index];
283725f49c5fSRichard Henderson                     }
283825f49c5fSRichard Henderson                     /* If the combination is not possible, restart.  */
283925f49c5fSRichard Henderson                     if (set == 0) {
284025f49c5fSRichard Henderson                         set = ct->u.regs;
284125f49c5fSRichard Henderson                     }
284225f49c5fSRichard Henderson                     *pset = set;
284325f49c5fSRichard Henderson                 }
284425f49c5fSRichard Henderson                 break;
2845c896fe29Sbellard             }
2846c896fe29Sbellard             break;
2847c896fe29Sbellard         }
2848bee158cbSRichard Henderson         op->life = arg_life;
2849c896fe29Sbellard     }
28501ff0a2c5SEvgeny Voevodin }
2851c896fe29Sbellard 
28525a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
2853b83eabeaSRichard Henderson static bool liveness_pass_2(TCGContext *s)
28545a18407fSRichard Henderson {
28555a18407fSRichard Henderson     int nb_globals = s->nb_globals;
285615fa08f8SRichard Henderson     int nb_temps, i;
28575a18407fSRichard Henderson     bool changes = false;
285815fa08f8SRichard Henderson     TCGOp *op, *op_next;
28595a18407fSRichard Henderson 
28605a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
28615a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
28625a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
28635a18407fSRichard Henderson         if (its->indirect_reg) {
28645a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
28655a18407fSRichard Henderson             dts->type = its->type;
28665a18407fSRichard Henderson             dts->base_type = its->base_type;
2867b83eabeaSRichard Henderson             its->state_ptr = dts;
2868b83eabeaSRichard Henderson         } else {
2869b83eabeaSRichard Henderson             its->state_ptr = NULL;
28705a18407fSRichard Henderson         }
2871b83eabeaSRichard Henderson         /* All globals begin dead.  */
2872b83eabeaSRichard Henderson         its->state = TS_DEAD;
28735a18407fSRichard Henderson     }
2874b83eabeaSRichard Henderson     for (nb_temps = s->nb_temps; i < nb_temps; ++i) {
2875b83eabeaSRichard Henderson         TCGTemp *its = &s->temps[i];
2876b83eabeaSRichard Henderson         its->state_ptr = NULL;
2877b83eabeaSRichard Henderson         its->state = TS_DEAD;
2878b83eabeaSRichard Henderson     }
28795a18407fSRichard Henderson 
288015fa08f8SRichard Henderson     QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
28815a18407fSRichard Henderson         TCGOpcode opc = op->opc;
28825a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
28835a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
28845a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
2885b83eabeaSRichard Henderson         TCGTemp *arg_ts, *dir_ts;
28865a18407fSRichard Henderson 
28875a18407fSRichard Henderson         if (opc == INDEX_op_call) {
2888cd9090aaSRichard Henderson             nb_oargs = TCGOP_CALLO(op);
2889cd9090aaSRichard Henderson             nb_iargs = TCGOP_CALLI(op);
2890efee3746SRichard Henderson             call_flags = op->args[nb_oargs + nb_iargs + 1];
28915a18407fSRichard Henderson         } else {
28925a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
28935a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
28945a18407fSRichard Henderson 
28955a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
28965a18407fSRichard Henderson             if (def->flags & TCG_OPF_BB_END) {
28975a18407fSRichard Henderson                 /* Like writing globals: save_globals */
28985a18407fSRichard Henderson                 call_flags = 0;
28995a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
29005a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
29015a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
29025a18407fSRichard Henderson             } else {
29035a18407fSRichard Henderson                 /* No effect on globals.  */
29045a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
29055a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
29065a18407fSRichard Henderson             }
29075a18407fSRichard Henderson         }
29085a18407fSRichard Henderson 
29095a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
29105a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2911b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2912b83eabeaSRichard Henderson             if (arg_ts) {
2913b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
2914b83eabeaSRichard Henderson                 if (dir_ts && arg_ts->state == TS_DEAD) {
2915b83eabeaSRichard Henderson                     TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
29165a18407fSRichard Henderson                                       ? INDEX_op_ld_i32
29175a18407fSRichard Henderson                                       : INDEX_op_ld_i64);
2918ac1043f6SEmilio G. Cota                     TCGOp *lop = tcg_op_insert_before(s, op, lopc);
29195a18407fSRichard Henderson 
2920b83eabeaSRichard Henderson                     lop->args[0] = temp_arg(dir_ts);
2921b83eabeaSRichard Henderson                     lop->args[1] = temp_arg(arg_ts->mem_base);
2922b83eabeaSRichard Henderson                     lop->args[2] = arg_ts->mem_offset;
29235a18407fSRichard Henderson 
29245a18407fSRichard Henderson                     /* Loaded, but synced with memory.  */
2925b83eabeaSRichard Henderson                     arg_ts->state = TS_MEM;
29265a18407fSRichard Henderson                 }
29275a18407fSRichard Henderson             }
29285a18407fSRichard Henderson         }
29295a18407fSRichard Henderson 
29305a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
29315a18407fSRichard Henderson            No action is required except keeping temp_state up to date
29325a18407fSRichard Henderson            so that we reload when needed.  */
29335a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2934b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2935b83eabeaSRichard Henderson             if (arg_ts) {
2936b83eabeaSRichard Henderson                 dir_ts = arg_ts->state_ptr;
2937b83eabeaSRichard Henderson                 if (dir_ts) {
2938b83eabeaSRichard Henderson                     op->args[i] = temp_arg(dir_ts);
29395a18407fSRichard Henderson                     changes = true;
29405a18407fSRichard Henderson                     if (IS_DEAD_ARG(i)) {
2941b83eabeaSRichard Henderson                         arg_ts->state = TS_DEAD;
29425a18407fSRichard Henderson                     }
29435a18407fSRichard Henderson                 }
29445a18407fSRichard Henderson             }
29455a18407fSRichard Henderson         }
29465a18407fSRichard Henderson 
29475a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
29485a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
29495a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
29505a18407fSRichard Henderson             /* Nothing to do */
29515a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
29525a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
29535a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
29545a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
2955b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
2956b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
2957b83eabeaSRichard Henderson                                  || arg_ts->state != 0);
29585a18407fSRichard Henderson             }
29595a18407fSRichard Henderson         } else {
29605a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
29615a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
29625a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
2963b83eabeaSRichard Henderson                 arg_ts = &s->temps[i];
2964b83eabeaSRichard Henderson                 tcg_debug_assert(arg_ts->state_ptr == 0
2965b83eabeaSRichard Henderson                                  || arg_ts->state == TS_DEAD);
29665a18407fSRichard Henderson             }
29675a18407fSRichard Henderson         }
29685a18407fSRichard Henderson 
29695a18407fSRichard Henderson         /* Outputs become available.  */
29705a18407fSRichard Henderson         for (i = 0; i < nb_oargs; i++) {
2971b83eabeaSRichard Henderson             arg_ts = arg_temp(op->args[i]);
2972b83eabeaSRichard Henderson             dir_ts = arg_ts->state_ptr;
2973b83eabeaSRichard Henderson             if (!dir_ts) {
29745a18407fSRichard Henderson                 continue;
29755a18407fSRichard Henderson             }
2976b83eabeaSRichard Henderson             op->args[i] = temp_arg(dir_ts);
29775a18407fSRichard Henderson             changes = true;
29785a18407fSRichard Henderson 
29795a18407fSRichard Henderson             /* The output is now live and modified.  */
2980b83eabeaSRichard Henderson             arg_ts->state = 0;
29815a18407fSRichard Henderson 
29825a18407fSRichard Henderson             /* Sync outputs upon their last write.  */
29835a18407fSRichard Henderson             if (NEED_SYNC_ARG(i)) {
2984b83eabeaSRichard Henderson                 TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
29855a18407fSRichard Henderson                                   ? INDEX_op_st_i32
29865a18407fSRichard Henderson                                   : INDEX_op_st_i64);
2987ac1043f6SEmilio G. Cota                 TCGOp *sop = tcg_op_insert_after(s, op, sopc);
29885a18407fSRichard Henderson 
2989b83eabeaSRichard Henderson                 sop->args[0] = temp_arg(dir_ts);
2990b83eabeaSRichard Henderson                 sop->args[1] = temp_arg(arg_ts->mem_base);
2991b83eabeaSRichard Henderson                 sop->args[2] = arg_ts->mem_offset;
29925a18407fSRichard Henderson 
2993b83eabeaSRichard Henderson                 arg_ts->state = TS_MEM;
29945a18407fSRichard Henderson             }
29955a18407fSRichard Henderson             /* Drop outputs that are dead.  */
29965a18407fSRichard Henderson             if (IS_DEAD_ARG(i)) {
2997b83eabeaSRichard Henderson                 arg_ts->state = TS_DEAD;
29985a18407fSRichard Henderson             }
29995a18407fSRichard Henderson         }
30005a18407fSRichard Henderson     }
30015a18407fSRichard Henderson 
30025a18407fSRichard Henderson     return changes;
30035a18407fSRichard Henderson }
30045a18407fSRichard Henderson 
30058d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
3006c896fe29Sbellard static void dump_regs(TCGContext *s)
3007c896fe29Sbellard {
3008c896fe29Sbellard     TCGTemp *ts;
3009c896fe29Sbellard     int i;
3010c896fe29Sbellard     char buf[64];
3011c896fe29Sbellard 
3012c896fe29Sbellard     for(i = 0; i < s->nb_temps; i++) {
3013c896fe29Sbellard         ts = &s->temps[i];
301443439139SRichard Henderson         printf("  %10s: ", tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3015c896fe29Sbellard         switch(ts->val_type) {
3016c896fe29Sbellard         case TEMP_VAL_REG:
3017c896fe29Sbellard             printf("%s", tcg_target_reg_names[ts->reg]);
3018c896fe29Sbellard             break;
3019c896fe29Sbellard         case TEMP_VAL_MEM:
3020b3a62939SRichard Henderson             printf("%d(%s)", (int)ts->mem_offset,
3021b3a62939SRichard Henderson                    tcg_target_reg_names[ts->mem_base->reg]);
3022c896fe29Sbellard             break;
3023c896fe29Sbellard         case TEMP_VAL_CONST:
3024c896fe29Sbellard             printf("$0x%" TCG_PRIlx, ts->val);
3025c896fe29Sbellard             break;
3026c896fe29Sbellard         case TEMP_VAL_DEAD:
3027c896fe29Sbellard             printf("D");
3028c896fe29Sbellard             break;
3029c896fe29Sbellard         default:
3030c896fe29Sbellard             printf("???");
3031c896fe29Sbellard             break;
3032c896fe29Sbellard         }
3033c896fe29Sbellard         printf("\n");
3034c896fe29Sbellard     }
3035c896fe29Sbellard 
3036c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
3037f8b2f202SRichard Henderson         if (s->reg_to_temp[i] != NULL) {
3038c896fe29Sbellard             printf("%s: %s\n",
3039c896fe29Sbellard                    tcg_target_reg_names[i],
3040f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i]));
3041c896fe29Sbellard         }
3042c896fe29Sbellard     }
3043c896fe29Sbellard }
3044c896fe29Sbellard 
3045c896fe29Sbellard static void check_regs(TCGContext *s)
3046c896fe29Sbellard {
3047869938aeSRichard Henderson     int reg;
3048b6638662SRichard Henderson     int k;
3049c896fe29Sbellard     TCGTemp *ts;
3050c896fe29Sbellard     char buf[64];
3051c896fe29Sbellard 
3052c896fe29Sbellard     for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
3053f8b2f202SRichard Henderson         ts = s->reg_to_temp[reg];
3054f8b2f202SRichard Henderson         if (ts != NULL) {
3055f8b2f202SRichard Henderson             if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) {
3056c896fe29Sbellard                 printf("Inconsistency for register %s:\n",
3057c896fe29Sbellard                        tcg_target_reg_names[reg]);
3058b03cce8eSbellard                 goto fail;
3059c896fe29Sbellard             }
3060c896fe29Sbellard         }
3061c896fe29Sbellard     }
3062c896fe29Sbellard     for (k = 0; k < s->nb_temps; k++) {
3063c896fe29Sbellard         ts = &s->temps[k];
3064f8b2f202SRichard Henderson         if (ts->val_type == TEMP_VAL_REG && !ts->fixed_reg
3065f8b2f202SRichard Henderson             && s->reg_to_temp[ts->reg] != ts) {
3066c896fe29Sbellard             printf("Inconsistency for temp %s:\n",
3067f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
3068b03cce8eSbellard         fail:
3069c896fe29Sbellard             printf("reg state:\n");
3070c896fe29Sbellard             dump_regs(s);
3071c896fe29Sbellard             tcg_abort();
3072c896fe29Sbellard         }
3073c896fe29Sbellard     }
3074c896fe29Sbellard }
3075c896fe29Sbellard #endif
3076c896fe29Sbellard 
30772272e4a7SRichard Henderson static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
3078c896fe29Sbellard {
30799b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64)
30809b9c37c3SRichard Henderson     /* Sparc64 stack is accessed with offset of 2047 */
3081b591dc59SBlue Swirl     s->current_frame_offset = (s->current_frame_offset +
3082b591dc59SBlue Swirl                                (tcg_target_long)sizeof(tcg_target_long) - 1) &
3083b591dc59SBlue Swirl         ~(sizeof(tcg_target_long) - 1);
3084f44c9960SBlue Swirl #endif
3085b591dc59SBlue Swirl     if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
3086b591dc59SBlue Swirl         s->frame_end) {
30875ff9d6a4Sbellard         tcg_abort();
3088b591dc59SBlue Swirl     }
3089c896fe29Sbellard     ts->mem_offset = s->current_frame_offset;
3090b3a62939SRichard Henderson     ts->mem_base = s->frame_temp;
3091c896fe29Sbellard     ts->mem_allocated = 1;
3092e2c6d1b4SRichard Henderson     s->current_frame_offset += sizeof(tcg_target_long);
3093c896fe29Sbellard }
3094c896fe29Sbellard 
3095b722452aSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
3096b3915dbbSRichard Henderson 
309759d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
309859d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
309959d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
3100c896fe29Sbellard {
310159d7c14eSRichard Henderson     if (ts->fixed_reg) {
310259d7c14eSRichard Henderson         return;
310359d7c14eSRichard Henderson     }
310459d7c14eSRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
310559d7c14eSRichard Henderson         s->reg_to_temp[ts->reg] = NULL;
310659d7c14eSRichard Henderson     }
310759d7c14eSRichard Henderson     ts->val_type = (free_or_dead < 0
310859d7c14eSRichard Henderson                     || ts->temp_local
3109fa477d25SRichard Henderson                     || ts->temp_global
311059d7c14eSRichard Henderson                     ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
311159d7c14eSRichard Henderson }
3112c896fe29Sbellard 
311359d7c14eSRichard Henderson /* Mark a temporary as dead.  */
311459d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
311559d7c14eSRichard Henderson {
311659d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
311759d7c14eSRichard Henderson }
311859d7c14eSRichard Henderson 
311959d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
312059d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
312159d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
312259d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
312398b4e186SRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
312498b4e186SRichard Henderson                       TCGRegSet preferred_regs, int free_or_dead)
312559d7c14eSRichard Henderson {
312659d7c14eSRichard Henderson     if (ts->fixed_reg) {
312759d7c14eSRichard Henderson         return;
312859d7c14eSRichard Henderson     }
312959d7c14eSRichard Henderson     if (!ts->mem_coherent) {
31307f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
31312272e4a7SRichard Henderson             temp_allocate_frame(s, ts);
313259d7c14eSRichard Henderson         }
313359d7c14eSRichard Henderson         switch (ts->val_type) {
313459d7c14eSRichard Henderson         case TEMP_VAL_CONST:
313559d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
313659d7c14eSRichard Henderson                require it later in a register, so attempt to store the
313759d7c14eSRichard Henderson                constant to memory directly.  */
313859d7c14eSRichard Henderson             if (free_or_dead
313959d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
314059d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
314159d7c14eSRichard Henderson                 break;
314259d7c14eSRichard Henderson             }
314359d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
314498b4e186SRichard Henderson                       allocated_regs, preferred_regs);
314559d7c14eSRichard Henderson             /* fallthrough */
314659d7c14eSRichard Henderson 
314759d7c14eSRichard Henderson         case TEMP_VAL_REG:
314859d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
314959d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
315059d7c14eSRichard Henderson             break;
315159d7c14eSRichard Henderson 
315259d7c14eSRichard Henderson         case TEMP_VAL_MEM:
315359d7c14eSRichard Henderson             break;
315459d7c14eSRichard Henderson 
315559d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
315659d7c14eSRichard Henderson         default:
315759d7c14eSRichard Henderson             tcg_abort();
3158c896fe29Sbellard         }
31597f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
31607f6ceedfSAurelien Jarno     }
316159d7c14eSRichard Henderson     if (free_or_dead) {
316259d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
316359d7c14eSRichard Henderson     }
316459d7c14eSRichard Henderson }
31657f6ceedfSAurelien Jarno 
31667f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
3167b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
31687f6ceedfSAurelien Jarno {
3169f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
3170f8b2f202SRichard Henderson     if (ts != NULL) {
317198b4e186SRichard Henderson         temp_sync(s, ts, allocated_regs, 0, -1);
3172c896fe29Sbellard     }
3173c896fe29Sbellard }
3174c896fe29Sbellard 
3175b016486eSRichard Henderson /**
3176b016486eSRichard Henderson  * tcg_reg_alloc:
3177b016486eSRichard Henderson  * @required_regs: Set of registers in which we must allocate.
3178b016486eSRichard Henderson  * @allocated_regs: Set of registers which must be avoided.
3179b016486eSRichard Henderson  * @preferred_regs: Set of registers we should prefer.
3180b016486eSRichard Henderson  * @rev: True if we search the registers in "indirect" order.
3181b016486eSRichard Henderson  *
3182b016486eSRichard Henderson  * The allocated register must be in @required_regs & ~@allocated_regs,
3183b016486eSRichard Henderson  * but if we can put it in @preferred_regs we may save a move later.
3184b016486eSRichard Henderson  */
3185b016486eSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
3186b016486eSRichard Henderson                             TCGRegSet allocated_regs,
3187b016486eSRichard Henderson                             TCGRegSet preferred_regs, bool rev)
3188c896fe29Sbellard {
3189b016486eSRichard Henderson     int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
3190b016486eSRichard Henderson     TCGRegSet reg_ct[2];
319191478cefSRichard Henderson     const int *order;
3192c896fe29Sbellard 
3193b016486eSRichard Henderson     reg_ct[1] = required_regs & ~allocated_regs;
3194b016486eSRichard Henderson     tcg_debug_assert(reg_ct[1] != 0);
3195b016486eSRichard Henderson     reg_ct[0] = reg_ct[1] & preferred_regs;
3196b016486eSRichard Henderson 
3197b016486eSRichard Henderson     /* Skip the preferred_regs option if it cannot be satisfied,
3198b016486eSRichard Henderson        or if the preference made no difference.  */
3199b016486eSRichard Henderson     f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
3200b016486eSRichard Henderson 
320191478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
3202c896fe29Sbellard 
3203b016486eSRichard Henderson     /* Try free registers, preferences first.  */
3204b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3205b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3206b016486eSRichard Henderson 
3207b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3208b016486eSRichard Henderson             /* One register in the set.  */
3209b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3210b016486eSRichard Henderson             if (s->reg_to_temp[reg] == NULL) {
3211c896fe29Sbellard                 return reg;
3212c896fe29Sbellard             }
3213b016486eSRichard Henderson         } else {
321491478cefSRichard Henderson             for (i = 0; i < n; i++) {
3215b016486eSRichard Henderson                 TCGReg reg = order[i];
3216b016486eSRichard Henderson                 if (s->reg_to_temp[reg] == NULL &&
3217b016486eSRichard Henderson                     tcg_regset_test_reg(set, reg)) {
3218b016486eSRichard Henderson                     return reg;
3219b016486eSRichard Henderson                 }
3220b016486eSRichard Henderson             }
3221b016486eSRichard Henderson         }
3222b016486eSRichard Henderson     }
3223b016486eSRichard Henderson 
3224b016486eSRichard Henderson     /* We must spill something.  */
3225b016486eSRichard Henderson     for (j = f; j < 2; j++) {
3226b016486eSRichard Henderson         TCGRegSet set = reg_ct[j];
3227b016486eSRichard Henderson 
3228b016486eSRichard Henderson         if (tcg_regset_single(set)) {
3229b016486eSRichard Henderson             /* One register in the set.  */
3230b016486eSRichard Henderson             TCGReg reg = tcg_regset_first(set);
3231b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
3232c896fe29Sbellard             return reg;
3233b016486eSRichard Henderson         } else {
3234b016486eSRichard Henderson             for (i = 0; i < n; i++) {
3235b016486eSRichard Henderson                 TCGReg reg = order[i];
3236b016486eSRichard Henderson                 if (tcg_regset_test_reg(set, reg)) {
3237b016486eSRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
3238b016486eSRichard Henderson                     return reg;
3239b016486eSRichard Henderson                 }
3240b016486eSRichard Henderson             }
3241c896fe29Sbellard         }
3242c896fe29Sbellard     }
3243c896fe29Sbellard 
3244c896fe29Sbellard     tcg_abort();
3245c896fe29Sbellard }
3246c896fe29Sbellard 
324740ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
324840ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
324940ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
3250b722452aSRichard Henderson                       TCGRegSet allocated_regs, TCGRegSet preferred_regs)
325140ae5c62SRichard Henderson {
325240ae5c62SRichard Henderson     TCGReg reg;
325340ae5c62SRichard Henderson 
325440ae5c62SRichard Henderson     switch (ts->val_type) {
325540ae5c62SRichard Henderson     case TEMP_VAL_REG:
325640ae5c62SRichard Henderson         return;
325740ae5c62SRichard Henderson     case TEMP_VAL_CONST:
3258b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3259b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
326040ae5c62SRichard Henderson         tcg_out_movi(s, ts->type, reg, ts->val);
326140ae5c62SRichard Henderson         ts->mem_coherent = 0;
326240ae5c62SRichard Henderson         break;
326340ae5c62SRichard Henderson     case TEMP_VAL_MEM:
3264b016486eSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
3265b722452aSRichard Henderson                             preferred_regs, ts->indirect_base);
326640ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
326740ae5c62SRichard Henderson         ts->mem_coherent = 1;
326840ae5c62SRichard Henderson         break;
326940ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
327040ae5c62SRichard Henderson     default:
327140ae5c62SRichard Henderson         tcg_abort();
327240ae5c62SRichard Henderson     }
327340ae5c62SRichard Henderson     ts->reg = reg;
327440ae5c62SRichard Henderson     ts->val_type = TEMP_VAL_REG;
327540ae5c62SRichard Henderson     s->reg_to_temp[reg] = ts;
327640ae5c62SRichard Henderson }
327740ae5c62SRichard Henderson 
327859d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
3279e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
328059d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
32811ad80729SAurelien Jarno {
32822c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
3283eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
3284f8bf00f1SRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg);
32851ad80729SAurelien Jarno }
32861ad80729SAurelien Jarno 
32879814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
3288641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
3289641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
3290641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
3291641d5fbeSbellard {
3292ac3b8891SRichard Henderson     int i, n;
3293641d5fbeSbellard 
3294ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
3295b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
3296641d5fbeSbellard     }
3297e5097dc8Sbellard }
3298e5097dc8Sbellard 
32993d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
33003d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
33013d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
33023d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
33033d5c5f87SAurelien Jarno {
3304ac3b8891SRichard Henderson     int i, n;
33053d5c5f87SAurelien Jarno 
3306ac3b8891SRichard Henderson     for (i = 0, n = s->nb_globals; i < n; i++) {
330712b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
330812b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
330912b9b11aSRichard Henderson                          || ts->fixed_reg
331012b9b11aSRichard Henderson                          || ts->mem_coherent);
33113d5c5f87SAurelien Jarno     }
33123d5c5f87SAurelien Jarno }
33133d5c5f87SAurelien Jarno 
3314e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
3315e8996ee0Sbellard    all globals are stored at their canonical location. */
3316e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
3317e5097dc8Sbellard {
3318e5097dc8Sbellard     int i;
3319e5097dc8Sbellard 
3320c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
3321b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
3322641d5fbeSbellard         if (ts->temp_local) {
3323b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
3324641d5fbeSbellard         } else {
33252c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
3326eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
3327eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
3328c896fe29Sbellard         }
3329641d5fbeSbellard     }
3330e8996ee0Sbellard 
3331e8996ee0Sbellard     save_globals(s, allocated_regs);
3332c896fe29Sbellard }
3333c896fe29Sbellard 
3334bab1671fSRichard Henderson /*
3335bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_movi_*.
3336bab1671fSRichard Henderson  */
33370fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
3338ba87719cSRichard Henderson                                   tcg_target_ulong val, TCGLifeData arg_life,
3339ba87719cSRichard Henderson                                   TCGRegSet preferred_regs)
3340e8996ee0Sbellard {
3341d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3342d63e3b6eSRichard Henderson     tcg_debug_assert(!ots->fixed_reg);
334359d7c14eSRichard Henderson 
334459d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
3345f8b2f202SRichard Henderson     if (ots->val_type == TEMP_VAL_REG) {
3346f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = NULL;
3347f8b2f202SRichard Henderson     }
3348e8996ee0Sbellard     ots->val_type = TEMP_VAL_CONST;
3349e8996ee0Sbellard     ots->val = val;
335059d7c14eSRichard Henderson     ots->mem_coherent = 0;
3351ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
3352ba87719cSRichard Henderson         temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
335359d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
3354f8bf00f1SRichard Henderson         temp_dead(s, ots);
33554c4e1ab2SAurelien Jarno     }
3356e8996ee0Sbellard }
3357e8996ee0Sbellard 
3358dd186292SRichard Henderson static void tcg_reg_alloc_movi(TCGContext *s, const TCGOp *op)
33590fe4fca4SPaolo Bonzini {
336043439139SRichard Henderson     TCGTemp *ots = arg_temp(op->args[0]);
3361dd186292SRichard Henderson     tcg_target_ulong val = op->args[1];
33620fe4fca4SPaolo Bonzini 
336369e3706dSRichard Henderson     tcg_reg_alloc_do_movi(s, ots, val, op->life, op->output_pref[0]);
33640fe4fca4SPaolo Bonzini }
33650fe4fca4SPaolo Bonzini 
3366bab1671fSRichard Henderson /*
3367bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_mov_*.
3368bab1671fSRichard Henderson  */
3369dd186292SRichard Henderson static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
3370c896fe29Sbellard {
3371dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
337269e3706dSRichard Henderson     TCGRegSet allocated_regs, preferred_regs;
3373c896fe29Sbellard     TCGTemp *ts, *ots;
3374450445d5SRichard Henderson     TCGType otype, itype;
3375c896fe29Sbellard 
3376d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
337769e3706dSRichard Henderson     preferred_regs = op->output_pref[0];
337843439139SRichard Henderson     ots = arg_temp(op->args[0]);
337943439139SRichard Henderson     ts = arg_temp(op->args[1]);
3380450445d5SRichard Henderson 
3381d63e3b6eSRichard Henderson     /* ENV should not be modified.  */
3382d63e3b6eSRichard Henderson     tcg_debug_assert(!ots->fixed_reg);
3383d63e3b6eSRichard Henderson 
3384450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
3385450445d5SRichard Henderson     otype = ots->type;
3386450445d5SRichard Henderson     itype = ts->type;
3387c896fe29Sbellard 
33880fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
33890fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
33900fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
33910fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
33920fe4fca4SPaolo Bonzini             temp_dead(s, ts);
33930fe4fca4SPaolo Bonzini         }
339469e3706dSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
33950fe4fca4SPaolo Bonzini         return;
33960fe4fca4SPaolo Bonzini     }
33970fe4fca4SPaolo Bonzini 
33980fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
33990fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
34000fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
34010fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
34020fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
340369e3706dSRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype],
340469e3706dSRichard Henderson                   allocated_regs, preferred_regs);
3405c29c1d7eSAurelien Jarno     }
3406c29c1d7eSAurelien Jarno 
34070fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
3408d63e3b6eSRichard Henderson     if (IS_DEAD_ARG(0)) {
3409c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
3410c29c1d7eSAurelien Jarno            liveness analysis disabled). */
3411eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
3412c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
34132272e4a7SRichard Henderson             temp_allocate_frame(s, ots);
3414c29c1d7eSAurelien Jarno         }
3415b3a62939SRichard Henderson         tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset);
3416c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
3417f8bf00f1SRichard Henderson             temp_dead(s, ts);
3418c29c1d7eSAurelien Jarno         }
3419f8bf00f1SRichard Henderson         temp_dead(s, ots);
3420e8996ee0Sbellard     } else {
3421d63e3b6eSRichard Henderson         if (IS_DEAD_ARG(1) && !ts->fixed_reg) {
3422c29c1d7eSAurelien Jarno             /* the mov can be suppressed */
3423c29c1d7eSAurelien Jarno             if (ots->val_type == TEMP_VAL_REG) {
3424f8b2f202SRichard Henderson                 s->reg_to_temp[ots->reg] = NULL;
3425c896fe29Sbellard             }
3426c29c1d7eSAurelien Jarno             ots->reg = ts->reg;
3427f8bf00f1SRichard Henderson             temp_dead(s, ts);
3428c29c1d7eSAurelien Jarno         } else {
3429c29c1d7eSAurelien Jarno             if (ots->val_type != TEMP_VAL_REG) {
3430c29c1d7eSAurelien Jarno                 /* When allocating a new register, make sure to not spill the
3431c29c1d7eSAurelien Jarno                    input one. */
3432c29c1d7eSAurelien Jarno                 tcg_regset_set_reg(allocated_regs, ts->reg);
3433450445d5SRichard Henderson                 ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
343469e3706dSRichard Henderson                                          allocated_regs, preferred_regs,
3435b016486eSRichard Henderson                                          ots->indirect_base);
3436c29c1d7eSAurelien Jarno             }
343778113e83SRichard Henderson             if (!tcg_out_mov(s, otype, ots->reg, ts->reg)) {
3438240c08d0SRichard Henderson                 /*
3439240c08d0SRichard Henderson                  * Cross register class move not supported.
3440240c08d0SRichard Henderson                  * Store the source register into the destination slot
3441240c08d0SRichard Henderson                  * and leave the destination temp as TEMP_VAL_MEM.
3442240c08d0SRichard Henderson                  */
3443240c08d0SRichard Henderson                 assert(!ots->fixed_reg);
3444240c08d0SRichard Henderson                 if (!ts->mem_allocated) {
3445240c08d0SRichard Henderson                     temp_allocate_frame(s, ots);
3446240c08d0SRichard Henderson                 }
3447240c08d0SRichard Henderson                 tcg_out_st(s, ts->type, ts->reg,
3448240c08d0SRichard Henderson                            ots->mem_base->reg, ots->mem_offset);
3449240c08d0SRichard Henderson                 ots->mem_coherent = 1;
3450240c08d0SRichard Henderson                 temp_free_or_dead(s, ots, -1);
3451240c08d0SRichard Henderson                 return;
345278113e83SRichard Henderson             }
3453c29c1d7eSAurelien Jarno         }
3454c896fe29Sbellard         ots->val_type = TEMP_VAL_REG;
3455c896fe29Sbellard         ots->mem_coherent = 0;
3456f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3457ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(0)) {
345898b4e186SRichard Henderson             temp_sync(s, ots, allocated_regs, 0, 0);
3459c29c1d7eSAurelien Jarno         }
3460ec7a869dSAurelien Jarno     }
3461c896fe29Sbellard }
3462c896fe29Sbellard 
3463bab1671fSRichard Henderson /*
3464bab1671fSRichard Henderson  * Specialized code generation for INDEX_op_dup_vec.
3465bab1671fSRichard Henderson  */
3466bab1671fSRichard Henderson static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
3467bab1671fSRichard Henderson {
3468bab1671fSRichard Henderson     const TCGLifeData arg_life = op->life;
3469bab1671fSRichard Henderson     TCGRegSet dup_out_regs, dup_in_regs;
3470bab1671fSRichard Henderson     TCGTemp *its, *ots;
3471bab1671fSRichard Henderson     TCGType itype, vtype;
3472d6ecb4a9SRichard Henderson     intptr_t endian_fixup;
3473bab1671fSRichard Henderson     unsigned vece;
3474bab1671fSRichard Henderson     bool ok;
3475bab1671fSRichard Henderson 
3476bab1671fSRichard Henderson     ots = arg_temp(op->args[0]);
3477bab1671fSRichard Henderson     its = arg_temp(op->args[1]);
3478bab1671fSRichard Henderson 
3479bab1671fSRichard Henderson     /* ENV should not be modified.  */
3480bab1671fSRichard Henderson     tcg_debug_assert(!ots->fixed_reg);
3481bab1671fSRichard Henderson 
3482bab1671fSRichard Henderson     itype = its->type;
3483bab1671fSRichard Henderson     vece = TCGOP_VECE(op);
3484bab1671fSRichard Henderson     vtype = TCGOP_VECL(op) + TCG_TYPE_V64;
3485bab1671fSRichard Henderson 
3486bab1671fSRichard Henderson     if (its->val_type == TEMP_VAL_CONST) {
3487bab1671fSRichard Henderson         /* Propagate constant via movi -> dupi.  */
3488bab1671fSRichard Henderson         tcg_target_ulong val = its->val;
3489bab1671fSRichard Henderson         if (IS_DEAD_ARG(1)) {
3490bab1671fSRichard Henderson             temp_dead(s, its);
3491bab1671fSRichard Henderson         }
3492bab1671fSRichard Henderson         tcg_reg_alloc_do_movi(s, ots, val, arg_life, op->output_pref[0]);
3493bab1671fSRichard Henderson         return;
3494bab1671fSRichard Henderson     }
3495bab1671fSRichard Henderson 
3496bab1671fSRichard Henderson     dup_out_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[0].u.regs;
3497bab1671fSRichard Henderson     dup_in_regs = tcg_op_defs[INDEX_op_dup_vec].args_ct[1].u.regs;
3498bab1671fSRichard Henderson 
3499bab1671fSRichard Henderson     /* Allocate the output register now.  */
3500bab1671fSRichard Henderson     if (ots->val_type != TEMP_VAL_REG) {
3501bab1671fSRichard Henderson         TCGRegSet allocated_regs = s->reserved_regs;
3502bab1671fSRichard Henderson 
3503bab1671fSRichard Henderson         if (!IS_DEAD_ARG(1) && its->val_type == TEMP_VAL_REG) {
3504bab1671fSRichard Henderson             /* Make sure to not spill the input register. */
3505bab1671fSRichard Henderson             tcg_regset_set_reg(allocated_regs, its->reg);
3506bab1671fSRichard Henderson         }
3507bab1671fSRichard Henderson         ots->reg = tcg_reg_alloc(s, dup_out_regs, allocated_regs,
3508bab1671fSRichard Henderson                                  op->output_pref[0], ots->indirect_base);
3509bab1671fSRichard Henderson         ots->val_type = TEMP_VAL_REG;
3510bab1671fSRichard Henderson         ots->mem_coherent = 0;
3511bab1671fSRichard Henderson         s->reg_to_temp[ots->reg] = ots;
3512bab1671fSRichard Henderson     }
3513bab1671fSRichard Henderson 
3514bab1671fSRichard Henderson     switch (its->val_type) {
3515bab1671fSRichard Henderson     case TEMP_VAL_REG:
3516bab1671fSRichard Henderson         /*
3517bab1671fSRichard Henderson          * The dup constriaints must be broad, covering all possible VECE.
3518bab1671fSRichard Henderson          * However, tcg_op_dup_vec() gets to see the VECE and we allow it
3519bab1671fSRichard Henderson          * to fail, indicating that extra moves are required for that case.
3520bab1671fSRichard Henderson          */
3521bab1671fSRichard Henderson         if (tcg_regset_test_reg(dup_in_regs, its->reg)) {
3522bab1671fSRichard Henderson             if (tcg_out_dup_vec(s, vtype, vece, ots->reg, its->reg)) {
3523bab1671fSRichard Henderson                 goto done;
3524bab1671fSRichard Henderson             }
3525bab1671fSRichard Henderson             /* Try again from memory or a vector input register.  */
3526bab1671fSRichard Henderson         }
3527bab1671fSRichard Henderson         if (!its->mem_coherent) {
3528bab1671fSRichard Henderson             /*
3529bab1671fSRichard Henderson              * The input register is not synced, and so an extra store
3530bab1671fSRichard Henderson              * would be required to use memory.  Attempt an integer-vector
3531bab1671fSRichard Henderson              * register move first.  We do not have a TCGRegSet for this.
3532bab1671fSRichard Henderson              */
3533bab1671fSRichard Henderson             if (tcg_out_mov(s, itype, ots->reg, its->reg)) {
3534bab1671fSRichard Henderson                 break;
3535bab1671fSRichard Henderson             }
3536bab1671fSRichard Henderson             /* Sync the temp back to its slot and load from there.  */
3537bab1671fSRichard Henderson             temp_sync(s, its, s->reserved_regs, 0, 0);
3538bab1671fSRichard Henderson         }
3539bab1671fSRichard Henderson         /* fall through */
3540bab1671fSRichard Henderson 
3541bab1671fSRichard Henderson     case TEMP_VAL_MEM:
3542d6ecb4a9SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
3543d6ecb4a9SRichard Henderson         endian_fixup = itype == TCG_TYPE_I32 ? 4 : 8;
3544d6ecb4a9SRichard Henderson         endian_fixup -= 1 << vece;
3545d6ecb4a9SRichard Henderson #else
3546d6ecb4a9SRichard Henderson         endian_fixup = 0;
3547d6ecb4a9SRichard Henderson #endif
3548d6ecb4a9SRichard Henderson         if (tcg_out_dupm_vec(s, vtype, vece, ots->reg, its->mem_base->reg,
3549d6ecb4a9SRichard Henderson                              its->mem_offset + endian_fixup)) {
3550d6ecb4a9SRichard Henderson             goto done;
3551d6ecb4a9SRichard Henderson         }
3552bab1671fSRichard Henderson         tcg_out_ld(s, itype, ots->reg, its->mem_base->reg, its->mem_offset);
3553bab1671fSRichard Henderson         break;
3554bab1671fSRichard Henderson 
3555bab1671fSRichard Henderson     default:
3556bab1671fSRichard Henderson         g_assert_not_reached();
3557bab1671fSRichard Henderson     }
3558bab1671fSRichard Henderson 
3559bab1671fSRichard Henderson     /* We now have a vector input register, so dup must succeed. */
3560bab1671fSRichard Henderson     ok = tcg_out_dup_vec(s, vtype, vece, ots->reg, ots->reg);
3561bab1671fSRichard Henderson     tcg_debug_assert(ok);
3562bab1671fSRichard Henderson 
3563bab1671fSRichard Henderson  done:
3564bab1671fSRichard Henderson     if (IS_DEAD_ARG(1)) {
3565bab1671fSRichard Henderson         temp_dead(s, its);
3566bab1671fSRichard Henderson     }
3567bab1671fSRichard Henderson     if (NEED_SYNC_ARG(0)) {
3568bab1671fSRichard Henderson         temp_sync(s, ots, s->reserved_regs, 0, 0);
3569bab1671fSRichard Henderson     }
3570bab1671fSRichard Henderson     if (IS_DEAD_ARG(0)) {
3571bab1671fSRichard Henderson         temp_dead(s, ots);
3572bab1671fSRichard Henderson     }
3573bab1671fSRichard Henderson }
3574bab1671fSRichard Henderson 
3575dd186292SRichard Henderson static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
3576c896fe29Sbellard {
3577dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3578dd186292SRichard Henderson     const TCGOpDef * const def = &tcg_op_defs[op->opc];
357982790a87SRichard Henderson     TCGRegSet i_allocated_regs;
358082790a87SRichard Henderson     TCGRegSet o_allocated_regs;
3581b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
3582b6638662SRichard Henderson     TCGReg reg;
3583c896fe29Sbellard     TCGArg arg;
3584c896fe29Sbellard     const TCGArgConstraint *arg_ct;
3585c896fe29Sbellard     TCGTemp *ts;
3586c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
3587c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
3588c896fe29Sbellard 
3589c896fe29Sbellard     nb_oargs = def->nb_oargs;
3590c896fe29Sbellard     nb_iargs = def->nb_iargs;
3591c896fe29Sbellard 
3592c896fe29Sbellard     /* copy constants */
3593c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
3594dd186292SRichard Henderson            op->args + nb_oargs + nb_iargs,
3595c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
3596c896fe29Sbellard 
3597d21369f5SRichard Henderson     i_allocated_regs = s->reserved_regs;
3598d21369f5SRichard Henderson     o_allocated_regs = s->reserved_regs;
359982790a87SRichard Henderson 
3600c896fe29Sbellard     /* satisfy input constraints */
3601c896fe29Sbellard     for (k = 0; k < nb_iargs; k++) {
3602d62816f2SRichard Henderson         TCGRegSet i_preferred_regs, o_preferred_regs;
3603d62816f2SRichard Henderson 
3604c896fe29Sbellard         i = def->sorted_args[nb_oargs + k];
3605dd186292SRichard Henderson         arg = op->args[i];
3606c896fe29Sbellard         arg_ct = &def->args_ct[i];
360743439139SRichard Henderson         ts = arg_temp(arg);
360840ae5c62SRichard Henderson 
360940ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
361040ae5c62SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct)) {
3611c896fe29Sbellard             /* constant is OK for instruction */
3612c896fe29Sbellard             const_args[i] = 1;
3613c896fe29Sbellard             new_args[i] = ts->val;
3614d62816f2SRichard Henderson             continue;
3615c896fe29Sbellard         }
361640ae5c62SRichard Henderson 
3617d62816f2SRichard Henderson         i_preferred_regs = o_preferred_regs = 0;
36185ff9d6a4Sbellard         if (arg_ct->ct & TCG_CT_IALIAS) {
3619d62816f2SRichard Henderson             o_preferred_regs = op->output_pref[arg_ct->alias_index];
36205ff9d6a4Sbellard             if (ts->fixed_reg) {
36215ff9d6a4Sbellard                 /* if fixed register, we must allocate a new register
36225ff9d6a4Sbellard                    if the alias is not the same register */
3623d62816f2SRichard Henderson                 if (arg != op->args[arg_ct->alias_index]) {
36245ff9d6a4Sbellard                     goto allocate_in_reg;
3625d62816f2SRichard Henderson                 }
36265ff9d6a4Sbellard             } else {
3627c896fe29Sbellard                 /* if the input is aliased to an output and if it is
3628c896fe29Sbellard                    not dead after the instruction, we must allocate
3629c896fe29Sbellard                    a new register and move it */
3630866cb6cbSAurelien Jarno                 if (!IS_DEAD_ARG(i)) {
3631c896fe29Sbellard                     goto allocate_in_reg;
3632c896fe29Sbellard                 }
3633d62816f2SRichard Henderson 
36347e1df267SAurelien Jarno                 /* check if the current register has already been allocated
36357e1df267SAurelien Jarno                    for another input aliased to an output */
3636d62816f2SRichard Henderson                 if (ts->val_type == TEMP_VAL_REG) {
36377e1df267SAurelien Jarno                     int k2, i2;
3638d62816f2SRichard Henderson                     reg = ts->reg;
36397e1df267SAurelien Jarno                     for (k2 = 0 ; k2 < k ; k2++) {
36407e1df267SAurelien Jarno                         i2 = def->sorted_args[nb_oargs + k2];
36417e1df267SAurelien Jarno                         if ((def->args_ct[i2].ct & TCG_CT_IALIAS) &&
3642d62816f2SRichard Henderson                             reg == new_args[i2]) {
36437e1df267SAurelien Jarno                             goto allocate_in_reg;
36447e1df267SAurelien Jarno                         }
36457e1df267SAurelien Jarno                     }
36465ff9d6a4Sbellard                 }
3647d62816f2SRichard Henderson                 i_preferred_regs = o_preferred_regs;
3648866cb6cbSAurelien Jarno             }
3649d62816f2SRichard Henderson         }
3650d62816f2SRichard Henderson 
3651d62816f2SRichard Henderson         temp_load(s, ts, arg_ct->u.regs, i_allocated_regs, i_preferred_regs);
3652c896fe29Sbellard         reg = ts->reg;
3653d62816f2SRichard Henderson 
3654c896fe29Sbellard         if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
3655c896fe29Sbellard             /* nothing to do : the constraint is satisfied */
3656c896fe29Sbellard         } else {
3657c896fe29Sbellard         allocate_in_reg:
3658c896fe29Sbellard             /* allocate a new register matching the constraint
3659c896fe29Sbellard                and move the temporary register into it */
3660d62816f2SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
3661d62816f2SRichard Henderson                       i_allocated_regs, 0);
366282790a87SRichard Henderson             reg = tcg_reg_alloc(s, arg_ct->u.regs, i_allocated_regs,
3663d62816f2SRichard Henderson                                 o_preferred_regs, ts->indirect_base);
366478113e83SRichard Henderson             if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
3665240c08d0SRichard Henderson                 /*
3666240c08d0SRichard Henderson                  * Cross register class move not supported.  Sync the
3667240c08d0SRichard Henderson                  * temp back to its slot and load from there.
3668240c08d0SRichard Henderson                  */
3669240c08d0SRichard Henderson                 temp_sync(s, ts, i_allocated_regs, 0, 0);
3670240c08d0SRichard Henderson                 tcg_out_ld(s, ts->type, reg,
3671240c08d0SRichard Henderson                            ts->mem_base->reg, ts->mem_offset);
367278113e83SRichard Henderson             }
3673c896fe29Sbellard         }
3674c896fe29Sbellard         new_args[i] = reg;
3675c896fe29Sbellard         const_args[i] = 0;
367682790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
3677c896fe29Sbellard     }
3678c896fe29Sbellard 
3679c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
3680866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
3681866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
368243439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
3683c896fe29Sbellard         }
3684c896fe29Sbellard     }
3685c896fe29Sbellard 
3686a52ad07eSAurelien Jarno     if (def->flags & TCG_OPF_BB_END) {
368782790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
3688a52ad07eSAurelien Jarno     } else {
3689c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
3690b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
3691c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
3692c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
369382790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
3694c896fe29Sbellard                 }
3695c896fe29Sbellard             }
36963d5c5f87SAurelien Jarno         }
36973d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
36983d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
36993d5c5f87SAurelien Jarno                an exception. */
370082790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
3701c896fe29Sbellard         }
3702c896fe29Sbellard 
3703c896fe29Sbellard         /* satisfy the output constraints */
3704c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
3705c896fe29Sbellard             i = def->sorted_args[k];
3706dd186292SRichard Henderson             arg = op->args[i];
3707c896fe29Sbellard             arg_ct = &def->args_ct[i];
370843439139SRichard Henderson             ts = arg_temp(arg);
3709d63e3b6eSRichard Henderson 
3710d63e3b6eSRichard Henderson             /* ENV should not be modified.  */
3711d63e3b6eSRichard Henderson             tcg_debug_assert(!ts->fixed_reg);
3712d63e3b6eSRichard Henderson 
371317280ff4SRichard Henderson             if ((arg_ct->ct & TCG_CT_ALIAS)
371417280ff4SRichard Henderson                 && !const_args[arg_ct->alias_index]) {
37155ff9d6a4Sbellard                 reg = new_args[arg_ct->alias_index];
371682790a87SRichard Henderson             } else if (arg_ct->ct & TCG_CT_NEWREG) {
371782790a87SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->u.regs,
371882790a87SRichard Henderson                                     i_allocated_regs | o_allocated_regs,
371969e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
3720c896fe29Sbellard             } else {
372182790a87SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->u.regs, o_allocated_regs,
372269e3706dSRichard Henderson                                     op->output_pref[k], ts->indirect_base);
3723c896fe29Sbellard             }
372482790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
3725639368ddSAurelien Jarno             if (ts->val_type == TEMP_VAL_REG) {
3726f8b2f202SRichard Henderson                 s->reg_to_temp[ts->reg] = NULL;
3727639368ddSAurelien Jarno             }
3728c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
3729c896fe29Sbellard             ts->reg = reg;
3730d63e3b6eSRichard Henderson             /*
3731d63e3b6eSRichard Henderson              * Temp value is modified, so the value kept in memory is
3732d63e3b6eSRichard Henderson              * potentially not the same.
3733d63e3b6eSRichard Henderson              */
3734c896fe29Sbellard             ts->mem_coherent = 0;
3735f8b2f202SRichard Henderson             s->reg_to_temp[reg] = ts;
3736c896fe29Sbellard             new_args[i] = reg;
3737c896fe29Sbellard         }
3738e8996ee0Sbellard     }
3739c896fe29Sbellard 
3740c896fe29Sbellard     /* emit instruction */
3741d2fd745fSRichard Henderson     if (def->flags & TCG_OPF_VECTOR) {
3742d2fd745fSRichard Henderson         tcg_out_vec_op(s, op->opc, TCGOP_VECL(op), TCGOP_VECE(op),
3743d2fd745fSRichard Henderson                        new_args, const_args);
3744d2fd745fSRichard Henderson     } else {
3745dd186292SRichard Henderson         tcg_out_op(s, op->opc, new_args, const_args);
3746d2fd745fSRichard Henderson     }
3747c896fe29Sbellard 
3748c896fe29Sbellard     /* move the outputs in the correct register if needed */
3749c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
375043439139SRichard Henderson         ts = arg_temp(op->args[i]);
3751d63e3b6eSRichard Henderson 
3752d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
3753d63e3b6eSRichard Henderson         tcg_debug_assert(!ts->fixed_reg);
3754d63e3b6eSRichard Henderson 
3755ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
375698b4e186SRichard Henderson             temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
375759d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
3758f8bf00f1SRichard Henderson             temp_dead(s, ts);
3759ec7a869dSAurelien Jarno         }
3760c896fe29Sbellard     }
3761c896fe29Sbellard }
3762c896fe29Sbellard 
3763b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP
3764b03cce8eSbellard #define STACK_DIR(x) (-(x))
3765b03cce8eSbellard #else
3766b03cce8eSbellard #define STACK_DIR(x) (x)
3767b03cce8eSbellard #endif
3768b03cce8eSbellard 
3769dd186292SRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
3770c896fe29Sbellard {
3771cd9090aaSRichard Henderson     const int nb_oargs = TCGOP_CALLO(op);
3772cd9090aaSRichard Henderson     const int nb_iargs = TCGOP_CALLI(op);
3773dd186292SRichard Henderson     const TCGLifeData arg_life = op->life;
3774b6638662SRichard Henderson     int flags, nb_regs, i;
3775b6638662SRichard Henderson     TCGReg reg;
3776cf066674SRichard Henderson     TCGArg arg;
3777c896fe29Sbellard     TCGTemp *ts;
3778d3452f1fSRichard Henderson     intptr_t stack_offset;
3779d3452f1fSRichard Henderson     size_t call_stack_size;
3780cf066674SRichard Henderson     tcg_insn_unit *func_addr;
3781cf066674SRichard Henderson     int allocate_args;
3782c896fe29Sbellard     TCGRegSet allocated_regs;
3783c896fe29Sbellard 
3784dd186292SRichard Henderson     func_addr = (tcg_insn_unit *)(intptr_t)op->args[nb_oargs + nb_iargs];
3785dd186292SRichard Henderson     flags = op->args[nb_oargs + nb_iargs + 1];
3786c896fe29Sbellard 
37876e17d0c5SStefan Weil     nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
3788c45cb8bbSRichard Henderson     if (nb_regs > nb_iargs) {
3789c45cb8bbSRichard Henderson         nb_regs = nb_iargs;
3790cf066674SRichard Henderson     }
3791c896fe29Sbellard 
3792c896fe29Sbellard     /* assign stack slots first */
3793c45cb8bbSRichard Henderson     call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long);
3794c896fe29Sbellard     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
3795c896fe29Sbellard         ~(TCG_TARGET_STACK_ALIGN - 1);
3796b03cce8eSbellard     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
3797b03cce8eSbellard     if (allocate_args) {
3798345649c0SBlue Swirl         /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
3799345649c0SBlue Swirl            preallocate call stack */
3800345649c0SBlue Swirl         tcg_abort();
3801b03cce8eSbellard     }
380239cf05d3Sbellard 
380339cf05d3Sbellard     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
3804c45cb8bbSRichard Henderson     for (i = nb_regs; i < nb_iargs; i++) {
3805dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
380639cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP
380739cf05d3Sbellard         stack_offset -= sizeof(tcg_target_long);
380839cf05d3Sbellard #endif
380939cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
381043439139SRichard Henderson             ts = arg_temp(arg);
381140ae5c62SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
3812b722452aSRichard Henderson                       s->reserved_regs, 0);
3813e4d5434cSblueswir1             tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
381439cf05d3Sbellard         }
381539cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP
381639cf05d3Sbellard         stack_offset += sizeof(tcg_target_long);
381739cf05d3Sbellard #endif
3818c896fe29Sbellard     }
3819c896fe29Sbellard 
3820c896fe29Sbellard     /* assign input registers */
3821d21369f5SRichard Henderson     allocated_regs = s->reserved_regs;
3822c896fe29Sbellard     for (i = 0; i < nb_regs; i++) {
3823dd186292SRichard Henderson         arg = op->args[nb_oargs + i];
382439cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
382543439139SRichard Henderson             ts = arg_temp(arg);
3826c896fe29Sbellard             reg = tcg_target_call_iarg_regs[i];
382740ae5c62SRichard Henderson 
3828c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
3829c896fe29Sbellard                 if (ts->reg != reg) {
38304250da10SRichard Henderson                     tcg_reg_free(s, reg, allocated_regs);
383178113e83SRichard Henderson                     if (!tcg_out_mov(s, ts->type, reg, ts->reg)) {
3832240c08d0SRichard Henderson                         /*
3833240c08d0SRichard Henderson                          * Cross register class move not supported.  Sync the
3834240c08d0SRichard Henderson                          * temp back to its slot and load from there.
3835240c08d0SRichard Henderson                          */
3836240c08d0SRichard Henderson                         temp_sync(s, ts, allocated_regs, 0, 0);
3837240c08d0SRichard Henderson                         tcg_out_ld(s, ts->type, reg,
3838240c08d0SRichard Henderson                                    ts->mem_base->reg, ts->mem_offset);
383978113e83SRichard Henderson                     }
3840c896fe29Sbellard                 }
3841c896fe29Sbellard             } else {
3842ccb1bb66SRichard Henderson                 TCGRegSet arg_set = 0;
384340ae5c62SRichard Henderson 
38444250da10SRichard Henderson                 tcg_reg_free(s, reg, allocated_regs);
384540ae5c62SRichard Henderson                 tcg_regset_set_reg(arg_set, reg);
3846b722452aSRichard Henderson                 temp_load(s, ts, arg_set, allocated_regs, 0);
3847c896fe29Sbellard             }
384840ae5c62SRichard Henderson 
3849c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
3850c896fe29Sbellard         }
385139cf05d3Sbellard     }
3852c896fe29Sbellard 
3853c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
3854866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
3855866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
385643439139SRichard Henderson             temp_dead(s, arg_temp(op->args[i]));
3857c896fe29Sbellard         }
3858c896fe29Sbellard     }
3859c896fe29Sbellard 
3860c896fe29Sbellard     /* clobber call registers */
3861c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
3862c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
3863b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
3864c896fe29Sbellard         }
3865c896fe29Sbellard     }
3866c896fe29Sbellard 
386778505279SAurelien Jarno     /* Save globals if they might be written by the helper, sync them if
386878505279SAurelien Jarno        they might be read. */
386978505279SAurelien Jarno     if (flags & TCG_CALL_NO_READ_GLOBALS) {
387078505279SAurelien Jarno         /* Nothing to do */
387178505279SAurelien Jarno     } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) {
387278505279SAurelien Jarno         sync_globals(s, allocated_regs);
387378505279SAurelien Jarno     } else {
3874e8996ee0Sbellard         save_globals(s, allocated_regs);
3875b9c18f56Saurel32     }
3876c896fe29Sbellard 
3877cf066674SRichard Henderson     tcg_out_call(s, func_addr);
3878c896fe29Sbellard 
3879c896fe29Sbellard     /* assign output registers and emit moves if needed */
3880c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
3881dd186292SRichard Henderson         arg = op->args[i];
388243439139SRichard Henderson         ts = arg_temp(arg);
3883d63e3b6eSRichard Henderson 
3884d63e3b6eSRichard Henderson         /* ENV should not be modified.  */
3885d63e3b6eSRichard Henderson         tcg_debug_assert(!ts->fixed_reg);
3886d63e3b6eSRichard Henderson 
3887c896fe29Sbellard         reg = tcg_target_call_oarg_regs[i];
3888eabb7b91SAurelien Jarno         tcg_debug_assert(s->reg_to_temp[reg] == NULL);
3889639368ddSAurelien Jarno         if (ts->val_type == TEMP_VAL_REG) {
3890f8b2f202SRichard Henderson             s->reg_to_temp[ts->reg] = NULL;
3891639368ddSAurelien Jarno         }
3892c896fe29Sbellard         ts->val_type = TEMP_VAL_REG;
3893c896fe29Sbellard         ts->reg = reg;
3894c896fe29Sbellard         ts->mem_coherent = 0;
3895f8b2f202SRichard Henderson         s->reg_to_temp[reg] = ts;
3896ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
389798b4e186SRichard Henderson             temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i));
389859d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
3899f8bf00f1SRichard Henderson             temp_dead(s, ts);
3900c896fe29Sbellard         }
3901c896fe29Sbellard     }
39028c11ad25SAurelien Jarno }
3903c896fe29Sbellard 
3904c896fe29Sbellard #ifdef CONFIG_PROFILER
3905c896fe29Sbellard 
3906c3fac113SEmilio G. Cota /* avoid copy/paste errors */
3907c3fac113SEmilio G. Cota #define PROF_ADD(to, from, field)                       \
3908c3fac113SEmilio G. Cota     do {                                                \
3909c3fac113SEmilio G. Cota         (to)->field += atomic_read(&((from)->field));   \
3910c3fac113SEmilio G. Cota     } while (0)
3911c896fe29Sbellard 
3912c3fac113SEmilio G. Cota #define PROF_MAX(to, from, field)                                       \
3913c3fac113SEmilio G. Cota     do {                                                                \
3914c3fac113SEmilio G. Cota         typeof((from)->field) val__ = atomic_read(&((from)->field));    \
3915c3fac113SEmilio G. Cota         if (val__ > (to)->field) {                                      \
3916c3fac113SEmilio G. Cota             (to)->field = val__;                                        \
3917c3fac113SEmilio G. Cota         }                                                               \
3918c3fac113SEmilio G. Cota     } while (0)
3919c3fac113SEmilio G. Cota 
3920c3fac113SEmilio G. Cota /* Pass in a zero'ed @prof */
3921c3fac113SEmilio G. Cota static inline
3922c3fac113SEmilio G. Cota void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
3923c896fe29Sbellard {
39243468b59eSEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
3925c3fac113SEmilio G. Cota     unsigned int i;
3926c3fac113SEmilio G. Cota 
39273468b59eSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
39283468b59eSEmilio G. Cota         TCGContext *s = atomic_read(&tcg_ctxs[i]);
39293468b59eSEmilio G. Cota         const TCGProfile *orig = &s->prof;
3930c3fac113SEmilio G. Cota 
3931c3fac113SEmilio G. Cota         if (counters) {
393272fd2efbSEmilio G. Cota             PROF_ADD(prof, orig, cpu_exec_time);
3933c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count1);
3934c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, tb_count);
3935c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, op_count);
3936c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, op_count_max);
3937c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, temp_count);
3938c3fac113SEmilio G. Cota             PROF_MAX(prof, orig, temp_count_max);
3939c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, del_op_count);
3940c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_in_len);
3941c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_out_len);
3942c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, search_out_len);
3943c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, interm_time);
3944c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, code_time);
3945c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, la_time);
3946c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, opt_time);
3947c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_count);
3948c3fac113SEmilio G. Cota             PROF_ADD(prof, orig, restore_time);
3949c3fac113SEmilio G. Cota         }
3950c3fac113SEmilio G. Cota         if (table) {
3951c896fe29Sbellard             int i;
3952d70724ceSzhanghailiang 
395315fc7daaSRichard Henderson             for (i = 0; i < NB_OPS; i++) {
3954c3fac113SEmilio G. Cota                 PROF_ADD(prof, orig, table_op_count[i]);
3955c3fac113SEmilio G. Cota             }
3956c3fac113SEmilio G. Cota         }
3957c3fac113SEmilio G. Cota     }
3958c3fac113SEmilio G. Cota }
3959c3fac113SEmilio G. Cota 
3960c3fac113SEmilio G. Cota #undef PROF_ADD
3961c3fac113SEmilio G. Cota #undef PROF_MAX
3962c3fac113SEmilio G. Cota 
3963c3fac113SEmilio G. Cota static void tcg_profile_snapshot_counters(TCGProfile *prof)
3964c3fac113SEmilio G. Cota {
3965c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, true, false);
3966c3fac113SEmilio G. Cota }
3967c3fac113SEmilio G. Cota 
3968c3fac113SEmilio G. Cota static void tcg_profile_snapshot_table(TCGProfile *prof)
3969c3fac113SEmilio G. Cota {
3970c3fac113SEmilio G. Cota     tcg_profile_snapshot(prof, false, true);
3971c3fac113SEmilio G. Cota }
3972c3fac113SEmilio G. Cota 
3973d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
3974c3fac113SEmilio G. Cota {
3975c3fac113SEmilio G. Cota     TCGProfile prof = {};
3976c3fac113SEmilio G. Cota     int i;
3977c3fac113SEmilio G. Cota 
3978c3fac113SEmilio G. Cota     tcg_profile_snapshot_table(&prof);
3979c3fac113SEmilio G. Cota     for (i = 0; i < NB_OPS; i++) {
3980d4c51a0aSMarkus Armbruster         qemu_printf("%s %" PRId64 "\n", tcg_op_defs[i].name,
3981c3fac113SEmilio G. Cota                     prof.table_op_count[i]);
3982c896fe29Sbellard     }
3983c896fe29Sbellard }
398472fd2efbSEmilio G. Cota 
398572fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
398672fd2efbSEmilio G. Cota {
398772fd2efbSEmilio G. Cota     unsigned int n_ctxs = atomic_read(&n_tcg_ctxs);
398872fd2efbSEmilio G. Cota     unsigned int i;
398972fd2efbSEmilio G. Cota     int64_t ret = 0;
399072fd2efbSEmilio G. Cota 
399172fd2efbSEmilio G. Cota     for (i = 0; i < n_ctxs; i++) {
399272fd2efbSEmilio G. Cota         const TCGContext *s = atomic_read(&tcg_ctxs[i]);
399372fd2efbSEmilio G. Cota         const TCGProfile *prof = &s->prof;
399472fd2efbSEmilio G. Cota 
399572fd2efbSEmilio G. Cota         ret += atomic_read(&prof->cpu_exec_time);
399672fd2efbSEmilio G. Cota     }
399772fd2efbSEmilio G. Cota     return ret;
399872fd2efbSEmilio G. Cota }
3999246ae24dSMax Filippov #else
4000d4c51a0aSMarkus Armbruster void tcg_dump_op_count(void)
4001246ae24dSMax Filippov {
4002d4c51a0aSMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4003246ae24dSMax Filippov }
400472fd2efbSEmilio G. Cota 
400572fd2efbSEmilio G. Cota int64_t tcg_cpu_exec_time(void)
400672fd2efbSEmilio G. Cota {
400772fd2efbSEmilio G. Cota     error_report("%s: TCG profiler not compiled", __func__);
400872fd2efbSEmilio G. Cota     exit(EXIT_FAILURE);
400972fd2efbSEmilio G. Cota }
4010c896fe29Sbellard #endif
4011c896fe29Sbellard 
4012c896fe29Sbellard 
40135bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
4014c896fe29Sbellard {
4015c3fac113SEmilio G. Cota #ifdef CONFIG_PROFILER
4016c3fac113SEmilio G. Cota     TCGProfile *prof = &s->prof;
4017c3fac113SEmilio G. Cota #endif
401815fa08f8SRichard Henderson     int i, num_insns;
401915fa08f8SRichard Henderson     TCGOp *op;
4020c896fe29Sbellard 
402104fe6400SRichard Henderson #ifdef CONFIG_PROFILER
402204fe6400SRichard Henderson     {
4023c1f543b7SEmilio G. Cota         int n = 0;
402404fe6400SRichard Henderson 
402515fa08f8SRichard Henderson         QTAILQ_FOREACH(op, &s->ops, link) {
402615fa08f8SRichard Henderson             n++;
402715fa08f8SRichard Henderson         }
4028c3fac113SEmilio G. Cota         atomic_set(&prof->op_count, prof->op_count + n);
4029c3fac113SEmilio G. Cota         if (n > prof->op_count_max) {
4030c3fac113SEmilio G. Cota             atomic_set(&prof->op_count_max, n);
403104fe6400SRichard Henderson         }
403204fe6400SRichard Henderson 
403304fe6400SRichard Henderson         n = s->nb_temps;
4034c3fac113SEmilio G. Cota         atomic_set(&prof->temp_count, prof->temp_count + n);
4035c3fac113SEmilio G. Cota         if (n > prof->temp_count_max) {
4036c3fac113SEmilio G. Cota             atomic_set(&prof->temp_count_max, n);
403704fe6400SRichard Henderson         }
403804fe6400SRichard Henderson     }
403904fe6400SRichard Henderson #endif
404004fe6400SRichard Henderson 
4041c896fe29Sbellard #ifdef DEBUG_DISAS
4042d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
4043d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
40441ee73216SRichard Henderson         qemu_log_lock();
404593fcfe39Saliguori         qemu_log("OP:\n");
40461894f69aSRichard Henderson         tcg_dump_ops(s, false);
404793fcfe39Saliguori         qemu_log("\n");
40481ee73216SRichard Henderson         qemu_log_unlock();
4049c896fe29Sbellard     }
4050c896fe29Sbellard #endif
4051c896fe29Sbellard 
4052bef16ab4SRichard Henderson #ifdef CONFIG_DEBUG_TCG
4053bef16ab4SRichard Henderson     /* Ensure all labels referenced have been emitted.  */
4054bef16ab4SRichard Henderson     {
4055bef16ab4SRichard Henderson         TCGLabel *l;
4056bef16ab4SRichard Henderson         bool error = false;
4057bef16ab4SRichard Henderson 
4058bef16ab4SRichard Henderson         QSIMPLEQ_FOREACH(l, &s->labels, next) {
4059bef16ab4SRichard Henderson             if (unlikely(!l->present) && l->refs) {
4060bef16ab4SRichard Henderson                 qemu_log_mask(CPU_LOG_TB_OP,
4061bef16ab4SRichard Henderson                               "$L%d referenced but not present.\n", l->id);
4062bef16ab4SRichard Henderson                 error = true;
4063bef16ab4SRichard Henderson             }
4064bef16ab4SRichard Henderson         }
4065bef16ab4SRichard Henderson         assert(!error);
4066bef16ab4SRichard Henderson     }
4067bef16ab4SRichard Henderson #endif
4068bef16ab4SRichard Henderson 
4069c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
4070c3fac113SEmilio G. Cota     atomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
4071c5cc28ffSAurelien Jarno #endif
4072c5cc28ffSAurelien Jarno 
40738f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
4074c45cb8bbSRichard Henderson     tcg_optimize(s);
40758f2e8c07SKirill Batuzov #endif
40768f2e8c07SKirill Batuzov 
4077a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4078c3fac113SEmilio G. Cota     atomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
4079c3fac113SEmilio G. Cota     atomic_set(&prof->la_time, prof->la_time - profile_getclock());
4080a23a9ec6Sbellard #endif
4081c5cc28ffSAurelien Jarno 
4082b4fc67c7SRichard Henderson     reachable_code_pass(s);
4083b83eabeaSRichard Henderson     liveness_pass_1(s);
40845a18407fSRichard Henderson 
40855a18407fSRichard Henderson     if (s->nb_indirects > 0) {
40865a18407fSRichard Henderson #ifdef DEBUG_DISAS
40875a18407fSRichard Henderson         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
40885a18407fSRichard Henderson                      && qemu_log_in_addr_range(tb->pc))) {
40891ee73216SRichard Henderson             qemu_log_lock();
40905a18407fSRichard Henderson             qemu_log("OP before indirect lowering:\n");
40911894f69aSRichard Henderson             tcg_dump_ops(s, false);
40925a18407fSRichard Henderson             qemu_log("\n");
40931ee73216SRichard Henderson             qemu_log_unlock();
40945a18407fSRichard Henderson         }
40955a18407fSRichard Henderson #endif
40965a18407fSRichard Henderson         /* Replace indirect temps with direct temps.  */
4097b83eabeaSRichard Henderson         if (liveness_pass_2(s)) {
40985a18407fSRichard Henderson             /* If changes were made, re-run liveness.  */
4099b83eabeaSRichard Henderson             liveness_pass_1(s);
41005a18407fSRichard Henderson         }
41015a18407fSRichard Henderson     }
4102c5cc28ffSAurelien Jarno 
4103a23a9ec6Sbellard #ifdef CONFIG_PROFILER
4104c3fac113SEmilio G. Cota     atomic_set(&prof->la_time, prof->la_time + profile_getclock());
4105a23a9ec6Sbellard #endif
4106c896fe29Sbellard 
4107c896fe29Sbellard #ifdef DEBUG_DISAS
4108d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
4109d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
41101ee73216SRichard Henderson         qemu_log_lock();
4111c5cc28ffSAurelien Jarno         qemu_log("OP after optimization and liveness analysis:\n");
41121894f69aSRichard Henderson         tcg_dump_ops(s, true);
411393fcfe39Saliguori         qemu_log("\n");
41141ee73216SRichard Henderson         qemu_log_unlock();
4115c896fe29Sbellard     }
4116c896fe29Sbellard #endif
4117c896fe29Sbellard 
4118c896fe29Sbellard     tcg_reg_alloc_start(s);
4119c896fe29Sbellard 
4120e7e168f4SEmilio G. Cota     s->code_buf = tb->tc.ptr;
4121e7e168f4SEmilio G. Cota     s->code_ptr = tb->tc.ptr;
4122c896fe29Sbellard 
4123659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
41246001f772SLaurent Vivier     QSIMPLEQ_INIT(&s->ldst_labels);
4125659ef5cbSRichard Henderson #endif
412657a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
412757a26946SRichard Henderson     s->pool_labels = NULL;
412857a26946SRichard Henderson #endif
41299ecefc84SRichard Henderson 
4130fca8a500SRichard Henderson     num_insns = -1;
413115fa08f8SRichard Henderson     QTAILQ_FOREACH(op, &s->ops, link) {
4132c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
4133b3db8758Sblueswir1 
4134c896fe29Sbellard #ifdef CONFIG_PROFILER
4135c3fac113SEmilio G. Cota         atomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
4136c896fe29Sbellard #endif
4137c45cb8bbSRichard Henderson 
4138c896fe29Sbellard         switch (opc) {
4139c896fe29Sbellard         case INDEX_op_mov_i32:
4140c896fe29Sbellard         case INDEX_op_mov_i64:
4141d2fd745fSRichard Henderson         case INDEX_op_mov_vec:
4142dd186292SRichard Henderson             tcg_reg_alloc_mov(s, op);
4143c896fe29Sbellard             break;
4144e8996ee0Sbellard         case INDEX_op_movi_i32:
4145e8996ee0Sbellard         case INDEX_op_movi_i64:
4146d2fd745fSRichard Henderson         case INDEX_op_dupi_vec:
4147dd186292SRichard Henderson             tcg_reg_alloc_movi(s, op);
4148e8996ee0Sbellard             break;
4149bab1671fSRichard Henderson         case INDEX_op_dup_vec:
4150bab1671fSRichard Henderson             tcg_reg_alloc_dup(s, op);
4151bab1671fSRichard Henderson             break;
4152765b842aSRichard Henderson         case INDEX_op_insn_start:
4153fca8a500SRichard Henderson             if (num_insns >= 0) {
41549f754620SRichard Henderson                 size_t off = tcg_current_code_size(s);
41559f754620SRichard Henderson                 s->gen_insn_end_off[num_insns] = off;
41569f754620SRichard Henderson                 /* Assert that we do not overflow our stored offset.  */
41579f754620SRichard Henderson                 assert(s->gen_insn_end_off[num_insns] == off);
4158fca8a500SRichard Henderson             }
4159fca8a500SRichard Henderson             num_insns++;
4160bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
4161bad729e2SRichard Henderson                 target_ulong a;
4162bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
4163efee3746SRichard Henderson                 a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]);
4164bad729e2SRichard Henderson #else
4165efee3746SRichard Henderson                 a = op->args[i];
4166bad729e2SRichard Henderson #endif
4167fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
4168bad729e2SRichard Henderson             }
4169c896fe29Sbellard             break;
41705ff9d6a4Sbellard         case INDEX_op_discard:
417143439139SRichard Henderson             temp_dead(s, arg_temp(op->args[0]));
41725ff9d6a4Sbellard             break;
4173c896fe29Sbellard         case INDEX_op_set_label:
4174e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
4175efee3746SRichard Henderson             tcg_out_label(s, arg_label(op->args[0]), s->code_ptr);
4176c896fe29Sbellard             break;
4177c896fe29Sbellard         case INDEX_op_call:
4178dd186292SRichard Henderson             tcg_reg_alloc_call(s, op);
4179c45cb8bbSRichard Henderson             break;
4180c896fe29Sbellard         default:
418125c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
4182be0f34b5SRichard Henderson             tcg_debug_assert(tcg_op_supported(opc));
4183c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
4184c896fe29Sbellard                faster to have specialized register allocator functions for
4185c896fe29Sbellard                some common argument patterns */
4186dd186292SRichard Henderson             tcg_reg_alloc_op(s, op);
4187c896fe29Sbellard             break;
4188c896fe29Sbellard         }
41898d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
4190c896fe29Sbellard         check_regs(s);
4191c896fe29Sbellard #endif
4192b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
4193b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
4194b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
4195b125f9dcSRichard Henderson            generating code without having to check during generation.  */
4196644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
4197b125f9dcSRichard Henderson             return -1;
4198b125f9dcSRichard Henderson         }
41996e6c4efeSRichard Henderson         /* Test for TB overflow, as seen by gen_insn_end_off.  */
42006e6c4efeSRichard Henderson         if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
42016e6c4efeSRichard Henderson             return -2;
42026e6c4efeSRichard Henderson         }
4203c896fe29Sbellard     }
4204fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
4205fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
4206c45cb8bbSRichard Henderson 
4207b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
4208659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
4209aeee05f5SRichard Henderson     i = tcg_out_ldst_finalize(s);
4210aeee05f5SRichard Henderson     if (i < 0) {
4211aeee05f5SRichard Henderson         return i;
421223dceda6SRichard Henderson     }
4213659ef5cbSRichard Henderson #endif
421457a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
42151768987bSRichard Henderson     i = tcg_out_pool_finalize(s);
42161768987bSRichard Henderson     if (i < 0) {
42171768987bSRichard Henderson         return i;
421857a26946SRichard Henderson     }
421957a26946SRichard Henderson #endif
42207ecd02a0SRichard Henderson     if (!tcg_resolve_relocs(s)) {
42217ecd02a0SRichard Henderson         return -2;
42227ecd02a0SRichard Henderson     }
4223c896fe29Sbellard 
4224c896fe29Sbellard     /* flush instruction cache */
42251813e175SRichard Henderson     flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr);
42262aeabc08SStefan Weil 
42271813e175SRichard Henderson     return tcg_current_code_size(s);
4228c896fe29Sbellard }
4229c896fe29Sbellard 
4230a23a9ec6Sbellard #ifdef CONFIG_PROFILER
42313de2faa9SMarkus Armbruster void tcg_dump_info(void)
4232a23a9ec6Sbellard {
4233c3fac113SEmilio G. Cota     TCGProfile prof = {};
4234c3fac113SEmilio G. Cota     const TCGProfile *s;
4235c3fac113SEmilio G. Cota     int64_t tb_count;
4236c3fac113SEmilio G. Cota     int64_t tb_div_count;
4237c3fac113SEmilio G. Cota     int64_t tot;
4238c3fac113SEmilio G. Cota 
4239c3fac113SEmilio G. Cota     tcg_profile_snapshot_counters(&prof);
4240c3fac113SEmilio G. Cota     s = &prof;
4241c3fac113SEmilio G. Cota     tb_count = s->tb_count;
4242c3fac113SEmilio G. Cota     tb_div_count = tb_count ? tb_count : 1;
4243c3fac113SEmilio G. Cota     tot = s->interm_time + s->code_time;
4244a23a9ec6Sbellard 
42453de2faa9SMarkus Armbruster     qemu_printf("JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
4246a23a9ec6Sbellard                 tot, tot / 2.4e9);
42473de2faa9SMarkus Armbruster     qemu_printf("translated TBs      %" PRId64 " (aborted=%" PRId64
42483de2faa9SMarkus Armbruster                 " %0.1f%%)\n",
4249fca8a500SRichard Henderson                 tb_count, s->tb_count1 - tb_count,
4250fca8a500SRichard Henderson                 (double)(s->tb_count1 - s->tb_count)
4251fca8a500SRichard Henderson                 / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
42523de2faa9SMarkus Armbruster     qemu_printf("avg ops/TB          %0.1f max=%d\n",
4253fca8a500SRichard Henderson                 (double)s->op_count / tb_div_count, s->op_count_max);
42543de2faa9SMarkus Armbruster     qemu_printf("deleted ops/TB      %0.2f\n",
4255fca8a500SRichard Henderson                 (double)s->del_op_count / tb_div_count);
42563de2faa9SMarkus Armbruster     qemu_printf("avg temps/TB        %0.2f max=%d\n",
4257fca8a500SRichard Henderson                 (double)s->temp_count / tb_div_count, s->temp_count_max);
42583de2faa9SMarkus Armbruster     qemu_printf("avg host code/TB    %0.1f\n",
4259fca8a500SRichard Henderson                 (double)s->code_out_len / tb_div_count);
42603de2faa9SMarkus Armbruster     qemu_printf("avg search data/TB  %0.1f\n",
4261fca8a500SRichard Henderson                 (double)s->search_out_len / tb_div_count);
4262a23a9ec6Sbellard 
42633de2faa9SMarkus Armbruster     qemu_printf("cycles/op           %0.1f\n",
4264a23a9ec6Sbellard                 s->op_count ? (double)tot / s->op_count : 0);
42653de2faa9SMarkus Armbruster     qemu_printf("cycles/in byte      %0.1f\n",
4266a23a9ec6Sbellard                 s->code_in_len ? (double)tot / s->code_in_len : 0);
42673de2faa9SMarkus Armbruster     qemu_printf("cycles/out byte     %0.1f\n",
4268a23a9ec6Sbellard                 s->code_out_len ? (double)tot / s->code_out_len : 0);
42693de2faa9SMarkus Armbruster     qemu_printf("cycles/search byte     %0.1f\n",
4270fca8a500SRichard Henderson                 s->search_out_len ? (double)tot / s->search_out_len : 0);
4271fca8a500SRichard Henderson     if (tot == 0) {
4272a23a9ec6Sbellard         tot = 1;
4273fca8a500SRichard Henderson     }
42743de2faa9SMarkus Armbruster     qemu_printf("  gen_interm time   %0.1f%%\n",
4275a23a9ec6Sbellard                 (double)s->interm_time / tot * 100.0);
42763de2faa9SMarkus Armbruster     qemu_printf("  gen_code time     %0.1f%%\n",
4277a23a9ec6Sbellard                 (double)s->code_time / tot * 100.0);
42783de2faa9SMarkus Armbruster     qemu_printf("optim./code time    %0.1f%%\n",
4279c5cc28ffSAurelien Jarno                 (double)s->opt_time / (s->code_time ? s->code_time : 1)
4280c5cc28ffSAurelien Jarno                 * 100.0);
42813de2faa9SMarkus Armbruster     qemu_printf("liveness/code time  %0.1f%%\n",
4282a23a9ec6Sbellard                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
42833de2faa9SMarkus Armbruster     qemu_printf("cpu_restore count   %" PRId64 "\n",
4284a23a9ec6Sbellard                 s->restore_count);
42853de2faa9SMarkus Armbruster     qemu_printf("  avg cycles        %0.1f\n",
4286a23a9ec6Sbellard                 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
4287a23a9ec6Sbellard }
4288a23a9ec6Sbellard #else
42893de2faa9SMarkus Armbruster void tcg_dump_info(void)
4290a23a9ec6Sbellard {
42913de2faa9SMarkus Armbruster     qemu_printf("[TCG profiler not compiled]\n");
4292a23a9ec6Sbellard }
4293a23a9ec6Sbellard #endif
4294813da627SRichard Henderson 
4295813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
42965872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
42975872bbf2SRichard Henderson 
42985872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
42995872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
43005872bbf2SRichard Henderson 
43015872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
43025872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
43035872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
43045872bbf2SRichard Henderson 
43055872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
43065872bbf2SRichard Henderson */
4307813da627SRichard Henderson 
4308813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
4309813da627SRichard Henderson typedef enum {
4310813da627SRichard Henderson     JIT_NOACTION = 0,
4311813da627SRichard Henderson     JIT_REGISTER_FN,
4312813da627SRichard Henderson     JIT_UNREGISTER_FN
4313813da627SRichard Henderson } jit_actions_t;
4314813da627SRichard Henderson 
4315813da627SRichard Henderson struct jit_code_entry {
4316813da627SRichard Henderson     struct jit_code_entry *next_entry;
4317813da627SRichard Henderson     struct jit_code_entry *prev_entry;
4318813da627SRichard Henderson     const void *symfile_addr;
4319813da627SRichard Henderson     uint64_t symfile_size;
4320813da627SRichard Henderson };
4321813da627SRichard Henderson 
4322813da627SRichard Henderson struct jit_descriptor {
4323813da627SRichard Henderson     uint32_t version;
4324813da627SRichard Henderson     uint32_t action_flag;
4325813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
4326813da627SRichard Henderson     struct jit_code_entry *first_entry;
4327813da627SRichard Henderson };
4328813da627SRichard Henderson 
4329813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
4330813da627SRichard Henderson void __jit_debug_register_code(void)
4331813da627SRichard Henderson {
4332813da627SRichard Henderson     asm("");
4333813da627SRichard Henderson }
4334813da627SRichard Henderson 
4335813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
4336813da627SRichard Henderson    the version before we can set it.  */
4337813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
4338813da627SRichard Henderson 
4339813da627SRichard Henderson /* End GDB interface.  */
4340813da627SRichard Henderson 
4341813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
4342813da627SRichard Henderson {
4343813da627SRichard Henderson     const char *p = strtab + 1;
4344813da627SRichard Henderson 
4345813da627SRichard Henderson     while (1) {
4346813da627SRichard Henderson         if (strcmp(p, str) == 0) {
4347813da627SRichard Henderson             return p - strtab;
4348813da627SRichard Henderson         }
4349813da627SRichard Henderson         p += strlen(p) + 1;
4350813da627SRichard Henderson     }
4351813da627SRichard Henderson }
4352813da627SRichard Henderson 
43535872bbf2SRichard Henderson static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
43542c90784aSRichard Henderson                                  const void *debug_frame,
43552c90784aSRichard Henderson                                  size_t debug_frame_size)
4356813da627SRichard Henderson {
43575872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
43585872bbf2SRichard Henderson         uint32_t  len;
43595872bbf2SRichard Henderson         uint16_t  version;
43605872bbf2SRichard Henderson         uint32_t  abbrev;
43615872bbf2SRichard Henderson         uint8_t   ptr_size;
43625872bbf2SRichard Henderson         uint8_t   cu_die;
43635872bbf2SRichard Henderson         uint16_t  cu_lang;
43645872bbf2SRichard Henderson         uintptr_t cu_low_pc;
43655872bbf2SRichard Henderson         uintptr_t cu_high_pc;
43665872bbf2SRichard Henderson         uint8_t   fn_die;
43675872bbf2SRichard Henderson         char      fn_name[16];
43685872bbf2SRichard Henderson         uintptr_t fn_low_pc;
43695872bbf2SRichard Henderson         uintptr_t fn_high_pc;
43705872bbf2SRichard Henderson         uint8_t   cu_eoc;
43715872bbf2SRichard Henderson     };
4372813da627SRichard Henderson 
4373813da627SRichard Henderson     struct ElfImage {
4374813da627SRichard Henderson         ElfW(Ehdr) ehdr;
4375813da627SRichard Henderson         ElfW(Phdr) phdr;
43765872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
43775872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
43785872bbf2SRichard Henderson         struct DebugInfo di;
43795872bbf2SRichard Henderson         uint8_t    da[24];
43805872bbf2SRichard Henderson         char       str[80];
43815872bbf2SRichard Henderson     };
43825872bbf2SRichard Henderson 
43835872bbf2SRichard Henderson     struct ElfImage *img;
43845872bbf2SRichard Henderson 
43855872bbf2SRichard Henderson     static const struct ElfImage img_template = {
43865872bbf2SRichard Henderson         .ehdr = {
43875872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
43885872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
43895872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
43905872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
43915872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
43925872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
43935872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
43945872bbf2SRichard Henderson             .e_type = ET_EXEC,
43955872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
43965872bbf2SRichard Henderson             .e_version = EV_CURRENT,
43975872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
43985872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
43995872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
44005872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
44015872bbf2SRichard Henderson             .e_phnum = 1,
44025872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
44035872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
44045872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
4405abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
4406abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
4407abbb3eaeSRichard Henderson #endif
4408abbb3eaeSRichard Henderson #ifdef ELF_OSABI
4409abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
4410abbb3eaeSRichard Henderson #endif
44115872bbf2SRichard Henderson         },
44125872bbf2SRichard Henderson         .phdr = {
44135872bbf2SRichard Henderson             .p_type = PT_LOAD,
44145872bbf2SRichard Henderson             .p_flags = PF_X,
44155872bbf2SRichard Henderson         },
44165872bbf2SRichard Henderson         .shdr = {
44175872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
44185872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
44195872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
44205872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
44215872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
44225872bbf2SRichard Henderson             [1] = { /* .text */
44235872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
44245872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
44255872bbf2SRichard Henderson             },
44265872bbf2SRichard Henderson             [2] = { /* .debug_info */
44275872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
44285872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
44295872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
44305872bbf2SRichard Henderson             },
44315872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
44325872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
44335872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
44345872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
44355872bbf2SRichard Henderson             },
44365872bbf2SRichard Henderson             [4] = { /* .debug_frame */
44375872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
44385872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
44395872bbf2SRichard Henderson             },
44405872bbf2SRichard Henderson             [5] = { /* .symtab */
44415872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
44425872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
44435872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
44445872bbf2SRichard Henderson                 .sh_info = 1,
44455872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
44465872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
44475872bbf2SRichard Henderson             },
44485872bbf2SRichard Henderson             [6] = { /* .strtab */
44495872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
44505872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
44515872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
44525872bbf2SRichard Henderson             }
44535872bbf2SRichard Henderson         },
44545872bbf2SRichard Henderson         .sym = {
44555872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
44565872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
44575872bbf2SRichard Henderson                 .st_shndx = 1,
44585872bbf2SRichard Henderson             }
44595872bbf2SRichard Henderson         },
44605872bbf2SRichard Henderson         .di = {
44615872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
44625872bbf2SRichard Henderson             .version = 2,
44635872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
44645872bbf2SRichard Henderson             .cu_die = 1,
44655872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
44665872bbf2SRichard Henderson             .fn_die = 2,
44675872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
44685872bbf2SRichard Henderson         },
44695872bbf2SRichard Henderson         .da = {
44705872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
44715872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
44725872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
44735872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
44745872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
44755872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
44765872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
44775872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
44785872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
44795872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
44805872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
44815872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
44825872bbf2SRichard Henderson             0           /* no more abbrev */
44835872bbf2SRichard Henderson         },
44845872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
44855872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
4486813da627SRichard Henderson     };
4487813da627SRichard Henderson 
4488813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
4489813da627SRichard Henderson     static struct jit_code_entry one_entry;
4490813da627SRichard Henderson 
44915872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
4492813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
44932c90784aSRichard Henderson     DebugFrameHeader *dfh;
4494813da627SRichard Henderson 
44955872bbf2SRichard Henderson     img = g_malloc(img_size);
44965872bbf2SRichard Henderson     *img = img_template;
4497813da627SRichard Henderson 
44985872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
44995872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
45005872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
4501813da627SRichard Henderson 
45025872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
45035872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
45045872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
4505813da627SRichard Henderson 
45065872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
45075872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
45085872bbf2SRichard Henderson 
45095872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
45105872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
45115872bbf2SRichard Henderson 
45125872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
45135872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
45145872bbf2SRichard Henderson 
45155872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
45165872bbf2SRichard Henderson     img->sym[1].st_value = buf;
45175872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
45185872bbf2SRichard Henderson 
45195872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
452045aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
45215872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
452245aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
4523813da627SRichard Henderson 
45242c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
45252c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
45262c90784aSRichard Henderson     dfh->fde.func_start = buf;
45272c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
45282c90784aSRichard Henderson 
4529813da627SRichard Henderson #ifdef DEBUG_JIT
4530813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
4531813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
4532813da627SRichard Henderson     {
4533813da627SRichard Henderson         FILE *f = fopen("/tmp/qemu.jit", "w+b");
4534813da627SRichard Henderson         if (f) {
45355872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
4536813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
4537813da627SRichard Henderson             }
4538813da627SRichard Henderson             fclose(f);
4539813da627SRichard Henderson         }
4540813da627SRichard Henderson     }
4541813da627SRichard Henderson #endif
4542813da627SRichard Henderson 
4543813da627SRichard Henderson     one_entry.symfile_addr = img;
4544813da627SRichard Henderson     one_entry.symfile_size = img_size;
4545813da627SRichard Henderson 
4546813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
4547813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
4548813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
4549813da627SRichard Henderson     __jit_debug_register_code();
4550813da627SRichard Henderson }
4551813da627SRichard Henderson #else
45525872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
45535872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
4554813da627SRichard Henderson 
4555813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size,
45562c90784aSRichard Henderson                                  const void *debug_frame,
45572c90784aSRichard Henderson                                  size_t debug_frame_size)
4558813da627SRichard Henderson {
4559813da627SRichard Henderson }
4560813da627SRichard Henderson 
4561813da627SRichard Henderson void tcg_register_jit(void *buf, size_t buf_size)
4562813da627SRichard Henderson {
4563813da627SRichard Henderson }
4564813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
4565db432672SRichard Henderson 
4566db432672SRichard Henderson #if !TCG_TARGET_MAYBE_vec
4567db432672SRichard Henderson void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...)
4568db432672SRichard Henderson {
4569db432672SRichard Henderson     g_assert_not_reached();
4570db432672SRichard Henderson }
4571db432672SRichard Henderson #endif
4572