xref: /qemu/tcg/tcg.c (revision 57a269469dbf70013dab3a176e1735636010a772)
1c896fe29Sbellard /*
2c896fe29Sbellard  * Tiny Code Generator for QEMU
3c896fe29Sbellard  *
4c896fe29Sbellard  * Copyright (c) 2008 Fabrice Bellard
5c896fe29Sbellard  *
6c896fe29Sbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
7c896fe29Sbellard  * of this software and associated documentation files (the "Software"), to deal
8c896fe29Sbellard  * in the Software without restriction, including without limitation the rights
9c896fe29Sbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10c896fe29Sbellard  * copies of the Software, and to permit persons to whom the Software is
11c896fe29Sbellard  * furnished to do so, subject to the following conditions:
12c896fe29Sbellard  *
13c896fe29Sbellard  * The above copyright notice and this permission notice shall be included in
14c896fe29Sbellard  * all copies or substantial portions of the Software.
15c896fe29Sbellard  *
16c896fe29Sbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17c896fe29Sbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18c896fe29Sbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19c896fe29Sbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20c896fe29Sbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21c896fe29Sbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22c896fe29Sbellard  * THE SOFTWARE.
23c896fe29Sbellard  */
24c896fe29Sbellard 
25c896fe29Sbellard /* define it to use liveness analysis (better code) */
268f2e8c07SKirill Batuzov #define USE_TCG_OPTIMIZATIONS
27c896fe29Sbellard 
28757e725bSPeter Maydell #include "qemu/osdep.h"
29cca82982Saurel32 
30813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB.  */
31813da627SRichard Henderson #undef DEBUG_JIT
32813da627SRichard Henderson 
33f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
341de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
351de7afc9SPaolo Bonzini #include "qemu/timer.h"
36c896fe29Sbellard 
37c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU
38c896fe29Sbellard    CPU definitions. Currently they are used for qemu_ld/st
39c896fe29Sbellard    instructions */
40c896fe29Sbellard #define NO_CPU_IO_DEFS
41c896fe29Sbellard #include "cpu.h"
42c896fe29Sbellard 
4363c91552SPaolo Bonzini #include "exec/cpu-common.h"
4463c91552SPaolo Bonzini #include "exec/exec-all.h"
4563c91552SPaolo Bonzini 
46c896fe29Sbellard #include "tcg-op.h"
47813da627SRichard Henderson 
48edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX
49813da627SRichard Henderson # define ELF_CLASS  ELFCLASS32
50edee2579SRichard Henderson #else
51edee2579SRichard Henderson # define ELF_CLASS  ELFCLASS64
52813da627SRichard Henderson #endif
53813da627SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
54813da627SRichard Henderson # define ELF_DATA   ELFDATA2MSB
55813da627SRichard Henderson #else
56813da627SRichard Henderson # define ELF_DATA   ELFDATA2LSB
57813da627SRichard Henderson #endif
58813da627SRichard Henderson 
59c896fe29Sbellard #include "elf.h"
60508127e2SPaolo Bonzini #include "exec/log.h"
61c896fe29Sbellard 
62ce151109SPeter Maydell /* Forward declarations for functions declared in tcg-target.inc.c and
63ce151109SPeter Maydell    used here. */
64e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s);
65f69d277eSRichard Henderson static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode);
66e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
671813e175SRichard Henderson static void patch_reloc(tcg_insn_unit *code_ptr, int type,
682ba7fae2SRichard Henderson                         intptr_t value, intptr_t addend);
69c896fe29Sbellard 
70497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts.  */
71497a22ebSRichard Henderson typedef struct {
72497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
73497a22ebSRichard Henderson     uint32_t id;
74497a22ebSRichard Henderson     uint8_t version;
75497a22ebSRichard Henderson     char augmentation[1];
76497a22ebSRichard Henderson     uint8_t code_align;
77497a22ebSRichard Henderson     uint8_t data_align;
78497a22ebSRichard Henderson     uint8_t return_column;
79497a22ebSRichard Henderson } DebugFrameCIE;
80497a22ebSRichard Henderson 
81497a22ebSRichard Henderson typedef struct QEMU_PACKED {
82497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
83497a22ebSRichard Henderson     uint32_t cie_offset;
84edee2579SRichard Henderson     uintptr_t func_start;
85edee2579SRichard Henderson     uintptr_t func_len;
86497a22ebSRichard Henderson } DebugFrameFDEHeader;
87497a22ebSRichard Henderson 
882c90784aSRichard Henderson typedef struct QEMU_PACKED {
892c90784aSRichard Henderson     DebugFrameCIE cie;
902c90784aSRichard Henderson     DebugFrameFDEHeader fde;
912c90784aSRichard Henderson } DebugFrameHeader;
922c90784aSRichard Henderson 
93813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size,
942c90784aSRichard Henderson                                  const void *debug_frame,
952c90784aSRichard Henderson                                  size_t debug_frame_size)
96813da627SRichard Henderson     __attribute__((unused));
97813da627SRichard Henderson 
98ce151109SPeter Maydell /* Forward declarations for functions declared and used in tcg-target.inc.c. */
99069ea736SRichard Henderson static const char *target_parse_constraint(TCGArgConstraint *ct,
100069ea736SRichard Henderson                                            const char *ct_str, TCGType type);
1012a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
102a05b5b9bSRichard Henderson                        intptr_t arg2);
1032a534affSRichard Henderson static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
104c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1052a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
106c0ad3001SStefan Weil static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
107c0ad3001SStefan Weil                        const int *const_args);
1082a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
109a05b5b9bSRichard Henderson                        intptr_t arg2);
11059d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
11159d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
112cf066674SRichard Henderson static void tcg_out_call(TCGContext *s, tcg_insn_unit *target);
113f6c6afc1SRichard Henderson static int tcg_target_const_match(tcg_target_long val, TCGType type,
114c0ad3001SStefan Weil                                   const TCGArgConstraint *arg_ct);
115659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
116659ef5cbSRichard Henderson static bool tcg_out_ldst_finalize(TCGContext *s);
117659ef5cbSRichard Henderson #endif
118c896fe29Sbellard 
119b1d8e52eSblueswir1 static TCGRegSet tcg_target_available_regs[2];
120b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
121c896fe29Sbellard 
1221813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
1234196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
124c896fe29Sbellard {
125c896fe29Sbellard     *s->code_ptr++ = v;
126c896fe29Sbellard }
127c896fe29Sbellard 
1284196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
1294196dca6SPeter Maydell                                                       uint8_t v)
1305c53bb81SPeter Maydell {
1311813e175SRichard Henderson     *p = v;
1325c53bb81SPeter Maydell }
1331813e175SRichard Henderson #endif
1345c53bb81SPeter Maydell 
1351813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
1364196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
137c896fe29Sbellard {
1381813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
1391813e175SRichard Henderson         *s->code_ptr++ = v;
1401813e175SRichard Henderson     } else {
1411813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
1424387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
1431813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
1441813e175SRichard Henderson     }
145c896fe29Sbellard }
146c896fe29Sbellard 
1474196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
1484196dca6SPeter Maydell                                                        uint16_t v)
1495c53bb81SPeter Maydell {
1501813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
1511813e175SRichard Henderson         *p = v;
1521813e175SRichard Henderson     } else {
1535c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
1545c53bb81SPeter Maydell     }
1551813e175SRichard Henderson }
1561813e175SRichard Henderson #endif
1575c53bb81SPeter Maydell 
1581813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
1594196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
160c896fe29Sbellard {
1611813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
1621813e175SRichard Henderson         *s->code_ptr++ = v;
1631813e175SRichard Henderson     } else {
1641813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
1654387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
1661813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
1671813e175SRichard Henderson     }
168c896fe29Sbellard }
169c896fe29Sbellard 
1704196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
1714196dca6SPeter Maydell                                                        uint32_t v)
1725c53bb81SPeter Maydell {
1731813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
1741813e175SRichard Henderson         *p = v;
1751813e175SRichard Henderson     } else {
1765c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
1775c53bb81SPeter Maydell     }
1781813e175SRichard Henderson }
1791813e175SRichard Henderson #endif
1805c53bb81SPeter Maydell 
1811813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
1824196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
183ac26eb69SRichard Henderson {
1841813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
1851813e175SRichard Henderson         *s->code_ptr++ = v;
1861813e175SRichard Henderson     } else {
1871813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
1884387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
1891813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
1901813e175SRichard Henderson     }
191ac26eb69SRichard Henderson }
192ac26eb69SRichard Henderson 
1934196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
1944196dca6SPeter Maydell                                                        uint64_t v)
1955c53bb81SPeter Maydell {
1961813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
1971813e175SRichard Henderson         *p = v;
1981813e175SRichard Henderson     } else {
1995c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2005c53bb81SPeter Maydell     }
2011813e175SRichard Henderson }
2021813e175SRichard Henderson #endif
2035c53bb81SPeter Maydell 
204c896fe29Sbellard /* label relocation processing */
205c896fe29Sbellard 
2061813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
207bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
208c896fe29Sbellard {
209c896fe29Sbellard     TCGRelocation *r;
210c896fe29Sbellard 
211c896fe29Sbellard     if (l->has_value) {
212623e265cSpbrook         /* FIXME: This may break relocations on RISC targets that
213623e265cSpbrook            modify instruction fields in place.  The caller may not have
214623e265cSpbrook            written the initial value.  */
215f54b3f92Saurel32         patch_reloc(code_ptr, type, l->u.value, addend);
216c896fe29Sbellard     } else {
217c896fe29Sbellard         /* add a new relocation entry */
218c896fe29Sbellard         r = tcg_malloc(sizeof(TCGRelocation));
219c896fe29Sbellard         r->type = type;
220c896fe29Sbellard         r->ptr = code_ptr;
221c896fe29Sbellard         r->addend = addend;
222c896fe29Sbellard         r->next = l->u.first_reloc;
223c896fe29Sbellard         l->u.first_reloc = r;
224c896fe29Sbellard     }
225c896fe29Sbellard }
226c896fe29Sbellard 
227bec16311SRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr)
228c896fe29Sbellard {
2292ba7fae2SRichard Henderson     intptr_t value = (intptr_t)ptr;
2301813e175SRichard Henderson     TCGRelocation *r;
231c896fe29Sbellard 
232eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
2331813e175SRichard Henderson 
2341813e175SRichard Henderson     for (r = l->u.first_reloc; r != NULL; r = r->next) {
235f54b3f92Saurel32         patch_reloc(r->ptr, r->type, value, r->addend);
236c896fe29Sbellard     }
2371813e175SRichard Henderson 
238c896fe29Sbellard     l->has_value = 1;
2391813e175SRichard Henderson     l->u.value_ptr = ptr;
240c896fe29Sbellard }
241c896fe29Sbellard 
24242a268c2SRichard Henderson TCGLabel *gen_new_label(void)
243c896fe29Sbellard {
244c896fe29Sbellard     TCGContext *s = &tcg_ctx;
24551e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
246c896fe29Sbellard 
24751e3972cSRichard Henderson     *l = (TCGLabel){
24851e3972cSRichard Henderson         .id = s->nb_labels++
24951e3972cSRichard Henderson     };
25042a268c2SRichard Henderson 
25142a268c2SRichard Henderson     return l;
252c896fe29Sbellard }
253c896fe29Sbellard 
254ce151109SPeter Maydell #include "tcg-target.inc.c"
255c896fe29Sbellard 
256c896fe29Sbellard /* pool based memory allocation */
257c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
258c896fe29Sbellard {
259c896fe29Sbellard     TCGPool *p;
260c896fe29Sbellard     int pool_size;
261c896fe29Sbellard 
262c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
263c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
2647267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
265c896fe29Sbellard         p->size = size;
2664055299eSKirill Batuzov         p->next = s->pool_first_large;
2674055299eSKirill Batuzov         s->pool_first_large = p;
2684055299eSKirill Batuzov         return p->data;
269c896fe29Sbellard     } else {
270c896fe29Sbellard         p = s->pool_current;
271c896fe29Sbellard         if (!p) {
272c896fe29Sbellard             p = s->pool_first;
273c896fe29Sbellard             if (!p)
274c896fe29Sbellard                 goto new_pool;
275c896fe29Sbellard         } else {
276c896fe29Sbellard             if (!p->next) {
277c896fe29Sbellard             new_pool:
278c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
2797267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
280c896fe29Sbellard                 p->size = pool_size;
281c896fe29Sbellard                 p->next = NULL;
282c896fe29Sbellard                 if (s->pool_current)
283c896fe29Sbellard                     s->pool_current->next = p;
284c896fe29Sbellard                 else
285c896fe29Sbellard                     s->pool_first = p;
286c896fe29Sbellard             } else {
287c896fe29Sbellard                 p = p->next;
288c896fe29Sbellard             }
289c896fe29Sbellard         }
290c896fe29Sbellard     }
291c896fe29Sbellard     s->pool_current = p;
292c896fe29Sbellard     s->pool_cur = p->data + size;
293c896fe29Sbellard     s->pool_end = p->data + p->size;
294c896fe29Sbellard     return p->data;
295c896fe29Sbellard }
296c896fe29Sbellard 
297c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
298c896fe29Sbellard {
2994055299eSKirill Batuzov     TCGPool *p, *t;
3004055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
3014055299eSKirill Batuzov         t = p->next;
3024055299eSKirill Batuzov         g_free(p);
3034055299eSKirill Batuzov     }
3044055299eSKirill Batuzov     s->pool_first_large = NULL;
305c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
306c896fe29Sbellard     s->pool_current = NULL;
307c896fe29Sbellard }
308c896fe29Sbellard 
309100b5e01SRichard Henderson typedef struct TCGHelperInfo {
310100b5e01SRichard Henderson     void *func;
311100b5e01SRichard Henderson     const char *name;
312afb49896SRichard Henderson     unsigned flags;
313afb49896SRichard Henderson     unsigned sizemask;
314100b5e01SRichard Henderson } TCGHelperInfo;
315100b5e01SRichard Henderson 
3162ef6175aSRichard Henderson #include "exec/helper-proto.h"
3172ef6175aSRichard Henderson 
318100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = {
3192ef6175aSRichard Henderson #include "exec/helper-tcg.h"
320100b5e01SRichard Henderson };
321100b5e01SRichard Henderson 
32291478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
323f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
32491478cefSRichard Henderson 
325c896fe29Sbellard void tcg_context_init(TCGContext *s)
326c896fe29Sbellard {
327100b5e01SRichard Henderson     int op, total_args, n, i;
328c896fe29Sbellard     TCGOpDef *def;
329c896fe29Sbellard     TCGArgConstraint *args_ct;
330c896fe29Sbellard     int *sorted_args;
33184fd9dd3SRichard Henderson     GHashTable *helper_table;
332c896fe29Sbellard 
333c896fe29Sbellard     memset(s, 0, sizeof(*s));
334c896fe29Sbellard     s->nb_globals = 0;
335c896fe29Sbellard 
336c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
337c896fe29Sbellard        space */
338c896fe29Sbellard     total_args = 0;
339c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
340c896fe29Sbellard         def = &tcg_op_defs[op];
341c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
342c896fe29Sbellard         total_args += n;
343c896fe29Sbellard     }
344c896fe29Sbellard 
3457267c094SAnthony Liguori     args_ct = g_malloc(sizeof(TCGArgConstraint) * total_args);
3467267c094SAnthony Liguori     sorted_args = g_malloc(sizeof(int) * total_args);
347c896fe29Sbellard 
348c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
349c896fe29Sbellard         def = &tcg_op_defs[op];
350c896fe29Sbellard         def->args_ct = args_ct;
351c896fe29Sbellard         def->sorted_args = sorted_args;
352c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
353c896fe29Sbellard         sorted_args += n;
354c896fe29Sbellard         args_ct += n;
355c896fe29Sbellard     }
356c896fe29Sbellard 
3575cd8f621SRichard Henderson     /* Register helpers.  */
35884fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
35984fd9dd3SRichard Henderson     s->helpers = helper_table = g_hash_table_new(NULL, NULL);
36084fd9dd3SRichard Henderson 
361100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
36284fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
36372866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
364100b5e01SRichard Henderson     }
3655cd8f621SRichard Henderson 
366c896fe29Sbellard     tcg_target_init(s);
367f69d277eSRichard Henderson     process_op_defs(s);
36891478cefSRichard Henderson 
36991478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
37091478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
37191478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
37291478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
37391478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
37491478cefSRichard Henderson             break;
37591478cefSRichard Henderson         }
37691478cefSRichard Henderson     }
37791478cefSRichard Henderson     for (i = 0; i < n; ++i) {
37891478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
37991478cefSRichard Henderson     }
38091478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
38191478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
38291478cefSRichard Henderson     }
3839002ec79SRichard Henderson }
384b03cce8eSbellard 
3856e3b2bfdSEmilio G. Cota /*
3866e3b2bfdSEmilio G. Cota  * Allocate TBs right before their corresponding translated code, making
3876e3b2bfdSEmilio G. Cota  * sure that TBs and code are on different cache lines.
3886e3b2bfdSEmilio G. Cota  */
3896e3b2bfdSEmilio G. Cota TranslationBlock *tcg_tb_alloc(TCGContext *s)
3906e3b2bfdSEmilio G. Cota {
3916e3b2bfdSEmilio G. Cota     uintptr_t align = qemu_icache_linesize;
3926e3b2bfdSEmilio G. Cota     TranslationBlock *tb;
3936e3b2bfdSEmilio G. Cota     void *next;
3946e3b2bfdSEmilio G. Cota 
3956e3b2bfdSEmilio G. Cota     tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align);
3966e3b2bfdSEmilio G. Cota     next = (void *)ROUND_UP((uintptr_t)(tb + 1), align);
3976e3b2bfdSEmilio G. Cota 
3986e3b2bfdSEmilio G. Cota     if (unlikely(next > s->code_gen_highwater)) {
3996e3b2bfdSEmilio G. Cota         return NULL;
4006e3b2bfdSEmilio G. Cota     }
4016e3b2bfdSEmilio G. Cota     s->code_gen_ptr = next;
402*57a26946SRichard Henderson     s->data_gen_ptr = NULL;
4036e3b2bfdSEmilio G. Cota     return tb;
4046e3b2bfdSEmilio G. Cota }
4056e3b2bfdSEmilio G. Cota 
4069002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
4079002ec79SRichard Henderson {
4088163b749SRichard Henderson     size_t prologue_size, total_size;
4098163b749SRichard Henderson     void *buf0, *buf1;
4108163b749SRichard Henderson 
4118163b749SRichard Henderson     /* Put the prologue at the beginning of code_gen_buffer.  */
4128163b749SRichard Henderson     buf0 = s->code_gen_buffer;
4138163b749SRichard Henderson     s->code_ptr = buf0;
4148163b749SRichard Henderson     s->code_buf = buf0;
4158163b749SRichard Henderson     s->code_gen_prologue = buf0;
4168163b749SRichard Henderson 
4178163b749SRichard Henderson     /* Generate the prologue.  */
418b03cce8eSbellard     tcg_target_qemu_prologue(s);
4198163b749SRichard Henderson     buf1 = s->code_ptr;
4208163b749SRichard Henderson     flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1);
4218163b749SRichard Henderson 
4228163b749SRichard Henderson     /* Deduct the prologue from the buffer.  */
4238163b749SRichard Henderson     prologue_size = tcg_current_code_size(s);
4248163b749SRichard Henderson     s->code_gen_ptr = buf1;
4258163b749SRichard Henderson     s->code_gen_buffer = buf1;
4268163b749SRichard Henderson     s->code_buf = buf1;
4278163b749SRichard Henderson     total_size = s->code_gen_buffer_size - prologue_size;
4288163b749SRichard Henderson     s->code_gen_buffer_size = total_size;
4298163b749SRichard Henderson 
430b125f9dcSRichard Henderson     /* Compute a high-water mark, at which we voluntarily flush the buffer
431b125f9dcSRichard Henderson        and start over.  The size here is arbitrary, significantly larger
432b125f9dcSRichard Henderson        than we expect the code generation for any one opcode to require.  */
43323dceda6SRichard Henderson     s->code_gen_highwater = s->code_gen_buffer + (total_size - 1024);
4348163b749SRichard Henderson 
4358163b749SRichard Henderson     tcg_register_jit(s->code_gen_buffer, total_size);
436d6b64b2bSRichard Henderson 
437d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
438d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
4391ee73216SRichard Henderson         qemu_log_lock();
4408163b749SRichard Henderson         qemu_log("PROLOGUE: [size=%zu]\n", prologue_size);
4418163b749SRichard Henderson         log_disas(buf0, prologue_size);
442d6b64b2bSRichard Henderson         qemu_log("\n");
443d6b64b2bSRichard Henderson         qemu_log_flush();
4441ee73216SRichard Henderson         qemu_log_unlock();
445d6b64b2bSRichard Henderson     }
446d6b64b2bSRichard Henderson #endif
447cedbcb01SEmilio G. Cota 
448cedbcb01SEmilio G. Cota     /* Assert that goto_ptr is implemented completely.  */
449cedbcb01SEmilio G. Cota     if (TCG_TARGET_HAS_goto_ptr) {
450cedbcb01SEmilio G. Cota         tcg_debug_assert(s->code_gen_epilogue != NULL);
451cedbcb01SEmilio G. Cota     }
452c896fe29Sbellard }
453c896fe29Sbellard 
454c896fe29Sbellard void tcg_func_start(TCGContext *s)
455c896fe29Sbellard {
456c896fe29Sbellard     tcg_pool_reset(s);
457c896fe29Sbellard     s->nb_temps = s->nb_globals;
4580ec9eabcSRichard Henderson 
4590ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
4600ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
4610ec9eabcSRichard Henderson 
462c896fe29Sbellard     s->nb_labels = 0;
463c896fe29Sbellard     s->current_frame_offset = s->frame_start;
464c896fe29Sbellard 
4650a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
4660a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
4670a209d4bSRichard Henderson #endif
4680a209d4bSRichard Henderson 
469dcb8e758SRichard Henderson     s->gen_op_buf[0].next = 1;
470dcb8e758SRichard Henderson     s->gen_op_buf[0].prev = 0;
471dcb8e758SRichard Henderson     s->gen_next_op_idx = 1;
472c45cb8bbSRichard Henderson     s->gen_next_parm_idx = 0;
473c896fe29Sbellard }
474c896fe29Sbellard 
4757ca4b752SRichard Henderson static inline int temp_idx(TCGContext *s, TCGTemp *ts)
476c896fe29Sbellard {
4777ca4b752SRichard Henderson     ptrdiff_t n = ts - s->temps;
4787ca4b752SRichard Henderson     tcg_debug_assert(n >= 0 && n < s->nb_temps);
4797ca4b752SRichard Henderson     return n;
4807ca4b752SRichard Henderson }
4817ca4b752SRichard Henderson 
4827ca4b752SRichard Henderson static inline TCGTemp *tcg_temp_alloc(TCGContext *s)
4837ca4b752SRichard Henderson {
4847ca4b752SRichard Henderson     int n = s->nb_temps++;
4857ca4b752SRichard Henderson     tcg_debug_assert(n < TCG_MAX_TEMPS);
4867ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
4877ca4b752SRichard Henderson }
4887ca4b752SRichard Henderson 
4897ca4b752SRichard Henderson static inline TCGTemp *tcg_global_alloc(TCGContext *s)
4907ca4b752SRichard Henderson {
4917ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
4927ca4b752SRichard Henderson     s->nb_globals++;
4937ca4b752SRichard Henderson     return tcg_temp_alloc(s);
494c896fe29Sbellard }
495c896fe29Sbellard 
496b3a62939SRichard Henderson static int tcg_global_reg_new_internal(TCGContext *s, TCGType type,
497b6638662SRichard Henderson                                        TCGReg reg, const char *name)
498c896fe29Sbellard {
499c896fe29Sbellard     TCGTemp *ts;
500c896fe29Sbellard 
501b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
502c896fe29Sbellard         tcg_abort();
503b3a62939SRichard Henderson     }
5047ca4b752SRichard Henderson 
5057ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
506c896fe29Sbellard     ts->base_type = type;
507c896fe29Sbellard     ts->type = type;
508c896fe29Sbellard     ts->fixed_reg = 1;
509c896fe29Sbellard     ts->reg = reg;
510c896fe29Sbellard     ts->name = name;
511c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
5127ca4b752SRichard Henderson 
5137ca4b752SRichard Henderson     return temp_idx(s, ts);
514a7812ae4Spbrook }
515a7812ae4Spbrook 
516b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
517a7812ae4Spbrook {
518a7812ae4Spbrook     int idx;
519b3a62939SRichard Henderson     s->frame_start = start;
520b3a62939SRichard Henderson     s->frame_end = start + size;
521b3a62939SRichard Henderson     idx = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
522b3a62939SRichard Henderson     s->frame_temp = &s->temps[idx];
523b3a62939SRichard Henderson }
524a7812ae4Spbrook 
525b6638662SRichard Henderson TCGv_i32 tcg_global_reg_new_i32(TCGReg reg, const char *name)
526b3a62939SRichard Henderson {
527b3a62939SRichard Henderson     TCGContext *s = &tcg_ctx;
528b3a62939SRichard Henderson     int idx;
529b3a62939SRichard Henderson 
530b3a62939SRichard Henderson     if (tcg_regset_test_reg(s->reserved_regs, reg)) {
531b3a62939SRichard Henderson         tcg_abort();
532b3a62939SRichard Henderson     }
533b3a62939SRichard Henderson     idx = tcg_global_reg_new_internal(s, TCG_TYPE_I32, reg, name);
534a7812ae4Spbrook     return MAKE_TCGV_I32(idx);
535a7812ae4Spbrook }
536a7812ae4Spbrook 
537b6638662SRichard Henderson TCGv_i64 tcg_global_reg_new_i64(TCGReg reg, const char *name)
538a7812ae4Spbrook {
539b3a62939SRichard Henderson     TCGContext *s = &tcg_ctx;
540a7812ae4Spbrook     int idx;
541a7812ae4Spbrook 
542b3a62939SRichard Henderson     if (tcg_regset_test_reg(s->reserved_regs, reg)) {
543b3a62939SRichard Henderson         tcg_abort();
544b3a62939SRichard Henderson     }
545b3a62939SRichard Henderson     idx = tcg_global_reg_new_internal(s, TCG_TYPE_I64, reg, name);
546a7812ae4Spbrook     return MAKE_TCGV_I64(idx);
547c896fe29Sbellard }
548c896fe29Sbellard 
549e1ccc054SRichard Henderson int tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
550e1ccc054SRichard Henderson                                 intptr_t offset, const char *name)
551c896fe29Sbellard {
552c896fe29Sbellard     TCGContext *s = &tcg_ctx;
5537ca4b752SRichard Henderson     TCGTemp *base_ts = &s->temps[GET_TCGV_PTR(base)];
5547ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
555b3915dbbSRichard Henderson     int indirect_reg = 0, bigendian = 0;
5567ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
5577ca4b752SRichard Henderson     bigendian = 1;
5587ca4b752SRichard Henderson #endif
559c896fe29Sbellard 
560b3915dbbSRichard Henderson     if (!base_ts->fixed_reg) {
5615a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
5625a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
563b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
5645a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
5655a18407fSRichard Henderson                             ? 2 : 1);
5665a18407fSRichard Henderson         indirect_reg = 1;
567b3915dbbSRichard Henderson     }
568b3915dbbSRichard Henderson 
5697ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
5707ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
571c896fe29Sbellard         char buf[64];
5727ca4b752SRichard Henderson 
5737ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
574c896fe29Sbellard         ts->type = TCG_TYPE_I32;
575b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
576c896fe29Sbellard         ts->mem_allocated = 1;
577b3a62939SRichard Henderson         ts->mem_base = base_ts;
5787ca4b752SRichard Henderson         ts->mem_offset = offset + bigendian * 4;
579c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
580c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
581c896fe29Sbellard         ts->name = strdup(buf);
582c896fe29Sbellard 
5837ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
5847ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
5857ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
586b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
5877ca4b752SRichard Henderson         ts2->mem_allocated = 1;
5887ca4b752SRichard Henderson         ts2->mem_base = base_ts;
5897ca4b752SRichard Henderson         ts2->mem_offset = offset + (1 - bigendian) * 4;
590c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
591c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
592120c1084SRichard Henderson         ts2->name = strdup(buf);
5937ca4b752SRichard Henderson     } else {
594c896fe29Sbellard         ts->base_type = type;
595c896fe29Sbellard         ts->type = type;
596b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
597c896fe29Sbellard         ts->mem_allocated = 1;
598b3a62939SRichard Henderson         ts->mem_base = base_ts;
599c896fe29Sbellard         ts->mem_offset = offset;
600c896fe29Sbellard         ts->name = name;
601c896fe29Sbellard     }
6027ca4b752SRichard Henderson     return temp_idx(s, ts);
603c896fe29Sbellard }
604c896fe29Sbellard 
6057ca4b752SRichard Henderson static int tcg_temp_new_internal(TCGType type, int temp_local)
606c896fe29Sbellard {
607c896fe29Sbellard     TCGContext *s = &tcg_ctx;
608c896fe29Sbellard     TCGTemp *ts;
609641d5fbeSbellard     int idx, k;
610c896fe29Sbellard 
6110ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
6120ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
6130ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
6140ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
6150ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
6160ec9eabcSRichard Henderson 
617e8996ee0Sbellard         ts = &s->temps[idx];
618e8996ee0Sbellard         ts->temp_allocated = 1;
6197ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
6207ca4b752SRichard Henderson         tcg_debug_assert(ts->temp_local == temp_local);
621e8996ee0Sbellard     } else {
6227ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
6237ca4b752SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
6247ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
6257ca4b752SRichard Henderson 
626c896fe29Sbellard             ts->base_type = type;
627c896fe29Sbellard             ts->type = TCG_TYPE_I32;
628e8996ee0Sbellard             ts->temp_allocated = 1;
629641d5fbeSbellard             ts->temp_local = temp_local;
6307ca4b752SRichard Henderson 
6317ca4b752SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
6327ca4b752SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
6337ca4b752SRichard Henderson             ts2->type = TCG_TYPE_I32;
6347ca4b752SRichard Henderson             ts2->temp_allocated = 1;
6357ca4b752SRichard Henderson             ts2->temp_local = temp_local;
6367ca4b752SRichard Henderson         } else {
637c896fe29Sbellard             ts->base_type = type;
638c896fe29Sbellard             ts->type = type;
639e8996ee0Sbellard             ts->temp_allocated = 1;
640641d5fbeSbellard             ts->temp_local = temp_local;
641c896fe29Sbellard         }
6427ca4b752SRichard Henderson         idx = temp_idx(s, ts);
643e8996ee0Sbellard     }
64427bfd83cSPeter Maydell 
64527bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
64627bfd83cSPeter Maydell     s->temps_in_use++;
64727bfd83cSPeter Maydell #endif
648a7812ae4Spbrook     return idx;
649c896fe29Sbellard }
650c896fe29Sbellard 
651a7812ae4Spbrook TCGv_i32 tcg_temp_new_internal_i32(int temp_local)
652a7812ae4Spbrook {
653a7812ae4Spbrook     int idx;
654a7812ae4Spbrook 
655a7812ae4Spbrook     idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local);
656a7812ae4Spbrook     return MAKE_TCGV_I32(idx);
657a7812ae4Spbrook }
658a7812ae4Spbrook 
659a7812ae4Spbrook TCGv_i64 tcg_temp_new_internal_i64(int temp_local)
660a7812ae4Spbrook {
661a7812ae4Spbrook     int idx;
662a7812ae4Spbrook 
663a7812ae4Spbrook     idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local);
664a7812ae4Spbrook     return MAKE_TCGV_I64(idx);
665a7812ae4Spbrook }
666a7812ae4Spbrook 
6670ec9eabcSRichard Henderson static void tcg_temp_free_internal(int idx)
668c896fe29Sbellard {
669c896fe29Sbellard     TCGContext *s = &tcg_ctx;
670c896fe29Sbellard     TCGTemp *ts;
671641d5fbeSbellard     int k;
672c896fe29Sbellard 
67327bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
67427bfd83cSPeter Maydell     s->temps_in_use--;
67527bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
67627bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
67727bfd83cSPeter Maydell     }
67827bfd83cSPeter Maydell #endif
67927bfd83cSPeter Maydell 
680eabb7b91SAurelien Jarno     tcg_debug_assert(idx >= s->nb_globals && idx < s->nb_temps);
681c896fe29Sbellard     ts = &s->temps[idx];
682eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
683e8996ee0Sbellard     ts->temp_allocated = 0;
6840ec9eabcSRichard Henderson 
68518d13fa2SAlexander Graf     k = ts->base_type + (ts->temp_local ? TCG_TYPE_COUNT : 0);
6860ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
687e8996ee0Sbellard }
688e8996ee0Sbellard 
689a7812ae4Spbrook void tcg_temp_free_i32(TCGv_i32 arg)
690e8996ee0Sbellard {
691a7812ae4Spbrook     tcg_temp_free_internal(GET_TCGV_I32(arg));
692a7812ae4Spbrook }
693a7812ae4Spbrook 
694a7812ae4Spbrook void tcg_temp_free_i64(TCGv_i64 arg)
695a7812ae4Spbrook {
696a7812ae4Spbrook     tcg_temp_free_internal(GET_TCGV_I64(arg));
697a7812ae4Spbrook }
698a7812ae4Spbrook 
699a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
700a7812ae4Spbrook {
701a7812ae4Spbrook     TCGv_i32 t0;
702a7812ae4Spbrook     t0 = tcg_temp_new_i32();
703e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
704e8996ee0Sbellard     return t0;
705c896fe29Sbellard }
706c896fe29Sbellard 
707a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
708c896fe29Sbellard {
709a7812ae4Spbrook     TCGv_i64 t0;
710a7812ae4Spbrook     t0 = tcg_temp_new_i64();
711e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
712e8996ee0Sbellard     return t0;
713c896fe29Sbellard }
714c896fe29Sbellard 
715a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
716bdffd4a9Saurel32 {
717a7812ae4Spbrook     TCGv_i32 t0;
718a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
719bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
720bdffd4a9Saurel32     return t0;
721bdffd4a9Saurel32 }
722bdffd4a9Saurel32 
723a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
724bdffd4a9Saurel32 {
725a7812ae4Spbrook     TCGv_i64 t0;
726a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
727bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
728bdffd4a9Saurel32     return t0;
729bdffd4a9Saurel32 }
730bdffd4a9Saurel32 
73127bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
73227bfd83cSPeter Maydell void tcg_clear_temp_count(void)
73327bfd83cSPeter Maydell {
73427bfd83cSPeter Maydell     TCGContext *s = &tcg_ctx;
73527bfd83cSPeter Maydell     s->temps_in_use = 0;
73627bfd83cSPeter Maydell }
73727bfd83cSPeter Maydell 
73827bfd83cSPeter Maydell int tcg_check_temp_count(void)
73927bfd83cSPeter Maydell {
74027bfd83cSPeter Maydell     TCGContext *s = &tcg_ctx;
74127bfd83cSPeter Maydell     if (s->temps_in_use) {
74227bfd83cSPeter Maydell         /* Clear the count so that we don't give another
74327bfd83cSPeter Maydell          * warning immediately next time around.
74427bfd83cSPeter Maydell          */
74527bfd83cSPeter Maydell         s->temps_in_use = 0;
74627bfd83cSPeter Maydell         return 1;
74727bfd83cSPeter Maydell     }
74827bfd83cSPeter Maydell     return 0;
74927bfd83cSPeter Maydell }
75027bfd83cSPeter Maydell #endif
75127bfd83cSPeter Maydell 
75239cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment
75339cf05d3Sbellard    and endian swap. Maybe it would be better to do the alignment
75439cf05d3Sbellard    and endian swap in tcg_reg_alloc_call(). */
755bbb8a1b4SRichard Henderson void tcg_gen_callN(TCGContext *s, void *func, TCGArg ret,
756bbb8a1b4SRichard Henderson                    int nargs, TCGArg *args)
757c896fe29Sbellard {
758c45cb8bbSRichard Henderson     int i, real_args, nb_rets, pi, pi_first;
759bbb8a1b4SRichard Henderson     unsigned sizemask, flags;
760afb49896SRichard Henderson     TCGHelperInfo *info;
761afb49896SRichard Henderson 
762afb49896SRichard Henderson     info = g_hash_table_lookup(s->helpers, (gpointer)func);
763bbb8a1b4SRichard Henderson     flags = info->flags;
764bbb8a1b4SRichard Henderson     sizemask = info->sizemask;
7652bece2c8SRichard Henderson 
76634b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
76734b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
76834b1a49cSRichard Henderson     /* We have 64-bit values in one register, but need to pass as two
76934b1a49cSRichard Henderson        separate parameters.  Split them.  */
77034b1a49cSRichard Henderson     int orig_sizemask = sizemask;
77134b1a49cSRichard Henderson     int orig_nargs = nargs;
77234b1a49cSRichard Henderson     TCGv_i64 retl, reth;
77334b1a49cSRichard Henderson 
77434b1a49cSRichard Henderson     TCGV_UNUSED_I64(retl);
77534b1a49cSRichard Henderson     TCGV_UNUSED_I64(reth);
77634b1a49cSRichard Henderson     if (sizemask != 0) {
77734b1a49cSRichard Henderson         TCGArg *split_args = __builtin_alloca(sizeof(TCGArg) * nargs * 2);
77834b1a49cSRichard Henderson         for (i = real_args = 0; i < nargs; ++i) {
77934b1a49cSRichard Henderson             int is_64bit = sizemask & (1 << (i+1)*2);
78034b1a49cSRichard Henderson             if (is_64bit) {
78134b1a49cSRichard Henderson                 TCGv_i64 orig = MAKE_TCGV_I64(args[i]);
78234b1a49cSRichard Henderson                 TCGv_i32 h = tcg_temp_new_i32();
78334b1a49cSRichard Henderson                 TCGv_i32 l = tcg_temp_new_i32();
78434b1a49cSRichard Henderson                 tcg_gen_extr_i64_i32(l, h, orig);
78534b1a49cSRichard Henderson                 split_args[real_args++] = GET_TCGV_I32(h);
78634b1a49cSRichard Henderson                 split_args[real_args++] = GET_TCGV_I32(l);
78734b1a49cSRichard Henderson             } else {
78834b1a49cSRichard Henderson                 split_args[real_args++] = args[i];
78934b1a49cSRichard Henderson             }
79034b1a49cSRichard Henderson         }
79134b1a49cSRichard Henderson         nargs = real_args;
79234b1a49cSRichard Henderson         args = split_args;
79334b1a49cSRichard Henderson         sizemask = 0;
79434b1a49cSRichard Henderson     }
79534b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
7962bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
7972bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
7982bece2c8SRichard Henderson         int is_signed = sizemask & (2 << (i+1)*2);
7992bece2c8SRichard Henderson         if (!is_64bit) {
8002bece2c8SRichard Henderson             TCGv_i64 temp = tcg_temp_new_i64();
8012bece2c8SRichard Henderson             TCGv_i64 orig = MAKE_TCGV_I64(args[i]);
8022bece2c8SRichard Henderson             if (is_signed) {
8032bece2c8SRichard Henderson                 tcg_gen_ext32s_i64(temp, orig);
8042bece2c8SRichard Henderson             } else {
8052bece2c8SRichard Henderson                 tcg_gen_ext32u_i64(temp, orig);
8062bece2c8SRichard Henderson             }
8072bece2c8SRichard Henderson             args[i] = GET_TCGV_I64(temp);
8082bece2c8SRichard Henderson         }
8092bece2c8SRichard Henderson     }
8102bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
8112bece2c8SRichard Henderson 
812c45cb8bbSRichard Henderson     pi_first = pi = s->gen_next_parm_idx;
813a7812ae4Spbrook     if (ret != TCG_CALL_DUMMY_ARG) {
81434b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
81534b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
81634b1a49cSRichard Henderson         if (orig_sizemask & 1) {
81734b1a49cSRichard Henderson             /* The 32-bit ABI is going to return the 64-bit value in
81834b1a49cSRichard Henderson                the %o0/%o1 register pair.  Prepare for this by using
81934b1a49cSRichard Henderson                two return temporaries, and reassemble below.  */
82034b1a49cSRichard Henderson             retl = tcg_temp_new_i64();
82134b1a49cSRichard Henderson             reth = tcg_temp_new_i64();
822c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = GET_TCGV_I64(reth);
823c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = GET_TCGV_I64(retl);
82434b1a49cSRichard Henderson             nb_rets = 2;
82534b1a49cSRichard Henderson         } else {
826c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = ret;
82734b1a49cSRichard Henderson             nb_rets = 1;
82834b1a49cSRichard Henderson         }
82934b1a49cSRichard Henderson #else
83034b1a49cSRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) {
83102eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
832c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = ret + 1;
833c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = ret;
834a7812ae4Spbrook #else
835c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = ret;
836c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = ret + 1;
837a7812ae4Spbrook #endif
838a7812ae4Spbrook             nb_rets = 2;
83934b1a49cSRichard Henderson         } else {
840c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = ret;
841a7812ae4Spbrook             nb_rets = 1;
842a7812ae4Spbrook         }
84334b1a49cSRichard Henderson #endif
844a7812ae4Spbrook     } else {
845a7812ae4Spbrook         nb_rets = 0;
846a7812ae4Spbrook     }
847a7812ae4Spbrook     real_args = 0;
848a7812ae4Spbrook     for (i = 0; i < nargs; i++) {
8492bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
850bbb8a1b4SRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
85139cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS
85239cf05d3Sbellard             /* some targets want aligned 64 bit args */
853ebd486d5Smalc             if (real_args & 1) {
854c45cb8bbSRichard Henderson                 s->gen_opparam_buf[pi++] = TCG_CALL_DUMMY_ARG;
855ebd486d5Smalc                 real_args++;
85639cf05d3Sbellard             }
85739cf05d3Sbellard #endif
8583f90f252SRichard Henderson            /* If stack grows up, then we will be placing successive
8593f90f252SRichard Henderson               arguments at lower addresses, which means we need to
8603f90f252SRichard Henderson               reverse the order compared to how we would normally
8613f90f252SRichard Henderson               treat either big or little-endian.  For those arguments
8623f90f252SRichard Henderson               that will wind up in registers, this still works for
8633f90f252SRichard Henderson               HPPA (the only current STACK_GROWSUP target) since the
8643f90f252SRichard Henderson               argument registers are *also* allocated in decreasing
8653f90f252SRichard Henderson               order.  If another such target is added, this logic may
8663f90f252SRichard Henderson               have to get more complicated to differentiate between
8673f90f252SRichard Henderson               stack arguments and register arguments.  */
86802eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
869c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = args[i] + 1;
870c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = args[i];
871c896fe29Sbellard #else
872c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = args[i];
873c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = args[i] + 1;
874c896fe29Sbellard #endif
875a7812ae4Spbrook             real_args += 2;
8762bece2c8SRichard Henderson             continue;
8772bece2c8SRichard Henderson         }
8782bece2c8SRichard Henderson 
879c45cb8bbSRichard Henderson         s->gen_opparam_buf[pi++] = args[i];
880a7812ae4Spbrook         real_args++;
881c896fe29Sbellard     }
882c45cb8bbSRichard Henderson     s->gen_opparam_buf[pi++] = (uintptr_t)func;
883c45cb8bbSRichard Henderson     s->gen_opparam_buf[pi++] = flags;
884a7812ae4Spbrook 
885c45cb8bbSRichard Henderson     i = s->gen_next_op_idx;
886c45cb8bbSRichard Henderson     tcg_debug_assert(i < OPC_BUF_SIZE);
887c45cb8bbSRichard Henderson     tcg_debug_assert(pi <= OPPARAM_BUF_SIZE);
888a7812ae4Spbrook 
889c45cb8bbSRichard Henderson     /* Set links for sequential allocation during translation.  */
890c45cb8bbSRichard Henderson     s->gen_op_buf[i] = (TCGOp){
891c45cb8bbSRichard Henderson         .opc = INDEX_op_call,
892c45cb8bbSRichard Henderson         .callo = nb_rets,
893c45cb8bbSRichard Henderson         .calli = real_args,
894c45cb8bbSRichard Henderson         .args = pi_first,
895c45cb8bbSRichard Henderson         .prev = i - 1,
896c45cb8bbSRichard Henderson         .next = i + 1
897c45cb8bbSRichard Henderson     };
898c45cb8bbSRichard Henderson 
899c45cb8bbSRichard Henderson     /* Make sure the calli field didn't overflow.  */
900c45cb8bbSRichard Henderson     tcg_debug_assert(s->gen_op_buf[i].calli == real_args);
901c45cb8bbSRichard Henderson 
902dcb8e758SRichard Henderson     s->gen_op_buf[0].prev = i;
903c45cb8bbSRichard Henderson     s->gen_next_op_idx = i + 1;
904c45cb8bbSRichard Henderson     s->gen_next_parm_idx = pi;
9052bece2c8SRichard Henderson 
90634b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
90734b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
90834b1a49cSRichard Henderson     /* Free all of the parts we allocated above.  */
90934b1a49cSRichard Henderson     for (i = real_args = 0; i < orig_nargs; ++i) {
91034b1a49cSRichard Henderson         int is_64bit = orig_sizemask & (1 << (i+1)*2);
91134b1a49cSRichard Henderson         if (is_64bit) {
91234b1a49cSRichard Henderson             TCGv_i32 h = MAKE_TCGV_I32(args[real_args++]);
91334b1a49cSRichard Henderson             TCGv_i32 l = MAKE_TCGV_I32(args[real_args++]);
91434b1a49cSRichard Henderson             tcg_temp_free_i32(h);
91534b1a49cSRichard Henderson             tcg_temp_free_i32(l);
91634b1a49cSRichard Henderson         } else {
91734b1a49cSRichard Henderson             real_args++;
91834b1a49cSRichard Henderson         }
91934b1a49cSRichard Henderson     }
92034b1a49cSRichard Henderson     if (orig_sizemask & 1) {
92134b1a49cSRichard Henderson         /* The 32-bit ABI returned two 32-bit pieces.  Re-assemble them.
92234b1a49cSRichard Henderson            Note that describing these as TCGv_i64 eliminates an unnecessary
92334b1a49cSRichard Henderson            zero-extension that tcg_gen_concat_i32_i64 would create.  */
92434b1a49cSRichard Henderson         tcg_gen_concat32_i64(MAKE_TCGV_I64(ret), retl, reth);
92534b1a49cSRichard Henderson         tcg_temp_free_i64(retl);
92634b1a49cSRichard Henderson         tcg_temp_free_i64(reth);
92734b1a49cSRichard Henderson     }
92834b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
9292bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
9302bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
9312bece2c8SRichard Henderson         if (!is_64bit) {
9322bece2c8SRichard Henderson             TCGv_i64 temp = MAKE_TCGV_I64(args[i]);
9332bece2c8SRichard Henderson             tcg_temp_free_i64(temp);
9342bece2c8SRichard Henderson         }
9352bece2c8SRichard Henderson     }
9362bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
937a7812ae4Spbrook }
938c896fe29Sbellard 
9398fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
940c896fe29Sbellard {
941c896fe29Sbellard     int i;
942c896fe29Sbellard     TCGTemp *ts;
943c896fe29Sbellard     for(i = 0; i < s->nb_globals; i++) {
944c896fe29Sbellard         ts = &s->temps[i];
945c896fe29Sbellard         if (ts->fixed_reg) {
946c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
947c896fe29Sbellard         } else {
948c896fe29Sbellard             ts->val_type = TEMP_VAL_MEM;
949c896fe29Sbellard         }
950c896fe29Sbellard     }
951e8996ee0Sbellard     for(i = s->nb_globals; i < s->nb_temps; i++) {
952e8996ee0Sbellard         ts = &s->temps[i];
9537dfd8c6aSAurelien Jarno         if (ts->temp_local) {
9547dfd8c6aSAurelien Jarno             ts->val_type = TEMP_VAL_MEM;
9557dfd8c6aSAurelien Jarno         } else {
956e8996ee0Sbellard             ts->val_type = TEMP_VAL_DEAD;
9577dfd8c6aSAurelien Jarno         }
958e8996ee0Sbellard         ts->mem_allocated = 0;
959e8996ee0Sbellard         ts->fixed_reg = 0;
960e8996ee0Sbellard     }
961f8b2f202SRichard Henderson 
962f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
963c896fe29Sbellard }
964c896fe29Sbellard 
965f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
966f8b2f202SRichard Henderson                                  TCGTemp *ts)
967c896fe29Sbellard {
968f8b2f202SRichard Henderson     int idx = temp_idx(s, ts);
969ac56dd48Spbrook 
970ac56dd48Spbrook     if (idx < s->nb_globals) {
971ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
972f8b2f202SRichard Henderson     } else if (ts->temp_local) {
973641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
974f8b2f202SRichard Henderson     } else {
975ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
976c896fe29Sbellard     }
977c896fe29Sbellard     return buf;
978c896fe29Sbellard }
979c896fe29Sbellard 
980f8b2f202SRichard Henderson static char *tcg_get_arg_str_idx(TCGContext *s, char *buf,
981f8b2f202SRichard Henderson                                  int buf_size, int idx)
982f8b2f202SRichard Henderson {
983eabb7b91SAurelien Jarno     tcg_debug_assert(idx >= 0 && idx < s->nb_temps);
984f8b2f202SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, &s->temps[idx]);
985f8b2f202SRichard Henderson }
986f8b2f202SRichard Henderson 
9876e085f72SRichard Henderson /* Find helper name.  */
9886e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val)
989e8996ee0Sbellard {
9906e085f72SRichard Henderson     const char *ret = NULL;
9916e085f72SRichard Henderson     if (s->helpers) {
99272866e82SRichard Henderson         TCGHelperInfo *info = g_hash_table_lookup(s->helpers, (gpointer)val);
99372866e82SRichard Henderson         if (info) {
99472866e82SRichard Henderson             ret = info->name;
99572866e82SRichard Henderson         }
996e8996ee0Sbellard     }
9976e085f72SRichard Henderson     return ret;
9984dc81f28Sbellard }
9994dc81f28Sbellard 
1000f48f3edeSblueswir1 static const char * const cond_name[] =
1001f48f3edeSblueswir1 {
10020aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
10030aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
1004f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
1005f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
1006f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
1007f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
1008f48f3edeSblueswir1     [TCG_COND_LE] = "le",
1009f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
1010f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
1011f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
1012f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
1013f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
1014f48f3edeSblueswir1 };
1015f48f3edeSblueswir1 
1016f713d6adSRichard Henderson static const char * const ldst_name[] =
1017f713d6adSRichard Henderson {
1018f713d6adSRichard Henderson     [MO_UB]   = "ub",
1019f713d6adSRichard Henderson     [MO_SB]   = "sb",
1020f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
1021f713d6adSRichard Henderson     [MO_LESW] = "lesw",
1022f713d6adSRichard Henderson     [MO_LEUL] = "leul",
1023f713d6adSRichard Henderson     [MO_LESL] = "lesl",
1024f713d6adSRichard Henderson     [MO_LEQ]  = "leq",
1025f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
1026f713d6adSRichard Henderson     [MO_BESW] = "besw",
1027f713d6adSRichard Henderson     [MO_BEUL] = "beul",
1028f713d6adSRichard Henderson     [MO_BESL] = "besl",
1029f713d6adSRichard Henderson     [MO_BEQ]  = "beq",
1030f713d6adSRichard Henderson };
1031f713d6adSRichard Henderson 
10321f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
10331f00b27fSSergey Sorokin #ifdef ALIGNED_ONLY
10341f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
10351f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
10361f00b27fSSergey Sorokin #else
10371f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
10381f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
10391f00b27fSSergey Sorokin #endif
10401f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
10411f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
10421f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
10431f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
10441f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
10451f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
10461f00b27fSSergey Sorokin };
10471f00b27fSSergey Sorokin 
1048eeacee4dSBlue Swirl void tcg_dump_ops(TCGContext *s)
1049c896fe29Sbellard {
1050c896fe29Sbellard     char buf[128];
1051c45cb8bbSRichard Henderson     TCGOp *op;
1052c45cb8bbSRichard Henderson     int oi;
1053c896fe29Sbellard 
1054dcb8e758SRichard Henderson     for (oi = s->gen_op_buf[0].next; oi != 0; oi = op->next) {
1055c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
1056c45cb8bbSRichard Henderson         const TCGOpDef *def;
1057c45cb8bbSRichard Henderson         const TCGArg *args;
1058c45cb8bbSRichard Henderson         TCGOpcode c;
1059bdfb460eSRichard Henderson         int col = 0;
1060c45cb8bbSRichard Henderson 
1061c45cb8bbSRichard Henderson         op = &s->gen_op_buf[oi];
1062c45cb8bbSRichard Henderson         c = op->opc;
1063c896fe29Sbellard         def = &tcg_op_defs[c];
1064c45cb8bbSRichard Henderson         args = &s->gen_opparam_buf[op->args];
1065c45cb8bbSRichard Henderson 
1066765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
1067bdfb460eSRichard Henderson             col += qemu_log("%s ----", oi != s->gen_op_buf[0].next ? "\n" : "");
10689aef40edSRichard Henderson 
10699aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
10709aef40edSRichard Henderson                 target_ulong a;
10717e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
10729aef40edSRichard Henderson                 a = ((target_ulong)args[i * 2 + 1] << 32) | args[i * 2];
10737e4597d7Sbellard #else
10749aef40edSRichard Henderson                 a = args[i];
10757e4597d7Sbellard #endif
1076bdfb460eSRichard Henderson                 col += qemu_log(" " TARGET_FMT_lx, a);
1077eeacee4dSBlue Swirl             }
10787e4597d7Sbellard         } else if (c == INDEX_op_call) {
1079c896fe29Sbellard             /* variable number of arguments */
1080c45cb8bbSRichard Henderson             nb_oargs = op->callo;
1081c45cb8bbSRichard Henderson             nb_iargs = op->calli;
1082c896fe29Sbellard             nb_cargs = def->nb_cargs;
1083b03cce8eSbellard 
1084cf066674SRichard Henderson             /* function name, flags, out args */
1085bdfb460eSRichard Henderson             col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name,
1086cf066674SRichard Henderson                             tcg_find_helper(s, args[nb_oargs + nb_iargs]),
1087cf066674SRichard Henderson                             args[nb_oargs + nb_iargs + 1], nb_oargs);
1088b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
1089bdfb460eSRichard Henderson                 col += qemu_log(",%s", tcg_get_arg_str_idx(s, buf, sizeof(buf),
1090eeacee4dSBlue Swirl                                                            args[i]));
1091b03cce8eSbellard             }
1092cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
1093cf066674SRichard Henderson                 TCGArg arg = args[nb_oargs + i];
1094cf066674SRichard Henderson                 const char *t = "<dummy>";
1095cf066674SRichard Henderson                 if (arg != TCG_CALL_DUMMY_ARG) {
1096cf066674SRichard Henderson                     t = tcg_get_arg_str_idx(s, buf, sizeof(buf), arg);
1097b03cce8eSbellard                 }
1098bdfb460eSRichard Henderson                 col += qemu_log(",%s", t);
1099e8996ee0Sbellard             }
1100b03cce8eSbellard         } else {
1101bdfb460eSRichard Henderson             col += qemu_log(" %s ", def->name);
1102c45cb8bbSRichard Henderson 
1103c896fe29Sbellard             nb_oargs = def->nb_oargs;
1104c896fe29Sbellard             nb_iargs = def->nb_iargs;
1105c896fe29Sbellard             nb_cargs = def->nb_cargs;
1106c896fe29Sbellard 
1107c896fe29Sbellard             k = 0;
1108c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
1109eeacee4dSBlue Swirl                 if (k != 0) {
1110bdfb460eSRichard Henderson                     col += qemu_log(",");
1111eeacee4dSBlue Swirl                 }
1112bdfb460eSRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf),
1113eeacee4dSBlue Swirl                                                           args[k++]));
1114c896fe29Sbellard             }
1115c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
1116eeacee4dSBlue Swirl                 if (k != 0) {
1117bdfb460eSRichard Henderson                     col += qemu_log(",");
1118eeacee4dSBlue Swirl                 }
1119bdfb460eSRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf),
1120eeacee4dSBlue Swirl                                                           args[k++]));
1121c896fe29Sbellard             }
1122be210acbSRichard Henderson             switch (c) {
1123be210acbSRichard Henderson             case INDEX_op_brcond_i32:
1124ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
1125ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
1126be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
1127be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
1128ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
1129be210acbSRichard Henderson             case INDEX_op_setcond_i64:
1130ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
1131eeacee4dSBlue Swirl                 if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]]) {
1132bdfb460eSRichard Henderson                     col += qemu_log(",%s", cond_name[args[k++]]);
1133eeacee4dSBlue Swirl                 } else {
1134bdfb460eSRichard Henderson                     col += qemu_log(",$0x%" TCG_PRIlx, args[k++]);
1135eeacee4dSBlue Swirl                 }
1136f48f3edeSblueswir1                 i = 1;
1137be210acbSRichard Henderson                 break;
1138f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
1139f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
1140f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
1141f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
114259227d5dSRichard Henderson                 {
114359227d5dSRichard Henderson                     TCGMemOpIdx oi = args[k++];
114459227d5dSRichard Henderson                     TCGMemOp op = get_memop(oi);
114559227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
114659227d5dSRichard Henderson 
114759c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
1148bdfb460eSRichard Henderson                         col += qemu_log(",$0x%x,%u", op, ix);
114959c4b7e8SRichard Henderson                     } else {
11501f00b27fSSergey Sorokin                         const char *s_al, *s_op;
11511f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
115259c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
1153bdfb460eSRichard Henderson                         col += qemu_log(",%s%s,%u", s_al, s_op, ix);
1154f713d6adSRichard Henderson                     }
1155f713d6adSRichard Henderson                     i = 1;
115659227d5dSRichard Henderson                 }
1157f713d6adSRichard Henderson                 break;
1158be210acbSRichard Henderson             default:
1159f48f3edeSblueswir1                 i = 0;
1160be210acbSRichard Henderson                 break;
1161be210acbSRichard Henderson             }
116251e3972cSRichard Henderson             switch (c) {
116351e3972cSRichard Henderson             case INDEX_op_set_label:
116451e3972cSRichard Henderson             case INDEX_op_br:
116551e3972cSRichard Henderson             case INDEX_op_brcond_i32:
116651e3972cSRichard Henderson             case INDEX_op_brcond_i64:
116751e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
1168bdfb460eSRichard Henderson                 col += qemu_log("%s$L%d", k ? "," : "", arg_label(args[k])->id);
116951e3972cSRichard Henderson                 i++, k++;
117051e3972cSRichard Henderson                 break;
117151e3972cSRichard Henderson             default:
117251e3972cSRichard Henderson                 break;
1173eeacee4dSBlue Swirl             }
117451e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
1175bdfb460eSRichard Henderson                 col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", args[k]);
1176bdfb460eSRichard Henderson             }
1177bdfb460eSRichard Henderson         }
1178bdfb460eSRichard Henderson         if (op->life) {
1179bdfb460eSRichard Henderson             unsigned life = op->life;
1180bdfb460eSRichard Henderson 
1181bdfb460eSRichard Henderson             for (; col < 48; ++col) {
1182bdfb460eSRichard Henderson                 putc(' ', qemu_logfile);
1183bdfb460eSRichard Henderson             }
1184bdfb460eSRichard Henderson 
1185bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
1186bdfb460eSRichard Henderson                 qemu_log("  sync:");
1187bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
1188bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
1189bdfb460eSRichard Henderson                         qemu_log(" %d", i);
1190bdfb460eSRichard Henderson                     }
1191bdfb460eSRichard Henderson                 }
1192bdfb460eSRichard Henderson             }
1193bdfb460eSRichard Henderson             life /= DEAD_ARG;
1194bdfb460eSRichard Henderson             if (life) {
1195bdfb460eSRichard Henderson                 qemu_log("  dead:");
1196bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
1197bdfb460eSRichard Henderson                     if (life & 1) {
1198bdfb460eSRichard Henderson                         qemu_log(" %d", i);
1199bdfb460eSRichard Henderson                     }
1200bdfb460eSRichard Henderson                 }
1201c896fe29Sbellard             }
1202b03cce8eSbellard         }
1203eeacee4dSBlue Swirl         qemu_log("\n");
1204c896fe29Sbellard     }
1205c896fe29Sbellard }
1206c896fe29Sbellard 
1207c896fe29Sbellard /* we give more priority to constraints with less registers */
1208c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
1209c896fe29Sbellard {
1210c896fe29Sbellard     const TCGArgConstraint *arg_ct;
1211c896fe29Sbellard 
1212c896fe29Sbellard     int i, n;
1213c896fe29Sbellard     arg_ct = &def->args_ct[k];
1214c896fe29Sbellard     if (arg_ct->ct & TCG_CT_ALIAS) {
1215c896fe29Sbellard         /* an alias is equivalent to a single register */
1216c896fe29Sbellard         n = 1;
1217c896fe29Sbellard     } else {
1218c896fe29Sbellard         if (!(arg_ct->ct & TCG_CT_REG))
1219c896fe29Sbellard             return 0;
1220c896fe29Sbellard         n = 0;
1221c896fe29Sbellard         for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
1222c896fe29Sbellard             if (tcg_regset_test_reg(arg_ct->u.regs, i))
1223c896fe29Sbellard                 n++;
1224c896fe29Sbellard         }
1225c896fe29Sbellard     }
1226c896fe29Sbellard     return TCG_TARGET_NB_REGS - n + 1;
1227c896fe29Sbellard }
1228c896fe29Sbellard 
1229c896fe29Sbellard /* sort from highest priority to lowest */
1230c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
1231c896fe29Sbellard {
1232c896fe29Sbellard     int i, j, p1, p2, tmp;
1233c896fe29Sbellard 
1234c896fe29Sbellard     for(i = 0; i < n; i++)
1235c896fe29Sbellard         def->sorted_args[start + i] = start + i;
1236c896fe29Sbellard     if (n <= 1)
1237c896fe29Sbellard         return;
1238c896fe29Sbellard     for(i = 0; i < n - 1; i++) {
1239c896fe29Sbellard         for(j = i + 1; j < n; j++) {
1240c896fe29Sbellard             p1 = get_constraint_priority(def, def->sorted_args[start + i]);
1241c896fe29Sbellard             p2 = get_constraint_priority(def, def->sorted_args[start + j]);
1242c896fe29Sbellard             if (p1 < p2) {
1243c896fe29Sbellard                 tmp = def->sorted_args[start + i];
1244c896fe29Sbellard                 def->sorted_args[start + i] = def->sorted_args[start + j];
1245c896fe29Sbellard                 def->sorted_args[start + j] = tmp;
1246c896fe29Sbellard             }
1247c896fe29Sbellard         }
1248c896fe29Sbellard     }
1249c896fe29Sbellard }
1250c896fe29Sbellard 
1251f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
1252c896fe29Sbellard {
1253a9751609SRichard Henderson     TCGOpcode op;
1254c896fe29Sbellard 
1255f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
1256f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
1257f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
1258069ea736SRichard Henderson         TCGType type;
1259069ea736SRichard Henderson         int i, nb_args;
1260f69d277eSRichard Henderson 
1261f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
1262f69d277eSRichard Henderson             continue;
1263f69d277eSRichard Henderson         }
1264f69d277eSRichard Henderson 
1265c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
1266f69d277eSRichard Henderson         if (nb_args == 0) {
1267f69d277eSRichard Henderson             continue;
1268f69d277eSRichard Henderson         }
1269f69d277eSRichard Henderson 
1270f69d277eSRichard Henderson         tdefs = tcg_target_op_def(op);
1271f69d277eSRichard Henderson         /* Missing TCGTargetOpDef entry. */
1272f69d277eSRichard Henderson         tcg_debug_assert(tdefs != NULL);
1273f69d277eSRichard Henderson 
1274069ea736SRichard Henderson         type = (def->flags & TCG_OPF_64BIT ? TCG_TYPE_I64 : TCG_TYPE_I32);
1275c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
1276f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
1277f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
1278eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
1279f69d277eSRichard Henderson 
1280c896fe29Sbellard             tcg_regset_clear(def->args_ct[i].u.regs);
1281c896fe29Sbellard             def->args_ct[i].ct = 0;
128217280ff4SRichard Henderson             while (*ct_str != '\0') {
128317280ff4SRichard Henderson                 switch(*ct_str) {
128417280ff4SRichard Henderson                 case '0' ... '9':
128517280ff4SRichard Henderson                     {
128617280ff4SRichard Henderson                         int oarg = *ct_str - '0';
128717280ff4SRichard Henderson                         tcg_debug_assert(ct_str == tdefs->args_ct_str[i]);
1288eabb7b91SAurelien Jarno                         tcg_debug_assert(oarg < def->nb_oargs);
1289eabb7b91SAurelien Jarno                         tcg_debug_assert(def->args_ct[oarg].ct & TCG_CT_REG);
129017280ff4SRichard Henderson                         /* TCG_CT_ALIAS is for the output arguments.
129117280ff4SRichard Henderson                            The input is tagged with TCG_CT_IALIAS. */
1292c896fe29Sbellard                         def->args_ct[i] = def->args_ct[oarg];
129317280ff4SRichard Henderson                         def->args_ct[oarg].ct |= TCG_CT_ALIAS;
12945ff9d6a4Sbellard                         def->args_ct[oarg].alias_index = i;
1295c896fe29Sbellard                         def->args_ct[i].ct |= TCG_CT_IALIAS;
12965ff9d6a4Sbellard                         def->args_ct[i].alias_index = oarg;
129717280ff4SRichard Henderson                     }
129817280ff4SRichard Henderson                     ct_str++;
1299c896fe29Sbellard                     break;
130082790a87SRichard Henderson                 case '&':
130182790a87SRichard Henderson                     def->args_ct[i].ct |= TCG_CT_NEWREG;
130282790a87SRichard Henderson                     ct_str++;
130382790a87SRichard Henderson                     break;
1304c896fe29Sbellard                 case 'i':
1305c896fe29Sbellard                     def->args_ct[i].ct |= TCG_CT_CONST;
1306c896fe29Sbellard                     ct_str++;
1307c896fe29Sbellard                     break;
1308c896fe29Sbellard                 default:
1309069ea736SRichard Henderson                     ct_str = target_parse_constraint(&def->args_ct[i],
1310069ea736SRichard Henderson                                                      ct_str, type);
1311f69d277eSRichard Henderson                     /* Typo in TCGTargetOpDef constraint. */
1312069ea736SRichard Henderson                     tcg_debug_assert(ct_str != NULL);
1313c896fe29Sbellard                 }
1314c896fe29Sbellard             }
1315c896fe29Sbellard         }
1316c896fe29Sbellard 
1317c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
1318eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
1319c68aaa18SStefan Weil 
1320c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
1321c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
1322c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
1323c896fe29Sbellard     }
1324c896fe29Sbellard }
1325c896fe29Sbellard 
13260c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
13270c627cdcSRichard Henderson {
13280c627cdcSRichard Henderson     int next = op->next;
13290c627cdcSRichard Henderson     int prev = op->prev;
13300c627cdcSRichard Henderson 
1331dcb8e758SRichard Henderson     /* We should never attempt to remove the list terminator.  */
1332dcb8e758SRichard Henderson     tcg_debug_assert(op != &s->gen_op_buf[0]);
13330c627cdcSRichard Henderson 
1334dcb8e758SRichard Henderson     s->gen_op_buf[next].prev = prev;
1335dcb8e758SRichard Henderson     s->gen_op_buf[prev].next = next;
1336dcb8e758SRichard Henderson 
1337dcb8e758SRichard Henderson     memset(op, 0, sizeof(*op));
13380c627cdcSRichard Henderson 
13390c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
13400c627cdcSRichard Henderson     s->del_op_count++;
13410c627cdcSRichard Henderson #endif
13420c627cdcSRichard Henderson }
13430c627cdcSRichard Henderson 
13445a18407fSRichard Henderson TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op,
13455a18407fSRichard Henderson                             TCGOpcode opc, int nargs)
13465a18407fSRichard Henderson {
13475a18407fSRichard Henderson     int oi = s->gen_next_op_idx;
13485a18407fSRichard Henderson     int pi = s->gen_next_parm_idx;
13495a18407fSRichard Henderson     int prev = old_op->prev;
13505a18407fSRichard Henderson     int next = old_op - s->gen_op_buf;
13515a18407fSRichard Henderson     TCGOp *new_op;
13525a18407fSRichard Henderson 
13535a18407fSRichard Henderson     tcg_debug_assert(oi < OPC_BUF_SIZE);
13545a18407fSRichard Henderson     tcg_debug_assert(pi + nargs <= OPPARAM_BUF_SIZE);
13555a18407fSRichard Henderson     s->gen_next_op_idx = oi + 1;
13565a18407fSRichard Henderson     s->gen_next_parm_idx = pi + nargs;
13575a18407fSRichard Henderson 
13585a18407fSRichard Henderson     new_op = &s->gen_op_buf[oi];
13595a18407fSRichard Henderson     *new_op = (TCGOp){
13605a18407fSRichard Henderson         .opc = opc,
13615a18407fSRichard Henderson         .args = pi,
13625a18407fSRichard Henderson         .prev = prev,
13635a18407fSRichard Henderson         .next = next
13645a18407fSRichard Henderson     };
13655a18407fSRichard Henderson     s->gen_op_buf[prev].next = oi;
13665a18407fSRichard Henderson     old_op->prev = oi;
13675a18407fSRichard Henderson 
13685a18407fSRichard Henderson     return new_op;
13695a18407fSRichard Henderson }
13705a18407fSRichard Henderson 
13715a18407fSRichard Henderson TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op,
13725a18407fSRichard Henderson                            TCGOpcode opc, int nargs)
13735a18407fSRichard Henderson {
13745a18407fSRichard Henderson     int oi = s->gen_next_op_idx;
13755a18407fSRichard Henderson     int pi = s->gen_next_parm_idx;
13765a18407fSRichard Henderson     int prev = old_op - s->gen_op_buf;
13775a18407fSRichard Henderson     int next = old_op->next;
13785a18407fSRichard Henderson     TCGOp *new_op;
13795a18407fSRichard Henderson 
13805a18407fSRichard Henderson     tcg_debug_assert(oi < OPC_BUF_SIZE);
13815a18407fSRichard Henderson     tcg_debug_assert(pi + nargs <= OPPARAM_BUF_SIZE);
13825a18407fSRichard Henderson     s->gen_next_op_idx = oi + 1;
13835a18407fSRichard Henderson     s->gen_next_parm_idx = pi + nargs;
13845a18407fSRichard Henderson 
13855a18407fSRichard Henderson     new_op = &s->gen_op_buf[oi];
13865a18407fSRichard Henderson     *new_op = (TCGOp){
13875a18407fSRichard Henderson         .opc = opc,
13885a18407fSRichard Henderson         .args = pi,
13895a18407fSRichard Henderson         .prev = prev,
13905a18407fSRichard Henderson         .next = next
13915a18407fSRichard Henderson     };
13925a18407fSRichard Henderson     s->gen_op_buf[next].prev = oi;
13935a18407fSRichard Henderson     old_op->next = oi;
13945a18407fSRichard Henderson 
13955a18407fSRichard Henderson     return new_op;
13965a18407fSRichard Henderson }
13975a18407fSRichard Henderson 
1398c70fbf0aSRichard Henderson #define TS_DEAD  1
1399c70fbf0aSRichard Henderson #define TS_MEM   2
1400c70fbf0aSRichard Henderson 
14015a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
14025a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
14035a18407fSRichard Henderson 
14049c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
14059c43b68dSAurelien Jarno    should be in memory. */
1406c70fbf0aSRichard Henderson static inline void tcg_la_func_end(TCGContext *s, uint8_t *temp_state)
1407c896fe29Sbellard {
1408c70fbf0aSRichard Henderson     memset(temp_state, TS_DEAD | TS_MEM, s->nb_globals);
1409c70fbf0aSRichard Henderson     memset(temp_state + s->nb_globals, TS_DEAD, s->nb_temps - s->nb_globals);
1410c896fe29Sbellard }
1411c896fe29Sbellard 
14129c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
14139c43b68dSAurelien Jarno    and local temps should be in memory. */
1414c70fbf0aSRichard Henderson static inline void tcg_la_bb_end(TCGContext *s, uint8_t *temp_state)
1415641d5fbeSbellard {
1416c70fbf0aSRichard Henderson     int i, n;
1417641d5fbeSbellard 
1418c70fbf0aSRichard Henderson     tcg_la_func_end(s, temp_state);
1419c70fbf0aSRichard Henderson     for (i = s->nb_globals, n = s->nb_temps; i < n; i++) {
1420c70fbf0aSRichard Henderson         if (s->temps[i].temp_local) {
1421c70fbf0aSRichard Henderson             temp_state[i] |= TS_MEM;
1422c70fbf0aSRichard Henderson         }
1423641d5fbeSbellard     }
1424641d5fbeSbellard }
1425641d5fbeSbellard 
1426a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
1427c896fe29Sbellard    given input arguments is dead. Instructions updating dead
1428c896fe29Sbellard    temporaries are removed. */
14295a18407fSRichard Henderson static void liveness_pass_1(TCGContext *s, uint8_t *temp_state)
1430c896fe29Sbellard {
1431c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
14325a18407fSRichard Henderson     int oi, oi_prev;
1433c896fe29Sbellard 
1434c70fbf0aSRichard Henderson     tcg_la_func_end(s, temp_state);
1435c896fe29Sbellard 
1436dcb8e758SRichard Henderson     for (oi = s->gen_op_buf[0].prev; oi != 0; oi = oi_prev) {
1437c45cb8bbSRichard Henderson         int i, nb_iargs, nb_oargs;
1438c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
1439c45cb8bbSRichard Henderson         bool have_opc_new2;
1440a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
1441c45cb8bbSRichard Henderson         TCGArg arg;
1442c45cb8bbSRichard Henderson 
1443c45cb8bbSRichard Henderson         TCGOp * const op = &s->gen_op_buf[oi];
1444c45cb8bbSRichard Henderson         TCGArg * const args = &s->gen_opparam_buf[op->args];
1445c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
1446c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
1447c45cb8bbSRichard Henderson 
1448c45cb8bbSRichard Henderson         oi_prev = op->prev;
1449c45cb8bbSRichard Henderson 
1450c45cb8bbSRichard Henderson         switch (opc) {
1451c896fe29Sbellard         case INDEX_op_call:
1452c6e113f5Sbellard             {
1453c6e113f5Sbellard                 int call_flags;
1454c6e113f5Sbellard 
1455c45cb8bbSRichard Henderson                 nb_oargs = op->callo;
1456c45cb8bbSRichard Henderson                 nb_iargs = op->calli;
1457cf066674SRichard Henderson                 call_flags = args[nb_oargs + nb_iargs + 1];
1458c6e113f5Sbellard 
1459c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
146078505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
1461c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
1462c6e113f5Sbellard                         arg = args[i];
1463c70fbf0aSRichard Henderson                         if (temp_state[arg] != TS_DEAD) {
1464c6e113f5Sbellard                             goto do_not_remove_call;
1465c6e113f5Sbellard                         }
14669c43b68dSAurelien Jarno                     }
1467c45cb8bbSRichard Henderson                     goto do_remove;
1468c6e113f5Sbellard                 } else {
1469c6e113f5Sbellard                 do_not_remove_call:
1470c896fe29Sbellard 
1471c896fe29Sbellard                     /* output args are dead */
1472c896fe29Sbellard                     for (i = 0; i < nb_oargs; i++) {
1473c896fe29Sbellard                         arg = args[i];
1474c70fbf0aSRichard Henderson                         if (temp_state[arg] & TS_DEAD) {
1475a1b3c48dSRichard Henderson                             arg_life |= DEAD_ARG << i;
14766b64b624SAurelien Jarno                         }
1477c70fbf0aSRichard Henderson                         if (temp_state[arg] & TS_MEM) {
1478a1b3c48dSRichard Henderson                             arg_life |= SYNC_ARG << i;
14799c43b68dSAurelien Jarno                         }
1480c70fbf0aSRichard Henderson                         temp_state[arg] = TS_DEAD;
1481c896fe29Sbellard                     }
1482c896fe29Sbellard 
148378505279SAurelien Jarno                     if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
148478505279SAurelien Jarno                                         TCG_CALL_NO_READ_GLOBALS))) {
14859c43b68dSAurelien Jarno                         /* globals should go back to memory */
1486c70fbf0aSRichard Henderson                         memset(temp_state, TS_DEAD | TS_MEM, nb_globals);
1487c70fbf0aSRichard Henderson                     } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
1488c70fbf0aSRichard Henderson                         /* globals should be synced to memory */
1489c70fbf0aSRichard Henderson                         for (i = 0; i < nb_globals; i++) {
1490c70fbf0aSRichard Henderson                             temp_state[i] |= TS_MEM;
1491c70fbf0aSRichard Henderson                         }
1492b9c18f56Saurel32                     }
1493c896fe29Sbellard 
1494c19f47bfSAurelien Jarno                     /* record arguments that die in this helper */
1495866cb6cbSAurelien Jarno                     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
1496866cb6cbSAurelien Jarno                         arg = args[i];
149739cf05d3Sbellard                         if (arg != TCG_CALL_DUMMY_ARG) {
1498c70fbf0aSRichard Henderson                             if (temp_state[arg] & TS_DEAD) {
1499a1b3c48dSRichard Henderson                                 arg_life |= DEAD_ARG << i;
1500c896fe29Sbellard                             }
1501c896fe29Sbellard                         }
150239cf05d3Sbellard                     }
150367cc32ebSVeres Lajos                     /* input arguments are live for preceding opcodes */
1504c70fbf0aSRichard Henderson                     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
1505c19f47bfSAurelien Jarno                         arg = args[i];
1506c70fbf0aSRichard Henderson                         if (arg != TCG_CALL_DUMMY_ARG) {
1507c70fbf0aSRichard Henderson                             temp_state[arg] &= ~TS_DEAD;
1508c70fbf0aSRichard Henderson                         }
1509c19f47bfSAurelien Jarno                     }
1510c6e113f5Sbellard                 }
1511c6e113f5Sbellard             }
1512c896fe29Sbellard             break;
1513765b842aSRichard Henderson         case INDEX_op_insn_start:
1514c896fe29Sbellard             break;
15155ff9d6a4Sbellard         case INDEX_op_discard:
15165ff9d6a4Sbellard             /* mark the temporary as dead */
1517c70fbf0aSRichard Henderson             temp_state[args[0]] = TS_DEAD;
15185ff9d6a4Sbellard             break;
15191305c451SRichard Henderson 
15201305c451SRichard Henderson         case INDEX_op_add2_i32:
1521c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
1522f1fae40cSRichard Henderson             goto do_addsub2;
15231305c451SRichard Henderson         case INDEX_op_sub2_i32:
1524c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
1525f1fae40cSRichard Henderson             goto do_addsub2;
1526f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
1527c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
1528f1fae40cSRichard Henderson             goto do_addsub2;
1529f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
1530c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
1531f1fae40cSRichard Henderson         do_addsub2:
15321305c451SRichard Henderson             nb_iargs = 4;
15331305c451SRichard Henderson             nb_oargs = 2;
15341305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
15351305c451SRichard Henderson                the low part.  The result can be optimized to a simple
15361305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
15371305c451SRichard Henderson                cpu mode is set to 32 bit.  */
1538c70fbf0aSRichard Henderson             if (temp_state[args[1]] == TS_DEAD) {
1539c70fbf0aSRichard Henderson                 if (temp_state[args[0]] == TS_DEAD) {
15401305c451SRichard Henderson                     goto do_remove;
15411305c451SRichard Henderson                 }
1542c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
1543c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
1544c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
15451305c451SRichard Henderson                 args[1] = args[2];
15461305c451SRichard Henderson                 args[2] = args[4];
15471305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
15481305c451SRichard Henderson                 nb_iargs = 2;
15491305c451SRichard Henderson                 nb_oargs = 1;
15501305c451SRichard Henderson             }
15511305c451SRichard Henderson             goto do_not_remove;
15521305c451SRichard Henderson 
15531414968aSRichard Henderson         case INDEX_op_mulu2_i32:
1554c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
1555c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
1556c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
155703271524SRichard Henderson             goto do_mul2;
1558f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
1559c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
1560c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
1561c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
1562f1fae40cSRichard Henderson             goto do_mul2;
1563f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
1564c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
1565c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
1566c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
156703271524SRichard Henderson             goto do_mul2;
1568f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
1569c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
1570c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
1571c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
157203271524SRichard Henderson             goto do_mul2;
1573f1fae40cSRichard Henderson         do_mul2:
15741414968aSRichard Henderson             nb_iargs = 2;
15751414968aSRichard Henderson             nb_oargs = 2;
1576c70fbf0aSRichard Henderson             if (temp_state[args[1]] == TS_DEAD) {
1577c70fbf0aSRichard Henderson                 if (temp_state[args[0]] == TS_DEAD) {
157803271524SRichard Henderson                     /* Both parts of the operation are dead.  */
15791414968aSRichard Henderson                     goto do_remove;
15801414968aSRichard Henderson                 }
158103271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
1582c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
15831414968aSRichard Henderson                 args[1] = args[2];
15841414968aSRichard Henderson                 args[2] = args[3];
1585c70fbf0aSRichard Henderson             } else if (temp_state[args[0]] == TS_DEAD && have_opc_new2) {
158603271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
1587c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
158803271524SRichard Henderson                 args[0] = args[1];
158903271524SRichard Henderson                 args[1] = args[2];
159003271524SRichard Henderson                 args[2] = args[3];
159103271524SRichard Henderson             } else {
159203271524SRichard Henderson                 goto do_not_remove;
159303271524SRichard Henderson             }
159403271524SRichard Henderson             /* Mark the single-word operation live.  */
15951414968aSRichard Henderson             nb_oargs = 1;
15961414968aSRichard Henderson             goto do_not_remove;
15971414968aSRichard Henderson 
1598c896fe29Sbellard         default:
15991305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1600c896fe29Sbellard             nb_iargs = def->nb_iargs;
1601c896fe29Sbellard             nb_oargs = def->nb_oargs;
1602c896fe29Sbellard 
1603c896fe29Sbellard             /* Test if the operation can be removed because all
16045ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
16055ff9d6a4Sbellard                implies side effects */
16065ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
1607c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
1608c70fbf0aSRichard Henderson                     if (temp_state[args[i]] != TS_DEAD) {
1609c896fe29Sbellard                         goto do_not_remove;
1610c896fe29Sbellard                     }
16119c43b68dSAurelien Jarno                 }
16121305c451SRichard Henderson             do_remove:
16130c627cdcSRichard Henderson                 tcg_op_remove(s, op);
1614c896fe29Sbellard             } else {
1615c896fe29Sbellard             do_not_remove:
1616c896fe29Sbellard                 /* output args are dead */
1617c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
1618c896fe29Sbellard                     arg = args[i];
1619c70fbf0aSRichard Henderson                     if (temp_state[arg] & TS_DEAD) {
1620a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
16216b64b624SAurelien Jarno                     }
1622c70fbf0aSRichard Henderson                     if (temp_state[arg] & TS_MEM) {
1623a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
16249c43b68dSAurelien Jarno                     }
1625c70fbf0aSRichard Henderson                     temp_state[arg] = TS_DEAD;
1626c896fe29Sbellard                 }
1627c896fe29Sbellard 
1628c896fe29Sbellard                 /* if end of basic block, update */
1629c896fe29Sbellard                 if (def->flags & TCG_OPF_BB_END) {
1630c70fbf0aSRichard Henderson                     tcg_la_bb_end(s, temp_state);
16313d5c5f87SAurelien Jarno                 } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
16323d5c5f87SAurelien Jarno                     /* globals should be synced to memory */
1633c70fbf0aSRichard Henderson                     for (i = 0; i < nb_globals; i++) {
1634c70fbf0aSRichard Henderson                         temp_state[i] |= TS_MEM;
1635c70fbf0aSRichard Henderson                     }
1636c896fe29Sbellard                 }
1637c896fe29Sbellard 
1638c19f47bfSAurelien Jarno                 /* record arguments that die in this opcode */
1639866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
1640866cb6cbSAurelien Jarno                     arg = args[i];
1641c70fbf0aSRichard Henderson                     if (temp_state[arg] & TS_DEAD) {
1642a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
1643c896fe29Sbellard                     }
1644c19f47bfSAurelien Jarno                 }
164567cc32ebSVeres Lajos                 /* input arguments are live for preceding opcodes */
1646c19f47bfSAurelien Jarno                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
1647c70fbf0aSRichard Henderson                     temp_state[args[i]] &= ~TS_DEAD;
1648c896fe29Sbellard                 }
1649c896fe29Sbellard             }
1650c896fe29Sbellard             break;
1651c896fe29Sbellard         }
1652bee158cbSRichard Henderson         op->life = arg_life;
1653c896fe29Sbellard     }
16541ff0a2c5SEvgeny Voevodin }
1655c896fe29Sbellard 
16565a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
16575a18407fSRichard Henderson static bool liveness_pass_2(TCGContext *s, uint8_t *temp_state)
16585a18407fSRichard Henderson {
16595a18407fSRichard Henderson     int nb_globals = s->nb_globals;
16605a18407fSRichard Henderson     int16_t *dir_temps;
16615a18407fSRichard Henderson     int i, oi, oi_next;
16625a18407fSRichard Henderson     bool changes = false;
16635a18407fSRichard Henderson 
16645a18407fSRichard Henderson     dir_temps = tcg_malloc(nb_globals * sizeof(int16_t));
16655a18407fSRichard Henderson     memset(dir_temps, 0, nb_globals * sizeof(int16_t));
16665a18407fSRichard Henderson 
16675a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
16685a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
16695a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
16705a18407fSRichard Henderson         if (its->indirect_reg) {
16715a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
16725a18407fSRichard Henderson             dts->type = its->type;
16735a18407fSRichard Henderson             dts->base_type = its->base_type;
16745a18407fSRichard Henderson             dir_temps[i] = temp_idx(s, dts);
16755a18407fSRichard Henderson         }
16765a18407fSRichard Henderson     }
16775a18407fSRichard Henderson 
16785a18407fSRichard Henderson     memset(temp_state, TS_DEAD, nb_globals);
16795a18407fSRichard Henderson 
16805a18407fSRichard Henderson     for (oi = s->gen_op_buf[0].next; oi != 0; oi = oi_next) {
16815a18407fSRichard Henderson         TCGOp *op = &s->gen_op_buf[oi];
16825a18407fSRichard Henderson         TCGArg *args = &s->gen_opparam_buf[op->args];
16835a18407fSRichard Henderson         TCGOpcode opc = op->opc;
16845a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
16855a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
16865a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
16875a18407fSRichard Henderson         TCGArg arg, dir;
16885a18407fSRichard Henderson 
16895a18407fSRichard Henderson         oi_next = op->next;
16905a18407fSRichard Henderson 
16915a18407fSRichard Henderson         if (opc == INDEX_op_call) {
16925a18407fSRichard Henderson             nb_oargs = op->callo;
16935a18407fSRichard Henderson             nb_iargs = op->calli;
16945a18407fSRichard Henderson             call_flags = args[nb_oargs + nb_iargs + 1];
16955a18407fSRichard Henderson         } else {
16965a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
16975a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
16985a18407fSRichard Henderson 
16995a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
17005a18407fSRichard Henderson             if (def->flags & TCG_OPF_BB_END) {
17015a18407fSRichard Henderson                 /* Like writing globals: save_globals */
17025a18407fSRichard Henderson                 call_flags = 0;
17035a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
17045a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
17055a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
17065a18407fSRichard Henderson             } else {
17075a18407fSRichard Henderson                 /* No effect on globals.  */
17085a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
17095a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
17105a18407fSRichard Henderson             }
17115a18407fSRichard Henderson         }
17125a18407fSRichard Henderson 
17135a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
17145a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
17155a18407fSRichard Henderson             arg = args[i];
17165a18407fSRichard Henderson             /* Note this unsigned test catches TCG_CALL_ARG_DUMMY too.  */
17175a18407fSRichard Henderson             if (arg < nb_globals) {
17185a18407fSRichard Henderson                 dir = dir_temps[arg];
17195a18407fSRichard Henderson                 if (dir != 0 && temp_state[arg] == TS_DEAD) {
17205a18407fSRichard Henderson                     TCGTemp *its = &s->temps[arg];
17215a18407fSRichard Henderson                     TCGOpcode lopc = (its->type == TCG_TYPE_I32
17225a18407fSRichard Henderson                                       ? INDEX_op_ld_i32
17235a18407fSRichard Henderson                                       : INDEX_op_ld_i64);
17245a18407fSRichard Henderson                     TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3);
17255a18407fSRichard Henderson                     TCGArg *largs = &s->gen_opparam_buf[lop->args];
17265a18407fSRichard Henderson 
17275a18407fSRichard Henderson                     largs[0] = dir;
17285a18407fSRichard Henderson                     largs[1] = temp_idx(s, its->mem_base);
17295a18407fSRichard Henderson                     largs[2] = its->mem_offset;
17305a18407fSRichard Henderson 
17315a18407fSRichard Henderson                     /* Loaded, but synced with memory.  */
17325a18407fSRichard Henderson                     temp_state[arg] = TS_MEM;
17335a18407fSRichard Henderson                 }
17345a18407fSRichard Henderson             }
17355a18407fSRichard Henderson         }
17365a18407fSRichard Henderson 
17375a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
17385a18407fSRichard Henderson            No action is required except keeping temp_state up to date
17395a18407fSRichard Henderson            so that we reload when needed.  */
17405a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
17415a18407fSRichard Henderson             arg = args[i];
17425a18407fSRichard Henderson             if (arg < nb_globals) {
17435a18407fSRichard Henderson                 dir = dir_temps[arg];
17445a18407fSRichard Henderson                 if (dir != 0) {
17455a18407fSRichard Henderson                     args[i] = dir;
17465a18407fSRichard Henderson                     changes = true;
17475a18407fSRichard Henderson                     if (IS_DEAD_ARG(i)) {
17485a18407fSRichard Henderson                         temp_state[arg] = TS_DEAD;
17495a18407fSRichard Henderson                     }
17505a18407fSRichard Henderson                 }
17515a18407fSRichard Henderson             }
17525a18407fSRichard Henderson         }
17535a18407fSRichard Henderson 
17545a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
17555a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
17565a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
17575a18407fSRichard Henderson             /* Nothing to do */
17585a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
17595a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
17605a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
17615a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
17625a18407fSRichard Henderson                 tcg_debug_assert(dir_temps[i] == 0
17635a18407fSRichard Henderson                                  || temp_state[i] != 0);
17645a18407fSRichard Henderson             }
17655a18407fSRichard Henderson         } else {
17665a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
17675a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
17685a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
17695a18407fSRichard Henderson                 tcg_debug_assert(dir_temps[i] == 0
17705a18407fSRichard Henderson                                  || temp_state[i] == TS_DEAD);
17715a18407fSRichard Henderson             }
17725a18407fSRichard Henderson         }
17735a18407fSRichard Henderson 
17745a18407fSRichard Henderson         /* Outputs become available.  */
17755a18407fSRichard Henderson         for (i = 0; i < nb_oargs; i++) {
17765a18407fSRichard Henderson             arg = args[i];
17775a18407fSRichard Henderson             if (arg >= nb_globals) {
17785a18407fSRichard Henderson                 continue;
17795a18407fSRichard Henderson             }
17805a18407fSRichard Henderson             dir = dir_temps[arg];
17815a18407fSRichard Henderson             if (dir == 0) {
17825a18407fSRichard Henderson                 continue;
17835a18407fSRichard Henderson             }
17845a18407fSRichard Henderson             args[i] = dir;
17855a18407fSRichard Henderson             changes = true;
17865a18407fSRichard Henderson 
17875a18407fSRichard Henderson             /* The output is now live and modified.  */
17885a18407fSRichard Henderson             temp_state[arg] = 0;
17895a18407fSRichard Henderson 
17905a18407fSRichard Henderson             /* Sync outputs upon their last write.  */
17915a18407fSRichard Henderson             if (NEED_SYNC_ARG(i)) {
17925a18407fSRichard Henderson                 TCGTemp *its = &s->temps[arg];
17935a18407fSRichard Henderson                 TCGOpcode sopc = (its->type == TCG_TYPE_I32
17945a18407fSRichard Henderson                                   ? INDEX_op_st_i32
17955a18407fSRichard Henderson                                   : INDEX_op_st_i64);
17965a18407fSRichard Henderson                 TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
17975a18407fSRichard Henderson                 TCGArg *sargs = &s->gen_opparam_buf[sop->args];
17985a18407fSRichard Henderson 
17995a18407fSRichard Henderson                 sargs[0] = dir;
18005a18407fSRichard Henderson                 sargs[1] = temp_idx(s, its->mem_base);
18015a18407fSRichard Henderson                 sargs[2] = its->mem_offset;
18025a18407fSRichard Henderson 
18035a18407fSRichard Henderson                 temp_state[arg] = TS_MEM;
18045a18407fSRichard Henderson             }
18055a18407fSRichard Henderson             /* Drop outputs that are dead.  */
18065a18407fSRichard Henderson             if (IS_DEAD_ARG(i)) {
18075a18407fSRichard Henderson                 temp_state[arg] = TS_DEAD;
18085a18407fSRichard Henderson             }
18095a18407fSRichard Henderson         }
18105a18407fSRichard Henderson     }
18115a18407fSRichard Henderson 
18125a18407fSRichard Henderson     return changes;
18135a18407fSRichard Henderson }
18145a18407fSRichard Henderson 
18158d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
1816c896fe29Sbellard static void dump_regs(TCGContext *s)
1817c896fe29Sbellard {
1818c896fe29Sbellard     TCGTemp *ts;
1819c896fe29Sbellard     int i;
1820c896fe29Sbellard     char buf[64];
1821c896fe29Sbellard 
1822c896fe29Sbellard     for(i = 0; i < s->nb_temps; i++) {
1823c896fe29Sbellard         ts = &s->temps[i];
1824ac56dd48Spbrook         printf("  %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i));
1825c896fe29Sbellard         switch(ts->val_type) {
1826c896fe29Sbellard         case TEMP_VAL_REG:
1827c896fe29Sbellard             printf("%s", tcg_target_reg_names[ts->reg]);
1828c896fe29Sbellard             break;
1829c896fe29Sbellard         case TEMP_VAL_MEM:
1830b3a62939SRichard Henderson             printf("%d(%s)", (int)ts->mem_offset,
1831b3a62939SRichard Henderson                    tcg_target_reg_names[ts->mem_base->reg]);
1832c896fe29Sbellard             break;
1833c896fe29Sbellard         case TEMP_VAL_CONST:
1834c896fe29Sbellard             printf("$0x%" TCG_PRIlx, ts->val);
1835c896fe29Sbellard             break;
1836c896fe29Sbellard         case TEMP_VAL_DEAD:
1837c896fe29Sbellard             printf("D");
1838c896fe29Sbellard             break;
1839c896fe29Sbellard         default:
1840c896fe29Sbellard             printf("???");
1841c896fe29Sbellard             break;
1842c896fe29Sbellard         }
1843c896fe29Sbellard         printf("\n");
1844c896fe29Sbellard     }
1845c896fe29Sbellard 
1846c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
1847f8b2f202SRichard Henderson         if (s->reg_to_temp[i] != NULL) {
1848c896fe29Sbellard             printf("%s: %s\n",
1849c896fe29Sbellard                    tcg_target_reg_names[i],
1850f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i]));
1851c896fe29Sbellard         }
1852c896fe29Sbellard     }
1853c896fe29Sbellard }
1854c896fe29Sbellard 
1855c896fe29Sbellard static void check_regs(TCGContext *s)
1856c896fe29Sbellard {
1857869938aeSRichard Henderson     int reg;
1858b6638662SRichard Henderson     int k;
1859c896fe29Sbellard     TCGTemp *ts;
1860c896fe29Sbellard     char buf[64];
1861c896fe29Sbellard 
1862c896fe29Sbellard     for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1863f8b2f202SRichard Henderson         ts = s->reg_to_temp[reg];
1864f8b2f202SRichard Henderson         if (ts != NULL) {
1865f8b2f202SRichard Henderson             if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) {
1866c896fe29Sbellard                 printf("Inconsistency for register %s:\n",
1867c896fe29Sbellard                        tcg_target_reg_names[reg]);
1868b03cce8eSbellard                 goto fail;
1869c896fe29Sbellard             }
1870c896fe29Sbellard         }
1871c896fe29Sbellard     }
1872c896fe29Sbellard     for (k = 0; k < s->nb_temps; k++) {
1873c896fe29Sbellard         ts = &s->temps[k];
1874f8b2f202SRichard Henderson         if (ts->val_type == TEMP_VAL_REG && !ts->fixed_reg
1875f8b2f202SRichard Henderson             && s->reg_to_temp[ts->reg] != ts) {
1876c896fe29Sbellard             printf("Inconsistency for temp %s:\n",
1877f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
1878b03cce8eSbellard         fail:
1879c896fe29Sbellard             printf("reg state:\n");
1880c896fe29Sbellard             dump_regs(s);
1881c896fe29Sbellard             tcg_abort();
1882c896fe29Sbellard         }
1883c896fe29Sbellard     }
1884c896fe29Sbellard }
1885c896fe29Sbellard #endif
1886c896fe29Sbellard 
1887c896fe29Sbellard static void temp_allocate_frame(TCGContext *s, int temp)
1888c896fe29Sbellard {
1889c896fe29Sbellard     TCGTemp *ts;
1890c896fe29Sbellard     ts = &s->temps[temp];
18919b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64)
18929b9c37c3SRichard Henderson     /* Sparc64 stack is accessed with offset of 2047 */
1893b591dc59SBlue Swirl     s->current_frame_offset = (s->current_frame_offset +
1894b591dc59SBlue Swirl                                (tcg_target_long)sizeof(tcg_target_long) - 1) &
1895b591dc59SBlue Swirl         ~(sizeof(tcg_target_long) - 1);
1896f44c9960SBlue Swirl #endif
1897b591dc59SBlue Swirl     if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
1898b591dc59SBlue Swirl         s->frame_end) {
18995ff9d6a4Sbellard         tcg_abort();
1900b591dc59SBlue Swirl     }
1901c896fe29Sbellard     ts->mem_offset = s->current_frame_offset;
1902b3a62939SRichard Henderson     ts->mem_base = s->frame_temp;
1903c896fe29Sbellard     ts->mem_allocated = 1;
1904e2c6d1b4SRichard Henderson     s->current_frame_offset += sizeof(tcg_target_long);
1905c896fe29Sbellard }
1906c896fe29Sbellard 
1907b3915dbbSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet);
1908b3915dbbSRichard Henderson 
190959d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
191059d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
191159d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
1912c896fe29Sbellard {
191359d7c14eSRichard Henderson     if (ts->fixed_reg) {
191459d7c14eSRichard Henderson         return;
191559d7c14eSRichard Henderson     }
191659d7c14eSRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
191759d7c14eSRichard Henderson         s->reg_to_temp[ts->reg] = NULL;
191859d7c14eSRichard Henderson     }
191959d7c14eSRichard Henderson     ts->val_type = (free_or_dead < 0
192059d7c14eSRichard Henderson                     || ts->temp_local
192159d7c14eSRichard Henderson                     || temp_idx(s, ts) < s->nb_globals
192259d7c14eSRichard Henderson                     ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
192359d7c14eSRichard Henderson }
1924c896fe29Sbellard 
192559d7c14eSRichard Henderson /* Mark a temporary as dead.  */
192659d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
192759d7c14eSRichard Henderson {
192859d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
192959d7c14eSRichard Henderson }
193059d7c14eSRichard Henderson 
193159d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
193259d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
193359d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
193459d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
193559d7c14eSRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts,
193659d7c14eSRichard Henderson                       TCGRegSet allocated_regs, int free_or_dead)
193759d7c14eSRichard Henderson {
193859d7c14eSRichard Henderson     if (ts->fixed_reg) {
193959d7c14eSRichard Henderson         return;
194059d7c14eSRichard Henderson     }
194159d7c14eSRichard Henderson     if (!ts->mem_coherent) {
19427f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
1943f8b2f202SRichard Henderson             temp_allocate_frame(s, temp_idx(s, ts));
194459d7c14eSRichard Henderson         }
194559d7c14eSRichard Henderson         switch (ts->val_type) {
194659d7c14eSRichard Henderson         case TEMP_VAL_CONST:
194759d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
194859d7c14eSRichard Henderson                require it later in a register, so attempt to store the
194959d7c14eSRichard Henderson                constant to memory directly.  */
195059d7c14eSRichard Henderson             if (free_or_dead
195159d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
195259d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
195359d7c14eSRichard Henderson                 break;
195459d7c14eSRichard Henderson             }
195559d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
195659d7c14eSRichard Henderson                       allocated_regs);
195759d7c14eSRichard Henderson             /* fallthrough */
195859d7c14eSRichard Henderson 
195959d7c14eSRichard Henderson         case TEMP_VAL_REG:
196059d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
196159d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
196259d7c14eSRichard Henderson             break;
196359d7c14eSRichard Henderson 
196459d7c14eSRichard Henderson         case TEMP_VAL_MEM:
196559d7c14eSRichard Henderson             break;
196659d7c14eSRichard Henderson 
196759d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
196859d7c14eSRichard Henderson         default:
196959d7c14eSRichard Henderson             tcg_abort();
1970c896fe29Sbellard         }
19717f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
19727f6ceedfSAurelien Jarno     }
197359d7c14eSRichard Henderson     if (free_or_dead) {
197459d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
197559d7c14eSRichard Henderson     }
197659d7c14eSRichard Henderson }
19777f6ceedfSAurelien Jarno 
19787f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
1979b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
19807f6ceedfSAurelien Jarno {
1981f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
1982f8b2f202SRichard Henderson     if (ts != NULL) {
198359d7c14eSRichard Henderson         temp_sync(s, ts, allocated_regs, -1);
1984c896fe29Sbellard     }
1985c896fe29Sbellard }
1986c896fe29Sbellard 
1987c896fe29Sbellard /* Allocate a register belonging to reg1 & ~reg2 */
1988b3915dbbSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet desired_regs,
198991478cefSRichard Henderson                             TCGRegSet allocated_regs, bool rev)
1990c896fe29Sbellard {
199191478cefSRichard Henderson     int i, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
199291478cefSRichard Henderson     const int *order;
1993b6638662SRichard Henderson     TCGReg reg;
1994c896fe29Sbellard     TCGRegSet reg_ct;
1995c896fe29Sbellard 
1996b3915dbbSRichard Henderson     tcg_regset_andnot(reg_ct, desired_regs, allocated_regs);
199791478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
1998c896fe29Sbellard 
1999c896fe29Sbellard     /* first try free registers */
200091478cefSRichard Henderson     for(i = 0; i < n; i++) {
200191478cefSRichard Henderson         reg = order[i];
2002f8b2f202SRichard Henderson         if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == NULL)
2003c896fe29Sbellard             return reg;
2004c896fe29Sbellard     }
2005c896fe29Sbellard 
2006c896fe29Sbellard     /* XXX: do better spill choice */
200791478cefSRichard Henderson     for(i = 0; i < n; i++) {
200891478cefSRichard Henderson         reg = order[i];
2009c896fe29Sbellard         if (tcg_regset_test_reg(reg_ct, reg)) {
2010b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
2011c896fe29Sbellard             return reg;
2012c896fe29Sbellard         }
2013c896fe29Sbellard     }
2014c896fe29Sbellard 
2015c896fe29Sbellard     tcg_abort();
2016c896fe29Sbellard }
2017c896fe29Sbellard 
201840ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
201940ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
202040ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
202140ae5c62SRichard Henderson                       TCGRegSet allocated_regs)
202240ae5c62SRichard Henderson {
202340ae5c62SRichard Henderson     TCGReg reg;
202440ae5c62SRichard Henderson 
202540ae5c62SRichard Henderson     switch (ts->val_type) {
202640ae5c62SRichard Henderson     case TEMP_VAL_REG:
202740ae5c62SRichard Henderson         return;
202840ae5c62SRichard Henderson     case TEMP_VAL_CONST:
202991478cefSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs, ts->indirect_base);
203040ae5c62SRichard Henderson         tcg_out_movi(s, ts->type, reg, ts->val);
203140ae5c62SRichard Henderson         ts->mem_coherent = 0;
203240ae5c62SRichard Henderson         break;
203340ae5c62SRichard Henderson     case TEMP_VAL_MEM:
203491478cefSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs, ts->indirect_base);
203540ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
203640ae5c62SRichard Henderson         ts->mem_coherent = 1;
203740ae5c62SRichard Henderson         break;
203840ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
203940ae5c62SRichard Henderson     default:
204040ae5c62SRichard Henderson         tcg_abort();
204140ae5c62SRichard Henderson     }
204240ae5c62SRichard Henderson     ts->reg = reg;
204340ae5c62SRichard Henderson     ts->val_type = TEMP_VAL_REG;
204440ae5c62SRichard Henderson     s->reg_to_temp[reg] = ts;
204540ae5c62SRichard Henderson }
204640ae5c62SRichard Henderson 
204759d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
2048e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
204959d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
20501ad80729SAurelien Jarno {
20512c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
2052eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
2053f8bf00f1SRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg);
20541ad80729SAurelien Jarno }
20551ad80729SAurelien Jarno 
20569814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
2057641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
2058641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
2059641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
2060641d5fbeSbellard {
2061641d5fbeSbellard     int i;
2062641d5fbeSbellard 
2063641d5fbeSbellard     for (i = 0; i < s->nb_globals; i++) {
2064b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
2065641d5fbeSbellard     }
2066e5097dc8Sbellard }
2067e5097dc8Sbellard 
20683d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
20693d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
20703d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
20713d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
20723d5c5f87SAurelien Jarno {
20733d5c5f87SAurelien Jarno     int i;
20743d5c5f87SAurelien Jarno 
20753d5c5f87SAurelien Jarno     for (i = 0; i < s->nb_globals; i++) {
207612b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
207712b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
207812b9b11aSRichard Henderson                          || ts->fixed_reg
207912b9b11aSRichard Henderson                          || ts->mem_coherent);
20803d5c5f87SAurelien Jarno     }
20813d5c5f87SAurelien Jarno }
20823d5c5f87SAurelien Jarno 
2083e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
2084e8996ee0Sbellard    all globals are stored at their canonical location. */
2085e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
2086e5097dc8Sbellard {
2087e5097dc8Sbellard     int i;
2088e5097dc8Sbellard 
2089c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
2090b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
2091641d5fbeSbellard         if (ts->temp_local) {
2092b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
2093641d5fbeSbellard         } else {
20942c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
2095eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
2096eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
2097c896fe29Sbellard         }
2098641d5fbeSbellard     }
2099e8996ee0Sbellard 
2100e8996ee0Sbellard     save_globals(s, allocated_regs);
2101c896fe29Sbellard }
2102c896fe29Sbellard 
21030fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
21040fe4fca4SPaolo Bonzini                                   tcg_target_ulong val, TCGLifeData arg_life)
2105e8996ee0Sbellard {
2106e8996ee0Sbellard     if (ots->fixed_reg) {
210759d7c14eSRichard Henderson         /* For fixed registers, we do not do any constant propagation.  */
2108e8996ee0Sbellard         tcg_out_movi(s, ots->type, ots->reg, val);
210959d7c14eSRichard Henderson         return;
211059d7c14eSRichard Henderson     }
211159d7c14eSRichard Henderson 
211259d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
2113f8b2f202SRichard Henderson     if (ots->val_type == TEMP_VAL_REG) {
2114f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = NULL;
2115f8b2f202SRichard Henderson     }
2116e8996ee0Sbellard     ots->val_type = TEMP_VAL_CONST;
2117e8996ee0Sbellard     ots->val = val;
211859d7c14eSRichard Henderson     ots->mem_coherent = 0;
2119ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
212059d7c14eSRichard Henderson         temp_sync(s, ots, s->reserved_regs, IS_DEAD_ARG(0));
212159d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
2122f8bf00f1SRichard Henderson         temp_dead(s, ots);
21234c4e1ab2SAurelien Jarno     }
2124e8996ee0Sbellard }
2125e8996ee0Sbellard 
21260fe4fca4SPaolo Bonzini static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args,
21270fe4fca4SPaolo Bonzini                                TCGLifeData arg_life)
21280fe4fca4SPaolo Bonzini {
21290fe4fca4SPaolo Bonzini     TCGTemp *ots = &s->temps[args[0]];
21300fe4fca4SPaolo Bonzini     tcg_target_ulong val = args[1];
21310fe4fca4SPaolo Bonzini 
21320fe4fca4SPaolo Bonzini     tcg_reg_alloc_do_movi(s, ots, val, arg_life);
21330fe4fca4SPaolo Bonzini }
21340fe4fca4SPaolo Bonzini 
2135c896fe29Sbellard static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
2136a1b3c48dSRichard Henderson                               const TCGArg *args, TCGLifeData arg_life)
2137c896fe29Sbellard {
2138c29c1d7eSAurelien Jarno     TCGRegSet allocated_regs;
2139c896fe29Sbellard     TCGTemp *ts, *ots;
2140450445d5SRichard Henderson     TCGType otype, itype;
2141c896fe29Sbellard 
2142c29c1d7eSAurelien Jarno     tcg_regset_set(allocated_regs, s->reserved_regs);
2143c896fe29Sbellard     ots = &s->temps[args[0]];
2144c896fe29Sbellard     ts = &s->temps[args[1]];
2145450445d5SRichard Henderson 
2146450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
2147450445d5SRichard Henderson     otype = ots->type;
2148450445d5SRichard Henderson     itype = ts->type;
2149c896fe29Sbellard 
21500fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
21510fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
21520fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
21530fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
21540fe4fca4SPaolo Bonzini             temp_dead(s, ts);
21550fe4fca4SPaolo Bonzini         }
21560fe4fca4SPaolo Bonzini         tcg_reg_alloc_do_movi(s, ots, val, arg_life);
21570fe4fca4SPaolo Bonzini         return;
21580fe4fca4SPaolo Bonzini     }
21590fe4fca4SPaolo Bonzini 
21600fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
21610fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
21620fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
21630fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
21640fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
216540ae5c62SRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype], allocated_regs);
2166c29c1d7eSAurelien Jarno     }
2167c29c1d7eSAurelien Jarno 
21680fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
2169c29c1d7eSAurelien Jarno     if (IS_DEAD_ARG(0) && !ots->fixed_reg) {
2170c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
2171c29c1d7eSAurelien Jarno            liveness analysis disabled). */
2172eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
2173c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
2174c29c1d7eSAurelien Jarno             temp_allocate_frame(s, args[0]);
2175c29c1d7eSAurelien Jarno         }
2176b3a62939SRichard Henderson         tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset);
2177c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
2178f8bf00f1SRichard Henderson             temp_dead(s, ts);
2179c29c1d7eSAurelien Jarno         }
2180f8bf00f1SRichard Henderson         temp_dead(s, ots);
2181e8996ee0Sbellard     } else {
2182c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1) && !ts->fixed_reg && !ots->fixed_reg) {
2183c29c1d7eSAurelien Jarno             /* the mov can be suppressed */
2184c29c1d7eSAurelien Jarno             if (ots->val_type == TEMP_VAL_REG) {
2185f8b2f202SRichard Henderson                 s->reg_to_temp[ots->reg] = NULL;
2186c896fe29Sbellard             }
2187c29c1d7eSAurelien Jarno             ots->reg = ts->reg;
2188f8bf00f1SRichard Henderson             temp_dead(s, ts);
2189c29c1d7eSAurelien Jarno         } else {
2190c29c1d7eSAurelien Jarno             if (ots->val_type != TEMP_VAL_REG) {
2191c29c1d7eSAurelien Jarno                 /* When allocating a new register, make sure to not spill the
2192c29c1d7eSAurelien Jarno                    input one. */
2193c29c1d7eSAurelien Jarno                 tcg_regset_set_reg(allocated_regs, ts->reg);
2194450445d5SRichard Henderson                 ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
219591478cefSRichard Henderson                                          allocated_regs, ots->indirect_base);
2196c29c1d7eSAurelien Jarno             }
2197450445d5SRichard Henderson             tcg_out_mov(s, otype, ots->reg, ts->reg);
2198c29c1d7eSAurelien Jarno         }
2199c896fe29Sbellard         ots->val_type = TEMP_VAL_REG;
2200c896fe29Sbellard         ots->mem_coherent = 0;
2201f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
2202ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(0)) {
220359d7c14eSRichard Henderson             temp_sync(s, ots, allocated_regs, 0);
2204c29c1d7eSAurelien Jarno         }
2205ec7a869dSAurelien Jarno     }
2206c896fe29Sbellard }
2207c896fe29Sbellard 
2208c896fe29Sbellard static void tcg_reg_alloc_op(TCGContext *s,
2209a9751609SRichard Henderson                              const TCGOpDef *def, TCGOpcode opc,
2210a1b3c48dSRichard Henderson                              const TCGArg *args, TCGLifeData arg_life)
2211c896fe29Sbellard {
221282790a87SRichard Henderson     TCGRegSet i_allocated_regs;
221382790a87SRichard Henderson     TCGRegSet o_allocated_regs;
2214b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
2215b6638662SRichard Henderson     TCGReg reg;
2216c896fe29Sbellard     TCGArg arg;
2217c896fe29Sbellard     const TCGArgConstraint *arg_ct;
2218c896fe29Sbellard     TCGTemp *ts;
2219c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
2220c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
2221c896fe29Sbellard 
2222c896fe29Sbellard     nb_oargs = def->nb_oargs;
2223c896fe29Sbellard     nb_iargs = def->nb_iargs;
2224c896fe29Sbellard 
2225c896fe29Sbellard     /* copy constants */
2226c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
2227c896fe29Sbellard            args + nb_oargs + nb_iargs,
2228c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
2229c896fe29Sbellard 
223082790a87SRichard Henderson     tcg_regset_set(i_allocated_regs, s->reserved_regs);
223182790a87SRichard Henderson     tcg_regset_set(o_allocated_regs, s->reserved_regs);
223282790a87SRichard Henderson 
2233c896fe29Sbellard     /* satisfy input constraints */
2234c896fe29Sbellard     for(k = 0; k < nb_iargs; k++) {
2235c896fe29Sbellard         i = def->sorted_args[nb_oargs + k];
2236c896fe29Sbellard         arg = args[i];
2237c896fe29Sbellard         arg_ct = &def->args_ct[i];
2238c896fe29Sbellard         ts = &s->temps[arg];
223940ae5c62SRichard Henderson 
224040ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
224140ae5c62SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct)) {
2242c896fe29Sbellard             /* constant is OK for instruction */
2243c896fe29Sbellard             const_args[i] = 1;
2244c896fe29Sbellard             new_args[i] = ts->val;
2245c896fe29Sbellard             goto iarg_end;
2246c896fe29Sbellard         }
224740ae5c62SRichard Henderson 
224882790a87SRichard Henderson         temp_load(s, ts, arg_ct->u.regs, i_allocated_regs);
224940ae5c62SRichard Henderson 
22505ff9d6a4Sbellard         if (arg_ct->ct & TCG_CT_IALIAS) {
22515ff9d6a4Sbellard             if (ts->fixed_reg) {
22525ff9d6a4Sbellard                 /* if fixed register, we must allocate a new register
22535ff9d6a4Sbellard                    if the alias is not the same register */
22545ff9d6a4Sbellard                 if (arg != args[arg_ct->alias_index])
22555ff9d6a4Sbellard                     goto allocate_in_reg;
22565ff9d6a4Sbellard             } else {
2257c896fe29Sbellard                 /* if the input is aliased to an output and if it is
2258c896fe29Sbellard                    not dead after the instruction, we must allocate
2259c896fe29Sbellard                    a new register and move it */
2260866cb6cbSAurelien Jarno                 if (!IS_DEAD_ARG(i)) {
2261c896fe29Sbellard                     goto allocate_in_reg;
2262c896fe29Sbellard                 }
22637e1df267SAurelien Jarno                 /* check if the current register has already been allocated
22647e1df267SAurelien Jarno                    for another input aliased to an output */
22657e1df267SAurelien Jarno                 int k2, i2;
22667e1df267SAurelien Jarno                 for (k2 = 0 ; k2 < k ; k2++) {
22677e1df267SAurelien Jarno                     i2 = def->sorted_args[nb_oargs + k2];
22687e1df267SAurelien Jarno                     if ((def->args_ct[i2].ct & TCG_CT_IALIAS) &&
22697e1df267SAurelien Jarno                         (new_args[i2] == ts->reg)) {
22707e1df267SAurelien Jarno                         goto allocate_in_reg;
22717e1df267SAurelien Jarno                     }
22727e1df267SAurelien Jarno                 }
22735ff9d6a4Sbellard             }
2274866cb6cbSAurelien Jarno         }
2275c896fe29Sbellard         reg = ts->reg;
2276c896fe29Sbellard         if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
2277c896fe29Sbellard             /* nothing to do : the constraint is satisfied */
2278c896fe29Sbellard         } else {
2279c896fe29Sbellard         allocate_in_reg:
2280c896fe29Sbellard             /* allocate a new register matching the constraint
2281c896fe29Sbellard                and move the temporary register into it */
228282790a87SRichard Henderson             reg = tcg_reg_alloc(s, arg_ct->u.regs, i_allocated_regs,
228391478cefSRichard Henderson                                 ts->indirect_base);
22843b6dac34SRichard Henderson             tcg_out_mov(s, ts->type, reg, ts->reg);
2285c896fe29Sbellard         }
2286c896fe29Sbellard         new_args[i] = reg;
2287c896fe29Sbellard         const_args[i] = 0;
228882790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
2289c896fe29Sbellard     iarg_end: ;
2290c896fe29Sbellard     }
2291c896fe29Sbellard 
2292c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
2293866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
2294866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
2295f8bf00f1SRichard Henderson             temp_dead(s, &s->temps[args[i]]);
2296c896fe29Sbellard         }
2297c896fe29Sbellard     }
2298c896fe29Sbellard 
2299a52ad07eSAurelien Jarno     if (def->flags & TCG_OPF_BB_END) {
230082790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
2301a52ad07eSAurelien Jarno     } else {
2302c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
2303b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
2304c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
2305c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
230682790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
2307c896fe29Sbellard                 }
2308c896fe29Sbellard             }
23093d5c5f87SAurelien Jarno         }
23103d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
23113d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
23123d5c5f87SAurelien Jarno                an exception. */
231382790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
2314c896fe29Sbellard         }
2315c896fe29Sbellard 
2316c896fe29Sbellard         /* satisfy the output constraints */
2317c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
2318c896fe29Sbellard             i = def->sorted_args[k];
2319c896fe29Sbellard             arg = args[i];
2320c896fe29Sbellard             arg_ct = &def->args_ct[i];
2321c896fe29Sbellard             ts = &s->temps[arg];
232217280ff4SRichard Henderson             if ((arg_ct->ct & TCG_CT_ALIAS)
232317280ff4SRichard Henderson                 && !const_args[arg_ct->alias_index]) {
23245ff9d6a4Sbellard                 reg = new_args[arg_ct->alias_index];
232582790a87SRichard Henderson             } else if (arg_ct->ct & TCG_CT_NEWREG) {
232682790a87SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->u.regs,
232782790a87SRichard Henderson                                     i_allocated_regs | o_allocated_regs,
232882790a87SRichard Henderson                                     ts->indirect_base);
2329c896fe29Sbellard             } else {
2330c896fe29Sbellard                 /* if fixed register, we try to use it */
2331c896fe29Sbellard                 reg = ts->reg;
2332c896fe29Sbellard                 if (ts->fixed_reg &&
2333c896fe29Sbellard                     tcg_regset_test_reg(arg_ct->u.regs, reg)) {
2334c896fe29Sbellard                     goto oarg_end;
2335c896fe29Sbellard                 }
233682790a87SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->u.regs, o_allocated_regs,
233791478cefSRichard Henderson                                     ts->indirect_base);
2338c896fe29Sbellard             }
233982790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
2340c896fe29Sbellard             /* if a fixed register is used, then a move will be done afterwards */
2341c896fe29Sbellard             if (!ts->fixed_reg) {
2342639368ddSAurelien Jarno                 if (ts->val_type == TEMP_VAL_REG) {
2343f8b2f202SRichard Henderson                     s->reg_to_temp[ts->reg] = NULL;
2344639368ddSAurelien Jarno                 }
2345c896fe29Sbellard                 ts->val_type = TEMP_VAL_REG;
2346c896fe29Sbellard                 ts->reg = reg;
2347c896fe29Sbellard                 /* temp value is modified, so the value kept in memory is
2348c896fe29Sbellard                    potentially not the same */
2349c896fe29Sbellard                 ts->mem_coherent = 0;
2350f8b2f202SRichard Henderson                 s->reg_to_temp[reg] = ts;
2351c896fe29Sbellard             }
2352c896fe29Sbellard         oarg_end:
2353c896fe29Sbellard             new_args[i] = reg;
2354c896fe29Sbellard         }
2355e8996ee0Sbellard     }
2356c896fe29Sbellard 
2357c896fe29Sbellard     /* emit instruction */
2358c896fe29Sbellard     tcg_out_op(s, opc, new_args, const_args);
2359c896fe29Sbellard 
2360c896fe29Sbellard     /* move the outputs in the correct register if needed */
2361c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
2362c896fe29Sbellard         ts = &s->temps[args[i]];
2363c896fe29Sbellard         reg = new_args[i];
2364c896fe29Sbellard         if (ts->fixed_reg && ts->reg != reg) {
23653b6dac34SRichard Henderson             tcg_out_mov(s, ts->type, ts->reg, reg);
2366c896fe29Sbellard         }
2367ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
236882790a87SRichard Henderson             temp_sync(s, ts, o_allocated_regs, IS_DEAD_ARG(i));
236959d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
2370f8bf00f1SRichard Henderson             temp_dead(s, ts);
2371ec7a869dSAurelien Jarno         }
2372c896fe29Sbellard     }
2373c896fe29Sbellard }
2374c896fe29Sbellard 
2375b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP
2376b03cce8eSbellard #define STACK_DIR(x) (-(x))
2377b03cce8eSbellard #else
2378b03cce8eSbellard #define STACK_DIR(x) (x)
2379b03cce8eSbellard #endif
2380b03cce8eSbellard 
2381c45cb8bbSRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, int nb_oargs, int nb_iargs,
2382a1b3c48dSRichard Henderson                                const TCGArg * const args, TCGLifeData arg_life)
2383c896fe29Sbellard {
2384b6638662SRichard Henderson     int flags, nb_regs, i;
2385b6638662SRichard Henderson     TCGReg reg;
2386cf066674SRichard Henderson     TCGArg arg;
2387c896fe29Sbellard     TCGTemp *ts;
2388d3452f1fSRichard Henderson     intptr_t stack_offset;
2389d3452f1fSRichard Henderson     size_t call_stack_size;
2390cf066674SRichard Henderson     tcg_insn_unit *func_addr;
2391cf066674SRichard Henderson     int allocate_args;
2392c896fe29Sbellard     TCGRegSet allocated_regs;
2393c896fe29Sbellard 
2394cf066674SRichard Henderson     func_addr = (tcg_insn_unit *)(intptr_t)args[nb_oargs + nb_iargs];
2395cf066674SRichard Henderson     flags = args[nb_oargs + nb_iargs + 1];
2396c896fe29Sbellard 
23976e17d0c5SStefan Weil     nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
2398c45cb8bbSRichard Henderson     if (nb_regs > nb_iargs) {
2399c45cb8bbSRichard Henderson         nb_regs = nb_iargs;
2400cf066674SRichard Henderson     }
2401c896fe29Sbellard 
2402c896fe29Sbellard     /* assign stack slots first */
2403c45cb8bbSRichard Henderson     call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long);
2404c896fe29Sbellard     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
2405c896fe29Sbellard         ~(TCG_TARGET_STACK_ALIGN - 1);
2406b03cce8eSbellard     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
2407b03cce8eSbellard     if (allocate_args) {
2408345649c0SBlue Swirl         /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
2409345649c0SBlue Swirl            preallocate call stack */
2410345649c0SBlue Swirl         tcg_abort();
2411b03cce8eSbellard     }
241239cf05d3Sbellard 
241339cf05d3Sbellard     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
2414c45cb8bbSRichard Henderson     for(i = nb_regs; i < nb_iargs; i++) {
2415c896fe29Sbellard         arg = args[nb_oargs + i];
241639cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP
241739cf05d3Sbellard         stack_offset -= sizeof(tcg_target_long);
241839cf05d3Sbellard #endif
241939cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
2420c896fe29Sbellard             ts = &s->temps[arg];
242140ae5c62SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
242240ae5c62SRichard Henderson                       s->reserved_regs);
2423e4d5434cSblueswir1             tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
242439cf05d3Sbellard         }
242539cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP
242639cf05d3Sbellard         stack_offset += sizeof(tcg_target_long);
242739cf05d3Sbellard #endif
2428c896fe29Sbellard     }
2429c896fe29Sbellard 
2430c896fe29Sbellard     /* assign input registers */
2431c896fe29Sbellard     tcg_regset_set(allocated_regs, s->reserved_regs);
2432c896fe29Sbellard     for(i = 0; i < nb_regs; i++) {
2433c896fe29Sbellard         arg = args[nb_oargs + i];
243439cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
2435c896fe29Sbellard             ts = &s->temps[arg];
2436c896fe29Sbellard             reg = tcg_target_call_iarg_regs[i];
2437b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
243840ae5c62SRichard Henderson 
2439c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
2440c896fe29Sbellard                 if (ts->reg != reg) {
24413b6dac34SRichard Henderson                     tcg_out_mov(s, ts->type, reg, ts->reg);
2442c896fe29Sbellard                 }
2443c896fe29Sbellard             } else {
244440ae5c62SRichard Henderson                 TCGRegSet arg_set;
244540ae5c62SRichard Henderson 
244640ae5c62SRichard Henderson                 tcg_regset_clear(arg_set);
244740ae5c62SRichard Henderson                 tcg_regset_set_reg(arg_set, reg);
244840ae5c62SRichard Henderson                 temp_load(s, ts, arg_set, allocated_regs);
2449c896fe29Sbellard             }
245040ae5c62SRichard Henderson 
2451c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
2452c896fe29Sbellard         }
245339cf05d3Sbellard     }
2454c896fe29Sbellard 
2455c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
2456866cb6cbSAurelien Jarno     for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2457866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
2458f8bf00f1SRichard Henderson             temp_dead(s, &s->temps[args[i]]);
2459c896fe29Sbellard         }
2460c896fe29Sbellard     }
2461c896fe29Sbellard 
2462c896fe29Sbellard     /* clobber call registers */
2463c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
2464c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
2465b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
2466c896fe29Sbellard         }
2467c896fe29Sbellard     }
2468c896fe29Sbellard 
246978505279SAurelien Jarno     /* Save globals if they might be written by the helper, sync them if
247078505279SAurelien Jarno        they might be read. */
247178505279SAurelien Jarno     if (flags & TCG_CALL_NO_READ_GLOBALS) {
247278505279SAurelien Jarno         /* Nothing to do */
247378505279SAurelien Jarno     } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) {
247478505279SAurelien Jarno         sync_globals(s, allocated_regs);
247578505279SAurelien Jarno     } else {
2476e8996ee0Sbellard         save_globals(s, allocated_regs);
2477b9c18f56Saurel32     }
2478c896fe29Sbellard 
2479cf066674SRichard Henderson     tcg_out_call(s, func_addr);
2480c896fe29Sbellard 
2481c896fe29Sbellard     /* assign output registers and emit moves if needed */
2482c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
2483c896fe29Sbellard         arg = args[i];
2484c896fe29Sbellard         ts = &s->temps[arg];
2485c896fe29Sbellard         reg = tcg_target_call_oarg_regs[i];
2486eabb7b91SAurelien Jarno         tcg_debug_assert(s->reg_to_temp[reg] == NULL);
248734b1a49cSRichard Henderson 
2488c896fe29Sbellard         if (ts->fixed_reg) {
2489c896fe29Sbellard             if (ts->reg != reg) {
24903b6dac34SRichard Henderson                 tcg_out_mov(s, ts->type, ts->reg, reg);
2491c896fe29Sbellard             }
2492c896fe29Sbellard         } else {
2493639368ddSAurelien Jarno             if (ts->val_type == TEMP_VAL_REG) {
2494f8b2f202SRichard Henderson                 s->reg_to_temp[ts->reg] = NULL;
2495639368ddSAurelien Jarno             }
2496c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
2497c896fe29Sbellard             ts->reg = reg;
2498c896fe29Sbellard             ts->mem_coherent = 0;
2499f8b2f202SRichard Henderson             s->reg_to_temp[reg] = ts;
2500ec7a869dSAurelien Jarno             if (NEED_SYNC_ARG(i)) {
250159d7c14eSRichard Henderson                 temp_sync(s, ts, allocated_regs, IS_DEAD_ARG(i));
250259d7c14eSRichard Henderson             } else if (IS_DEAD_ARG(i)) {
2503f8bf00f1SRichard Henderson                 temp_dead(s, ts);
2504c896fe29Sbellard             }
2505c896fe29Sbellard         }
25068c11ad25SAurelien Jarno     }
2507c896fe29Sbellard }
2508c896fe29Sbellard 
2509c896fe29Sbellard #ifdef CONFIG_PROFILER
2510c896fe29Sbellard 
251154604f74Saurel32 static int64_t tcg_table_op_count[NB_OPS];
2512c896fe29Sbellard 
2513246ae24dSMax Filippov void tcg_dump_op_count(FILE *f, fprintf_function cpu_fprintf)
2514c896fe29Sbellard {
2515c896fe29Sbellard     int i;
2516d70724ceSzhanghailiang 
251715fc7daaSRichard Henderson     for (i = 0; i < NB_OPS; i++) {
2518246ae24dSMax Filippov         cpu_fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name,
2519246ae24dSMax Filippov                     tcg_table_op_count[i]);
2520c896fe29Sbellard     }
2521c896fe29Sbellard }
2522246ae24dSMax Filippov #else
2523246ae24dSMax Filippov void tcg_dump_op_count(FILE *f, fprintf_function cpu_fprintf)
2524246ae24dSMax Filippov {
2525246ae24dSMax Filippov     cpu_fprintf(f, "[TCG profiler not compiled]\n");
2526246ae24dSMax Filippov }
2527c896fe29Sbellard #endif
2528c896fe29Sbellard 
2529c896fe29Sbellard 
25305bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
2531c896fe29Sbellard {
2532fca8a500SRichard Henderson     int i, oi, oi_next, num_insns;
2533c896fe29Sbellard 
253404fe6400SRichard Henderson #ifdef CONFIG_PROFILER
253504fe6400SRichard Henderson     {
253604fe6400SRichard Henderson         int n;
253704fe6400SRichard Henderson 
2538dcb8e758SRichard Henderson         n = s->gen_op_buf[0].prev + 1;
253904fe6400SRichard Henderson         s->op_count += n;
254004fe6400SRichard Henderson         if (n > s->op_count_max) {
254104fe6400SRichard Henderson             s->op_count_max = n;
254204fe6400SRichard Henderson         }
254304fe6400SRichard Henderson 
254404fe6400SRichard Henderson         n = s->nb_temps;
254504fe6400SRichard Henderson         s->temp_count += n;
254604fe6400SRichard Henderson         if (n > s->temp_count_max) {
254704fe6400SRichard Henderson             s->temp_count_max = n;
254804fe6400SRichard Henderson         }
254904fe6400SRichard Henderson     }
255004fe6400SRichard Henderson #endif
255104fe6400SRichard Henderson 
2552c896fe29Sbellard #ifdef DEBUG_DISAS
2553d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
2554d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
25551ee73216SRichard Henderson         qemu_log_lock();
255693fcfe39Saliguori         qemu_log("OP:\n");
2557eeacee4dSBlue Swirl         tcg_dump_ops(s);
255893fcfe39Saliguori         qemu_log("\n");
25591ee73216SRichard Henderson         qemu_log_unlock();
2560c896fe29Sbellard     }
2561c896fe29Sbellard #endif
2562c896fe29Sbellard 
2563c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
2564c5cc28ffSAurelien Jarno     s->opt_time -= profile_getclock();
2565c5cc28ffSAurelien Jarno #endif
2566c5cc28ffSAurelien Jarno 
25678f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
2568c45cb8bbSRichard Henderson     tcg_optimize(s);
25698f2e8c07SKirill Batuzov #endif
25708f2e8c07SKirill Batuzov 
2571a23a9ec6Sbellard #ifdef CONFIG_PROFILER
2572c5cc28ffSAurelien Jarno     s->opt_time += profile_getclock();
2573a23a9ec6Sbellard     s->la_time -= profile_getclock();
2574a23a9ec6Sbellard #endif
2575c5cc28ffSAurelien Jarno 
25765a18407fSRichard Henderson     {
25775a18407fSRichard Henderson         uint8_t *temp_state = tcg_malloc(s->nb_temps + s->nb_indirects);
25785a18407fSRichard Henderson 
25795a18407fSRichard Henderson         liveness_pass_1(s, temp_state);
25805a18407fSRichard Henderson 
25815a18407fSRichard Henderson         if (s->nb_indirects > 0) {
25825a18407fSRichard Henderson #ifdef DEBUG_DISAS
25835a18407fSRichard Henderson             if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
25845a18407fSRichard Henderson                          && qemu_log_in_addr_range(tb->pc))) {
25851ee73216SRichard Henderson                 qemu_log_lock();
25865a18407fSRichard Henderson                 qemu_log("OP before indirect lowering:\n");
25875a18407fSRichard Henderson                 tcg_dump_ops(s);
25885a18407fSRichard Henderson                 qemu_log("\n");
25891ee73216SRichard Henderson                 qemu_log_unlock();
25905a18407fSRichard Henderson             }
25915a18407fSRichard Henderson #endif
25925a18407fSRichard Henderson             /* Replace indirect temps with direct temps.  */
25935a18407fSRichard Henderson             if (liveness_pass_2(s, temp_state)) {
25945a18407fSRichard Henderson                 /* If changes were made, re-run liveness.  */
25955a18407fSRichard Henderson                 liveness_pass_1(s, temp_state);
25965a18407fSRichard Henderson             }
25975a18407fSRichard Henderson         }
25985a18407fSRichard Henderson     }
2599c5cc28ffSAurelien Jarno 
2600a23a9ec6Sbellard #ifdef CONFIG_PROFILER
2601a23a9ec6Sbellard     s->la_time += profile_getclock();
2602a23a9ec6Sbellard #endif
2603c896fe29Sbellard 
2604c896fe29Sbellard #ifdef DEBUG_DISAS
2605d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
2606d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
26071ee73216SRichard Henderson         qemu_log_lock();
2608c5cc28ffSAurelien Jarno         qemu_log("OP after optimization and liveness analysis:\n");
2609eeacee4dSBlue Swirl         tcg_dump_ops(s);
261093fcfe39Saliguori         qemu_log("\n");
26111ee73216SRichard Henderson         qemu_log_unlock();
2612c896fe29Sbellard     }
2613c896fe29Sbellard #endif
2614c896fe29Sbellard 
2615c896fe29Sbellard     tcg_reg_alloc_start(s);
2616c896fe29Sbellard 
26175bd2ec3dSAlex Bennée     s->code_buf = tb->tc_ptr;
26185bd2ec3dSAlex Bennée     s->code_ptr = tb->tc_ptr;
2619c896fe29Sbellard 
2620659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
2621659ef5cbSRichard Henderson     s->ldst_labels = NULL;
2622659ef5cbSRichard Henderson #endif
2623*57a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
2624*57a26946SRichard Henderson     s->pool_labels = NULL;
2625*57a26946SRichard Henderson #endif
26269ecefc84SRichard Henderson 
2627fca8a500SRichard Henderson     num_insns = -1;
2628dcb8e758SRichard Henderson     for (oi = s->gen_op_buf[0].next; oi != 0; oi = oi_next) {
2629c45cb8bbSRichard Henderson         TCGOp * const op = &s->gen_op_buf[oi];
2630c45cb8bbSRichard Henderson         TCGArg * const args = &s->gen_opparam_buf[op->args];
2631c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2632c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2633bee158cbSRichard Henderson         TCGLifeData arg_life = op->life;
2634b3db8758Sblueswir1 
2635c45cb8bbSRichard Henderson         oi_next = op->next;
2636c896fe29Sbellard #ifdef CONFIG_PROFILER
263754604f74Saurel32         tcg_table_op_count[opc]++;
2638c896fe29Sbellard #endif
2639c45cb8bbSRichard Henderson 
2640c896fe29Sbellard         switch (opc) {
2641c896fe29Sbellard         case INDEX_op_mov_i32:
2642c896fe29Sbellard         case INDEX_op_mov_i64:
2643a1b3c48dSRichard Henderson             tcg_reg_alloc_mov(s, def, args, arg_life);
2644c896fe29Sbellard             break;
2645e8996ee0Sbellard         case INDEX_op_movi_i32:
2646e8996ee0Sbellard         case INDEX_op_movi_i64:
2647a1b3c48dSRichard Henderson             tcg_reg_alloc_movi(s, args, arg_life);
2648e8996ee0Sbellard             break;
2649765b842aSRichard Henderson         case INDEX_op_insn_start:
2650fca8a500SRichard Henderson             if (num_insns >= 0) {
2651fca8a500SRichard Henderson                 s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
2652fca8a500SRichard Henderson             }
2653fca8a500SRichard Henderson             num_insns++;
2654bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
2655bad729e2SRichard Henderson                 target_ulong a;
2656bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
2657bad729e2SRichard Henderson                 a = ((target_ulong)args[i * 2 + 1] << 32) | args[i * 2];
2658bad729e2SRichard Henderson #else
2659bad729e2SRichard Henderson                 a = args[i];
2660bad729e2SRichard Henderson #endif
2661fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
2662bad729e2SRichard Henderson             }
2663c896fe29Sbellard             break;
26645ff9d6a4Sbellard         case INDEX_op_discard:
2665f8bf00f1SRichard Henderson             temp_dead(s, &s->temps[args[0]]);
26665ff9d6a4Sbellard             break;
2667c896fe29Sbellard         case INDEX_op_set_label:
2668e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
2669bec16311SRichard Henderson             tcg_out_label(s, arg_label(args[0]), s->code_ptr);
2670c896fe29Sbellard             break;
2671c896fe29Sbellard         case INDEX_op_call:
2672a1b3c48dSRichard Henderson             tcg_reg_alloc_call(s, op->callo, op->calli, args, arg_life);
2673c45cb8bbSRichard Henderson             break;
2674c896fe29Sbellard         default:
267525c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
267625c4d9ccSRichard Henderson             if (def->flags & TCG_OPF_NOT_PRESENT) {
267725c4d9ccSRichard Henderson                 tcg_abort();
267825c4d9ccSRichard Henderson             }
2679c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
2680c896fe29Sbellard                faster to have specialized register allocator functions for
2681c896fe29Sbellard                some common argument patterns */
2682a1b3c48dSRichard Henderson             tcg_reg_alloc_op(s, def, opc, args, arg_life);
2683c896fe29Sbellard             break;
2684c896fe29Sbellard         }
26858d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
2686c896fe29Sbellard         check_regs(s);
2687c896fe29Sbellard #endif
2688b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
2689b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
2690b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
2691b125f9dcSRichard Henderson            generating code without having to check during generation.  */
2692644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
2693b125f9dcSRichard Henderson             return -1;
2694b125f9dcSRichard Henderson         }
2695c896fe29Sbellard     }
2696fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
2697fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
2698c45cb8bbSRichard Henderson 
2699b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
2700659ef5cbSRichard Henderson #ifdef TCG_TARGET_NEED_LDST_LABELS
2701659ef5cbSRichard Henderson     if (!tcg_out_ldst_finalize(s)) {
270223dceda6SRichard Henderson         return -1;
270323dceda6SRichard Henderson     }
2704659ef5cbSRichard Henderson #endif
2705*57a26946SRichard Henderson #ifdef TCG_TARGET_NEED_POOL_LABELS
2706*57a26946SRichard Henderson     if (!tcg_out_pool_finalize(s)) {
2707*57a26946SRichard Henderson         return -1;
2708*57a26946SRichard Henderson     }
2709*57a26946SRichard Henderson #endif
2710c896fe29Sbellard 
2711c896fe29Sbellard     /* flush instruction cache */
27121813e175SRichard Henderson     flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr);
27132aeabc08SStefan Weil 
27141813e175SRichard Henderson     return tcg_current_code_size(s);
2715c896fe29Sbellard }
2716c896fe29Sbellard 
2717a23a9ec6Sbellard #ifdef CONFIG_PROFILER
2718405cf9ffSStefan Weil void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
2719a23a9ec6Sbellard {
2720a23a9ec6Sbellard     TCGContext *s = &tcg_ctx;
2721fca8a500SRichard Henderson     int64_t tb_count = s->tb_count;
2722fca8a500SRichard Henderson     int64_t tb_div_count = tb_count ? tb_count : 1;
2723fca8a500SRichard Henderson     int64_t tot = s->interm_time + s->code_time;
2724a23a9ec6Sbellard 
2725a23a9ec6Sbellard     cpu_fprintf(f, "JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
2726a23a9ec6Sbellard                 tot, tot / 2.4e9);
2727a23a9ec6Sbellard     cpu_fprintf(f, "translated TBs      %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n",
2728fca8a500SRichard Henderson                 tb_count, s->tb_count1 - tb_count,
2729fca8a500SRichard Henderson                 (double)(s->tb_count1 - s->tb_count)
2730fca8a500SRichard Henderson                 / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
2731a23a9ec6Sbellard     cpu_fprintf(f, "avg ops/TB          %0.1f max=%d\n",
2732fca8a500SRichard Henderson                 (double)s->op_count / tb_div_count, s->op_count_max);
2733a23a9ec6Sbellard     cpu_fprintf(f, "deleted ops/TB      %0.2f\n",
2734fca8a500SRichard Henderson                 (double)s->del_op_count / tb_div_count);
2735a23a9ec6Sbellard     cpu_fprintf(f, "avg temps/TB        %0.2f max=%d\n",
2736fca8a500SRichard Henderson                 (double)s->temp_count / tb_div_count, s->temp_count_max);
2737fca8a500SRichard Henderson     cpu_fprintf(f, "avg host code/TB    %0.1f\n",
2738fca8a500SRichard Henderson                 (double)s->code_out_len / tb_div_count);
2739fca8a500SRichard Henderson     cpu_fprintf(f, "avg search data/TB  %0.1f\n",
2740fca8a500SRichard Henderson                 (double)s->search_out_len / tb_div_count);
2741a23a9ec6Sbellard 
2742a23a9ec6Sbellard     cpu_fprintf(f, "cycles/op           %0.1f\n",
2743a23a9ec6Sbellard                 s->op_count ? (double)tot / s->op_count : 0);
2744a23a9ec6Sbellard     cpu_fprintf(f, "cycles/in byte      %0.1f\n",
2745a23a9ec6Sbellard                 s->code_in_len ? (double)tot / s->code_in_len : 0);
2746a23a9ec6Sbellard     cpu_fprintf(f, "cycles/out byte     %0.1f\n",
2747a23a9ec6Sbellard                 s->code_out_len ? (double)tot / s->code_out_len : 0);
2748fca8a500SRichard Henderson     cpu_fprintf(f, "cycles/search byte     %0.1f\n",
2749fca8a500SRichard Henderson                 s->search_out_len ? (double)tot / s->search_out_len : 0);
2750fca8a500SRichard Henderson     if (tot == 0) {
2751a23a9ec6Sbellard         tot = 1;
2752fca8a500SRichard Henderson     }
2753a23a9ec6Sbellard     cpu_fprintf(f, "  gen_interm time   %0.1f%%\n",
2754a23a9ec6Sbellard                 (double)s->interm_time / tot * 100.0);
2755a23a9ec6Sbellard     cpu_fprintf(f, "  gen_code time     %0.1f%%\n",
2756a23a9ec6Sbellard                 (double)s->code_time / tot * 100.0);
2757c5cc28ffSAurelien Jarno     cpu_fprintf(f, "optim./code time    %0.1f%%\n",
2758c5cc28ffSAurelien Jarno                 (double)s->opt_time / (s->code_time ? s->code_time : 1)
2759c5cc28ffSAurelien Jarno                 * 100.0);
2760a23a9ec6Sbellard     cpu_fprintf(f, "liveness/code time  %0.1f%%\n",
2761a23a9ec6Sbellard                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
2762a23a9ec6Sbellard     cpu_fprintf(f, "cpu_restore count   %" PRId64 "\n",
2763a23a9ec6Sbellard                 s->restore_count);
2764a23a9ec6Sbellard     cpu_fprintf(f, "  avg cycles        %0.1f\n",
2765a23a9ec6Sbellard                 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
2766a23a9ec6Sbellard }
2767a23a9ec6Sbellard #else
2768405cf9ffSStefan Weil void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
2769a23a9ec6Sbellard {
277024bf7b3aSbellard     cpu_fprintf(f, "[TCG profiler not compiled]\n");
2771a23a9ec6Sbellard }
2772a23a9ec6Sbellard #endif
2773813da627SRichard Henderson 
2774813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
27755872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
27765872bbf2SRichard Henderson 
27775872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
27785872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
27795872bbf2SRichard Henderson 
27805872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
27815872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
27825872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
27835872bbf2SRichard Henderson 
27845872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
27855872bbf2SRichard Henderson */
2786813da627SRichard Henderson 
2787813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
2788813da627SRichard Henderson typedef enum {
2789813da627SRichard Henderson     JIT_NOACTION = 0,
2790813da627SRichard Henderson     JIT_REGISTER_FN,
2791813da627SRichard Henderson     JIT_UNREGISTER_FN
2792813da627SRichard Henderson } jit_actions_t;
2793813da627SRichard Henderson 
2794813da627SRichard Henderson struct jit_code_entry {
2795813da627SRichard Henderson     struct jit_code_entry *next_entry;
2796813da627SRichard Henderson     struct jit_code_entry *prev_entry;
2797813da627SRichard Henderson     const void *symfile_addr;
2798813da627SRichard Henderson     uint64_t symfile_size;
2799813da627SRichard Henderson };
2800813da627SRichard Henderson 
2801813da627SRichard Henderson struct jit_descriptor {
2802813da627SRichard Henderson     uint32_t version;
2803813da627SRichard Henderson     uint32_t action_flag;
2804813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
2805813da627SRichard Henderson     struct jit_code_entry *first_entry;
2806813da627SRichard Henderson };
2807813da627SRichard Henderson 
2808813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
2809813da627SRichard Henderson void __jit_debug_register_code(void)
2810813da627SRichard Henderson {
2811813da627SRichard Henderson     asm("");
2812813da627SRichard Henderson }
2813813da627SRichard Henderson 
2814813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
2815813da627SRichard Henderson    the version before we can set it.  */
2816813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
2817813da627SRichard Henderson 
2818813da627SRichard Henderson /* End GDB interface.  */
2819813da627SRichard Henderson 
2820813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
2821813da627SRichard Henderson {
2822813da627SRichard Henderson     const char *p = strtab + 1;
2823813da627SRichard Henderson 
2824813da627SRichard Henderson     while (1) {
2825813da627SRichard Henderson         if (strcmp(p, str) == 0) {
2826813da627SRichard Henderson             return p - strtab;
2827813da627SRichard Henderson         }
2828813da627SRichard Henderson         p += strlen(p) + 1;
2829813da627SRichard Henderson     }
2830813da627SRichard Henderson }
2831813da627SRichard Henderson 
28325872bbf2SRichard Henderson static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
28332c90784aSRichard Henderson                                  const void *debug_frame,
28342c90784aSRichard Henderson                                  size_t debug_frame_size)
2835813da627SRichard Henderson {
28365872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
28375872bbf2SRichard Henderson         uint32_t  len;
28385872bbf2SRichard Henderson         uint16_t  version;
28395872bbf2SRichard Henderson         uint32_t  abbrev;
28405872bbf2SRichard Henderson         uint8_t   ptr_size;
28415872bbf2SRichard Henderson         uint8_t   cu_die;
28425872bbf2SRichard Henderson         uint16_t  cu_lang;
28435872bbf2SRichard Henderson         uintptr_t cu_low_pc;
28445872bbf2SRichard Henderson         uintptr_t cu_high_pc;
28455872bbf2SRichard Henderson         uint8_t   fn_die;
28465872bbf2SRichard Henderson         char      fn_name[16];
28475872bbf2SRichard Henderson         uintptr_t fn_low_pc;
28485872bbf2SRichard Henderson         uintptr_t fn_high_pc;
28495872bbf2SRichard Henderson         uint8_t   cu_eoc;
28505872bbf2SRichard Henderson     };
2851813da627SRichard Henderson 
2852813da627SRichard Henderson     struct ElfImage {
2853813da627SRichard Henderson         ElfW(Ehdr) ehdr;
2854813da627SRichard Henderson         ElfW(Phdr) phdr;
28555872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
28565872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
28575872bbf2SRichard Henderson         struct DebugInfo di;
28585872bbf2SRichard Henderson         uint8_t    da[24];
28595872bbf2SRichard Henderson         char       str[80];
28605872bbf2SRichard Henderson     };
28615872bbf2SRichard Henderson 
28625872bbf2SRichard Henderson     struct ElfImage *img;
28635872bbf2SRichard Henderson 
28645872bbf2SRichard Henderson     static const struct ElfImage img_template = {
28655872bbf2SRichard Henderson         .ehdr = {
28665872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
28675872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
28685872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
28695872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
28705872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
28715872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
28725872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
28735872bbf2SRichard Henderson             .e_type = ET_EXEC,
28745872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
28755872bbf2SRichard Henderson             .e_version = EV_CURRENT,
28765872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
28775872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
28785872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
28795872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
28805872bbf2SRichard Henderson             .e_phnum = 1,
28815872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
28825872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
28835872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
2884abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
2885abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
2886abbb3eaeSRichard Henderson #endif
2887abbb3eaeSRichard Henderson #ifdef ELF_OSABI
2888abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
2889abbb3eaeSRichard Henderson #endif
28905872bbf2SRichard Henderson         },
28915872bbf2SRichard Henderson         .phdr = {
28925872bbf2SRichard Henderson             .p_type = PT_LOAD,
28935872bbf2SRichard Henderson             .p_flags = PF_X,
28945872bbf2SRichard Henderson         },
28955872bbf2SRichard Henderson         .shdr = {
28965872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
28975872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
28985872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
28995872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
29005872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
29015872bbf2SRichard Henderson             [1] = { /* .text */
29025872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
29035872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
29045872bbf2SRichard Henderson             },
29055872bbf2SRichard Henderson             [2] = { /* .debug_info */
29065872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
29075872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
29085872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
29095872bbf2SRichard Henderson             },
29105872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
29115872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
29125872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
29135872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
29145872bbf2SRichard Henderson             },
29155872bbf2SRichard Henderson             [4] = { /* .debug_frame */
29165872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
29175872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
29185872bbf2SRichard Henderson             },
29195872bbf2SRichard Henderson             [5] = { /* .symtab */
29205872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
29215872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
29225872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
29235872bbf2SRichard Henderson                 .sh_info = 1,
29245872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
29255872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
29265872bbf2SRichard Henderson             },
29275872bbf2SRichard Henderson             [6] = { /* .strtab */
29285872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
29295872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
29305872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
29315872bbf2SRichard Henderson             }
29325872bbf2SRichard Henderson         },
29335872bbf2SRichard Henderson         .sym = {
29345872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
29355872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
29365872bbf2SRichard Henderson                 .st_shndx = 1,
29375872bbf2SRichard Henderson             }
29385872bbf2SRichard Henderson         },
29395872bbf2SRichard Henderson         .di = {
29405872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
29415872bbf2SRichard Henderson             .version = 2,
29425872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
29435872bbf2SRichard Henderson             .cu_die = 1,
29445872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
29455872bbf2SRichard Henderson             .fn_die = 2,
29465872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
29475872bbf2SRichard Henderson         },
29485872bbf2SRichard Henderson         .da = {
29495872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
29505872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
29515872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
29525872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
29535872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
29545872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
29555872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
29565872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
29575872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
29585872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
29595872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
29605872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
29615872bbf2SRichard Henderson             0           /* no more abbrev */
29625872bbf2SRichard Henderson         },
29635872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
29645872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
2965813da627SRichard Henderson     };
2966813da627SRichard Henderson 
2967813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
2968813da627SRichard Henderson     static struct jit_code_entry one_entry;
2969813da627SRichard Henderson 
29705872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
2971813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
29722c90784aSRichard Henderson     DebugFrameHeader *dfh;
2973813da627SRichard Henderson 
29745872bbf2SRichard Henderson     img = g_malloc(img_size);
29755872bbf2SRichard Henderson     *img = img_template;
2976813da627SRichard Henderson 
29775872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
29785872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
29795872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
2980813da627SRichard Henderson 
29815872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
29825872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
29835872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
2984813da627SRichard Henderson 
29855872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
29865872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
29875872bbf2SRichard Henderson 
29885872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
29895872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
29905872bbf2SRichard Henderson 
29915872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
29925872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
29935872bbf2SRichard Henderson 
29945872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
29955872bbf2SRichard Henderson     img->sym[1].st_value = buf;
29965872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
29975872bbf2SRichard Henderson 
29985872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
299945aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
30005872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
300145aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
3002813da627SRichard Henderson 
30032c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
30042c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
30052c90784aSRichard Henderson     dfh->fde.func_start = buf;
30062c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
30072c90784aSRichard Henderson 
3008813da627SRichard Henderson #ifdef DEBUG_JIT
3009813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
3010813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
3011813da627SRichard Henderson     {
3012813da627SRichard Henderson         FILE *f = fopen("/tmp/qemu.jit", "w+b");
3013813da627SRichard Henderson         if (f) {
30145872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
3015813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
3016813da627SRichard Henderson             }
3017813da627SRichard Henderson             fclose(f);
3018813da627SRichard Henderson         }
3019813da627SRichard Henderson     }
3020813da627SRichard Henderson #endif
3021813da627SRichard Henderson 
3022813da627SRichard Henderson     one_entry.symfile_addr = img;
3023813da627SRichard Henderson     one_entry.symfile_size = img_size;
3024813da627SRichard Henderson 
3025813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
3026813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
3027813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
3028813da627SRichard Henderson     __jit_debug_register_code();
3029813da627SRichard Henderson }
3030813da627SRichard Henderson #else
30315872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
30325872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
3033813da627SRichard Henderson 
3034813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size,
30352c90784aSRichard Henderson                                  const void *debug_frame,
30362c90784aSRichard Henderson                                  size_t debug_frame_size)
3037813da627SRichard Henderson {
3038813da627SRichard Henderson }
3039813da627SRichard Henderson 
3040813da627SRichard Henderson void tcg_register_jit(void *buf, size_t buf_size)
3041813da627SRichard Henderson {
3042813da627SRichard Henderson }
3043813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
3044