xref: /qemu/tcg/tcg.c (revision f69d277ece43c42c7ab0144c2ff05ba740f6706b)
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);
65*f69d277eSRichard 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. */
99c0ad3001SStefan Weil static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str);
1002a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
101a05b5b9bSRichard Henderson                        intptr_t arg2);
1022a534affSRichard Henderson static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
103c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1042a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
105c0ad3001SStefan Weil static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
106c0ad3001SStefan Weil                        const int *const_args);
1072a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
108a05b5b9bSRichard Henderson                        intptr_t arg2);
10959d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
11059d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
111cf066674SRichard Henderson static void tcg_out_call(TCGContext *s, tcg_insn_unit *target);
112f6c6afc1SRichard Henderson static int tcg_target_const_match(tcg_target_long val, TCGType type,
113c0ad3001SStefan Weil                                   const TCGArgConstraint *arg_ct);
1149ecefc84SRichard Henderson static void tcg_out_tb_init(TCGContext *s);
11523dceda6SRichard Henderson static bool tcg_out_tb_finalize(TCGContext *s);
1169ecefc84SRichard Henderson 
117c0ad3001SStefan Weil 
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)];
323*f69d277eSRichard 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);
367*f69d277eSRichard 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 
3859002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
3869002ec79SRichard Henderson {
3878163b749SRichard Henderson     size_t prologue_size, total_size;
3888163b749SRichard Henderson     void *buf0, *buf1;
3898163b749SRichard Henderson 
3908163b749SRichard Henderson     /* Put the prologue at the beginning of code_gen_buffer.  */
3918163b749SRichard Henderson     buf0 = s->code_gen_buffer;
3928163b749SRichard Henderson     s->code_ptr = buf0;
3938163b749SRichard Henderson     s->code_buf = buf0;
3948163b749SRichard Henderson     s->code_gen_prologue = buf0;
3958163b749SRichard Henderson 
3968163b749SRichard Henderson     /* Generate the prologue.  */
397b03cce8eSbellard     tcg_target_qemu_prologue(s);
3988163b749SRichard Henderson     buf1 = s->code_ptr;
3998163b749SRichard Henderson     flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1);
4008163b749SRichard Henderson 
4018163b749SRichard Henderson     /* Deduct the prologue from the buffer.  */
4028163b749SRichard Henderson     prologue_size = tcg_current_code_size(s);
4038163b749SRichard Henderson     s->code_gen_ptr = buf1;
4048163b749SRichard Henderson     s->code_gen_buffer = buf1;
4058163b749SRichard Henderson     s->code_buf = buf1;
4068163b749SRichard Henderson     total_size = s->code_gen_buffer_size - prologue_size;
4078163b749SRichard Henderson     s->code_gen_buffer_size = total_size;
4088163b749SRichard Henderson 
409b125f9dcSRichard Henderson     /* Compute a high-water mark, at which we voluntarily flush the buffer
410b125f9dcSRichard Henderson        and start over.  The size here is arbitrary, significantly larger
411b125f9dcSRichard Henderson        than we expect the code generation for any one opcode to require.  */
41223dceda6SRichard Henderson     s->code_gen_highwater = s->code_gen_buffer + (total_size - 1024);
4138163b749SRichard Henderson 
4148163b749SRichard Henderson     tcg_register_jit(s->code_gen_buffer, total_size);
415d6b64b2bSRichard Henderson 
416d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
417d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
4181ee73216SRichard Henderson         qemu_log_lock();
4198163b749SRichard Henderson         qemu_log("PROLOGUE: [size=%zu]\n", prologue_size);
4208163b749SRichard Henderson         log_disas(buf0, prologue_size);
421d6b64b2bSRichard Henderson         qemu_log("\n");
422d6b64b2bSRichard Henderson         qemu_log_flush();
4231ee73216SRichard Henderson         qemu_log_unlock();
424d6b64b2bSRichard Henderson     }
425d6b64b2bSRichard Henderson #endif
426c896fe29Sbellard }
427c896fe29Sbellard 
428c896fe29Sbellard void tcg_func_start(TCGContext *s)
429c896fe29Sbellard {
430c896fe29Sbellard     tcg_pool_reset(s);
431c896fe29Sbellard     s->nb_temps = s->nb_globals;
4320ec9eabcSRichard Henderson 
4330ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
4340ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
4350ec9eabcSRichard Henderson 
436c896fe29Sbellard     s->nb_labels = 0;
437c896fe29Sbellard     s->current_frame_offset = s->frame_start;
438c896fe29Sbellard 
4390a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
4400a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
4410a209d4bSRichard Henderson #endif
4420a209d4bSRichard Henderson 
443dcb8e758SRichard Henderson     s->gen_op_buf[0].next = 1;
444dcb8e758SRichard Henderson     s->gen_op_buf[0].prev = 0;
445dcb8e758SRichard Henderson     s->gen_next_op_idx = 1;
446c45cb8bbSRichard Henderson     s->gen_next_parm_idx = 0;
447b76f0d8cSYeongkyoon Lee 
4489ecefc84SRichard Henderson     s->be = tcg_malloc(sizeof(TCGBackendData));
449c896fe29Sbellard }
450c896fe29Sbellard 
4517ca4b752SRichard Henderson static inline int temp_idx(TCGContext *s, TCGTemp *ts)
452c896fe29Sbellard {
4537ca4b752SRichard Henderson     ptrdiff_t n = ts - s->temps;
4547ca4b752SRichard Henderson     tcg_debug_assert(n >= 0 && n < s->nb_temps);
4557ca4b752SRichard Henderson     return n;
4567ca4b752SRichard Henderson }
4577ca4b752SRichard Henderson 
4587ca4b752SRichard Henderson static inline TCGTemp *tcg_temp_alloc(TCGContext *s)
4597ca4b752SRichard Henderson {
4607ca4b752SRichard Henderson     int n = s->nb_temps++;
4617ca4b752SRichard Henderson     tcg_debug_assert(n < TCG_MAX_TEMPS);
4627ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
4637ca4b752SRichard Henderson }
4647ca4b752SRichard Henderson 
4657ca4b752SRichard Henderson static inline TCGTemp *tcg_global_alloc(TCGContext *s)
4667ca4b752SRichard Henderson {
4677ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
4687ca4b752SRichard Henderson     s->nb_globals++;
4697ca4b752SRichard Henderson     return tcg_temp_alloc(s);
470c896fe29Sbellard }
471c896fe29Sbellard 
472b3a62939SRichard Henderson static int tcg_global_reg_new_internal(TCGContext *s, TCGType type,
473b6638662SRichard Henderson                                        TCGReg reg, const char *name)
474c896fe29Sbellard {
475c896fe29Sbellard     TCGTemp *ts;
476c896fe29Sbellard 
477b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
478c896fe29Sbellard         tcg_abort();
479b3a62939SRichard Henderson     }
4807ca4b752SRichard Henderson 
4817ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
482c896fe29Sbellard     ts->base_type = type;
483c896fe29Sbellard     ts->type = type;
484c896fe29Sbellard     ts->fixed_reg = 1;
485c896fe29Sbellard     ts->reg = reg;
486c896fe29Sbellard     ts->name = name;
487c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
4887ca4b752SRichard Henderson 
4897ca4b752SRichard Henderson     return temp_idx(s, ts);
490a7812ae4Spbrook }
491a7812ae4Spbrook 
492b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
493a7812ae4Spbrook {
494a7812ae4Spbrook     int idx;
495b3a62939SRichard Henderson     s->frame_start = start;
496b3a62939SRichard Henderson     s->frame_end = start + size;
497b3a62939SRichard Henderson     idx = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
498b3a62939SRichard Henderson     s->frame_temp = &s->temps[idx];
499b3a62939SRichard Henderson }
500a7812ae4Spbrook 
501b6638662SRichard Henderson TCGv_i32 tcg_global_reg_new_i32(TCGReg reg, const char *name)
502b3a62939SRichard Henderson {
503b3a62939SRichard Henderson     TCGContext *s = &tcg_ctx;
504b3a62939SRichard Henderson     int idx;
505b3a62939SRichard Henderson 
506b3a62939SRichard Henderson     if (tcg_regset_test_reg(s->reserved_regs, reg)) {
507b3a62939SRichard Henderson         tcg_abort();
508b3a62939SRichard Henderson     }
509b3a62939SRichard Henderson     idx = tcg_global_reg_new_internal(s, TCG_TYPE_I32, reg, name);
510a7812ae4Spbrook     return MAKE_TCGV_I32(idx);
511a7812ae4Spbrook }
512a7812ae4Spbrook 
513b6638662SRichard Henderson TCGv_i64 tcg_global_reg_new_i64(TCGReg reg, const char *name)
514a7812ae4Spbrook {
515b3a62939SRichard Henderson     TCGContext *s = &tcg_ctx;
516a7812ae4Spbrook     int idx;
517a7812ae4Spbrook 
518b3a62939SRichard Henderson     if (tcg_regset_test_reg(s->reserved_regs, reg)) {
519b3a62939SRichard Henderson         tcg_abort();
520b3a62939SRichard Henderson     }
521b3a62939SRichard Henderson     idx = tcg_global_reg_new_internal(s, TCG_TYPE_I64, reg, name);
522a7812ae4Spbrook     return MAKE_TCGV_I64(idx);
523c896fe29Sbellard }
524c896fe29Sbellard 
525e1ccc054SRichard Henderson int tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
526e1ccc054SRichard Henderson                                 intptr_t offset, const char *name)
527c896fe29Sbellard {
528c896fe29Sbellard     TCGContext *s = &tcg_ctx;
5297ca4b752SRichard Henderson     TCGTemp *base_ts = &s->temps[GET_TCGV_PTR(base)];
5307ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
531b3915dbbSRichard Henderson     int indirect_reg = 0, bigendian = 0;
5327ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
5337ca4b752SRichard Henderson     bigendian = 1;
5347ca4b752SRichard Henderson #endif
535c896fe29Sbellard 
536b3915dbbSRichard Henderson     if (!base_ts->fixed_reg) {
5375a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
5385a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
539b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
5405a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
5415a18407fSRichard Henderson                             ? 2 : 1);
5425a18407fSRichard Henderson         indirect_reg = 1;
543b3915dbbSRichard Henderson     }
544b3915dbbSRichard Henderson 
5457ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
5467ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
547c896fe29Sbellard         char buf[64];
5487ca4b752SRichard Henderson 
5497ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
550c896fe29Sbellard         ts->type = TCG_TYPE_I32;
551b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
552c896fe29Sbellard         ts->mem_allocated = 1;
553b3a62939SRichard Henderson         ts->mem_base = base_ts;
5547ca4b752SRichard Henderson         ts->mem_offset = offset + bigendian * 4;
555c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
556c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
557c896fe29Sbellard         ts->name = strdup(buf);
558c896fe29Sbellard 
5597ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
5607ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
5617ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
562b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
5637ca4b752SRichard Henderson         ts2->mem_allocated = 1;
5647ca4b752SRichard Henderson         ts2->mem_base = base_ts;
5657ca4b752SRichard Henderson         ts2->mem_offset = offset + (1 - bigendian) * 4;
566c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
567c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
568120c1084SRichard Henderson         ts2->name = strdup(buf);
5697ca4b752SRichard Henderson     } else {
570c896fe29Sbellard         ts->base_type = type;
571c896fe29Sbellard         ts->type = type;
572b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
573c896fe29Sbellard         ts->mem_allocated = 1;
574b3a62939SRichard Henderson         ts->mem_base = base_ts;
575c896fe29Sbellard         ts->mem_offset = offset;
576c896fe29Sbellard         ts->name = name;
577c896fe29Sbellard     }
5787ca4b752SRichard Henderson     return temp_idx(s, ts);
579c896fe29Sbellard }
580c896fe29Sbellard 
5817ca4b752SRichard Henderson static int tcg_temp_new_internal(TCGType type, int temp_local)
582c896fe29Sbellard {
583c896fe29Sbellard     TCGContext *s = &tcg_ctx;
584c896fe29Sbellard     TCGTemp *ts;
585641d5fbeSbellard     int idx, k;
586c896fe29Sbellard 
5870ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
5880ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
5890ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
5900ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
5910ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
5920ec9eabcSRichard Henderson 
593e8996ee0Sbellard         ts = &s->temps[idx];
594e8996ee0Sbellard         ts->temp_allocated = 1;
5957ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
5967ca4b752SRichard Henderson         tcg_debug_assert(ts->temp_local == temp_local);
597e8996ee0Sbellard     } else {
5987ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
5997ca4b752SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
6007ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
6017ca4b752SRichard Henderson 
602c896fe29Sbellard             ts->base_type = type;
603c896fe29Sbellard             ts->type = TCG_TYPE_I32;
604e8996ee0Sbellard             ts->temp_allocated = 1;
605641d5fbeSbellard             ts->temp_local = temp_local;
6067ca4b752SRichard Henderson 
6077ca4b752SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
6087ca4b752SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
6097ca4b752SRichard Henderson             ts2->type = TCG_TYPE_I32;
6107ca4b752SRichard Henderson             ts2->temp_allocated = 1;
6117ca4b752SRichard Henderson             ts2->temp_local = temp_local;
6127ca4b752SRichard Henderson         } else {
613c896fe29Sbellard             ts->base_type = type;
614c896fe29Sbellard             ts->type = type;
615e8996ee0Sbellard             ts->temp_allocated = 1;
616641d5fbeSbellard             ts->temp_local = temp_local;
617c896fe29Sbellard         }
6187ca4b752SRichard Henderson         idx = temp_idx(s, ts);
619e8996ee0Sbellard     }
62027bfd83cSPeter Maydell 
62127bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
62227bfd83cSPeter Maydell     s->temps_in_use++;
62327bfd83cSPeter Maydell #endif
624a7812ae4Spbrook     return idx;
625c896fe29Sbellard }
626c896fe29Sbellard 
627a7812ae4Spbrook TCGv_i32 tcg_temp_new_internal_i32(int temp_local)
628a7812ae4Spbrook {
629a7812ae4Spbrook     int idx;
630a7812ae4Spbrook 
631a7812ae4Spbrook     idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local);
632a7812ae4Spbrook     return MAKE_TCGV_I32(idx);
633a7812ae4Spbrook }
634a7812ae4Spbrook 
635a7812ae4Spbrook TCGv_i64 tcg_temp_new_internal_i64(int temp_local)
636a7812ae4Spbrook {
637a7812ae4Spbrook     int idx;
638a7812ae4Spbrook 
639a7812ae4Spbrook     idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local);
640a7812ae4Spbrook     return MAKE_TCGV_I64(idx);
641a7812ae4Spbrook }
642a7812ae4Spbrook 
6430ec9eabcSRichard Henderson static void tcg_temp_free_internal(int idx)
644c896fe29Sbellard {
645c896fe29Sbellard     TCGContext *s = &tcg_ctx;
646c896fe29Sbellard     TCGTemp *ts;
647641d5fbeSbellard     int k;
648c896fe29Sbellard 
64927bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
65027bfd83cSPeter Maydell     s->temps_in_use--;
65127bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
65227bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
65327bfd83cSPeter Maydell     }
65427bfd83cSPeter Maydell #endif
65527bfd83cSPeter Maydell 
656eabb7b91SAurelien Jarno     tcg_debug_assert(idx >= s->nb_globals && idx < s->nb_temps);
657c896fe29Sbellard     ts = &s->temps[idx];
658eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
659e8996ee0Sbellard     ts->temp_allocated = 0;
6600ec9eabcSRichard Henderson 
66118d13fa2SAlexander Graf     k = ts->base_type + (ts->temp_local ? TCG_TYPE_COUNT : 0);
6620ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
663e8996ee0Sbellard }
664e8996ee0Sbellard 
665a7812ae4Spbrook void tcg_temp_free_i32(TCGv_i32 arg)
666e8996ee0Sbellard {
667a7812ae4Spbrook     tcg_temp_free_internal(GET_TCGV_I32(arg));
668a7812ae4Spbrook }
669a7812ae4Spbrook 
670a7812ae4Spbrook void tcg_temp_free_i64(TCGv_i64 arg)
671a7812ae4Spbrook {
672a7812ae4Spbrook     tcg_temp_free_internal(GET_TCGV_I64(arg));
673a7812ae4Spbrook }
674a7812ae4Spbrook 
675a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
676a7812ae4Spbrook {
677a7812ae4Spbrook     TCGv_i32 t0;
678a7812ae4Spbrook     t0 = tcg_temp_new_i32();
679e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
680e8996ee0Sbellard     return t0;
681c896fe29Sbellard }
682c896fe29Sbellard 
683a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
684c896fe29Sbellard {
685a7812ae4Spbrook     TCGv_i64 t0;
686a7812ae4Spbrook     t0 = tcg_temp_new_i64();
687e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
688e8996ee0Sbellard     return t0;
689c896fe29Sbellard }
690c896fe29Sbellard 
691a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
692bdffd4a9Saurel32 {
693a7812ae4Spbrook     TCGv_i32 t0;
694a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
695bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
696bdffd4a9Saurel32     return t0;
697bdffd4a9Saurel32 }
698bdffd4a9Saurel32 
699a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
700bdffd4a9Saurel32 {
701a7812ae4Spbrook     TCGv_i64 t0;
702a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
703bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
704bdffd4a9Saurel32     return t0;
705bdffd4a9Saurel32 }
706bdffd4a9Saurel32 
70727bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
70827bfd83cSPeter Maydell void tcg_clear_temp_count(void)
70927bfd83cSPeter Maydell {
71027bfd83cSPeter Maydell     TCGContext *s = &tcg_ctx;
71127bfd83cSPeter Maydell     s->temps_in_use = 0;
71227bfd83cSPeter Maydell }
71327bfd83cSPeter Maydell 
71427bfd83cSPeter Maydell int tcg_check_temp_count(void)
71527bfd83cSPeter Maydell {
71627bfd83cSPeter Maydell     TCGContext *s = &tcg_ctx;
71727bfd83cSPeter Maydell     if (s->temps_in_use) {
71827bfd83cSPeter Maydell         /* Clear the count so that we don't give another
71927bfd83cSPeter Maydell          * warning immediately next time around.
72027bfd83cSPeter Maydell          */
72127bfd83cSPeter Maydell         s->temps_in_use = 0;
72227bfd83cSPeter Maydell         return 1;
72327bfd83cSPeter Maydell     }
72427bfd83cSPeter Maydell     return 0;
72527bfd83cSPeter Maydell }
72627bfd83cSPeter Maydell #endif
72727bfd83cSPeter Maydell 
72839cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment
72939cf05d3Sbellard    and endian swap. Maybe it would be better to do the alignment
73039cf05d3Sbellard    and endian swap in tcg_reg_alloc_call(). */
731bbb8a1b4SRichard Henderson void tcg_gen_callN(TCGContext *s, void *func, TCGArg ret,
732bbb8a1b4SRichard Henderson                    int nargs, TCGArg *args)
733c896fe29Sbellard {
734c45cb8bbSRichard Henderson     int i, real_args, nb_rets, pi, pi_first;
735bbb8a1b4SRichard Henderson     unsigned sizemask, flags;
736afb49896SRichard Henderson     TCGHelperInfo *info;
737afb49896SRichard Henderson 
738afb49896SRichard Henderson     info = g_hash_table_lookup(s->helpers, (gpointer)func);
739bbb8a1b4SRichard Henderson     flags = info->flags;
740bbb8a1b4SRichard Henderson     sizemask = info->sizemask;
7412bece2c8SRichard Henderson 
74234b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
74334b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
74434b1a49cSRichard Henderson     /* We have 64-bit values in one register, but need to pass as two
74534b1a49cSRichard Henderson        separate parameters.  Split them.  */
74634b1a49cSRichard Henderson     int orig_sizemask = sizemask;
74734b1a49cSRichard Henderson     int orig_nargs = nargs;
74834b1a49cSRichard Henderson     TCGv_i64 retl, reth;
74934b1a49cSRichard Henderson 
75034b1a49cSRichard Henderson     TCGV_UNUSED_I64(retl);
75134b1a49cSRichard Henderson     TCGV_UNUSED_I64(reth);
75234b1a49cSRichard Henderson     if (sizemask != 0) {
75334b1a49cSRichard Henderson         TCGArg *split_args = __builtin_alloca(sizeof(TCGArg) * nargs * 2);
75434b1a49cSRichard Henderson         for (i = real_args = 0; i < nargs; ++i) {
75534b1a49cSRichard Henderson             int is_64bit = sizemask & (1 << (i+1)*2);
75634b1a49cSRichard Henderson             if (is_64bit) {
75734b1a49cSRichard Henderson                 TCGv_i64 orig = MAKE_TCGV_I64(args[i]);
75834b1a49cSRichard Henderson                 TCGv_i32 h = tcg_temp_new_i32();
75934b1a49cSRichard Henderson                 TCGv_i32 l = tcg_temp_new_i32();
76034b1a49cSRichard Henderson                 tcg_gen_extr_i64_i32(l, h, orig);
76134b1a49cSRichard Henderson                 split_args[real_args++] = GET_TCGV_I32(h);
76234b1a49cSRichard Henderson                 split_args[real_args++] = GET_TCGV_I32(l);
76334b1a49cSRichard Henderson             } else {
76434b1a49cSRichard Henderson                 split_args[real_args++] = args[i];
76534b1a49cSRichard Henderson             }
76634b1a49cSRichard Henderson         }
76734b1a49cSRichard Henderson         nargs = real_args;
76834b1a49cSRichard Henderson         args = split_args;
76934b1a49cSRichard Henderson         sizemask = 0;
77034b1a49cSRichard Henderson     }
77134b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
7722bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
7732bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
7742bece2c8SRichard Henderson         int is_signed = sizemask & (2 << (i+1)*2);
7752bece2c8SRichard Henderson         if (!is_64bit) {
7762bece2c8SRichard Henderson             TCGv_i64 temp = tcg_temp_new_i64();
7772bece2c8SRichard Henderson             TCGv_i64 orig = MAKE_TCGV_I64(args[i]);
7782bece2c8SRichard Henderson             if (is_signed) {
7792bece2c8SRichard Henderson                 tcg_gen_ext32s_i64(temp, orig);
7802bece2c8SRichard Henderson             } else {
7812bece2c8SRichard Henderson                 tcg_gen_ext32u_i64(temp, orig);
7822bece2c8SRichard Henderson             }
7832bece2c8SRichard Henderson             args[i] = GET_TCGV_I64(temp);
7842bece2c8SRichard Henderson         }
7852bece2c8SRichard Henderson     }
7862bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
7872bece2c8SRichard Henderson 
788c45cb8bbSRichard Henderson     pi_first = pi = s->gen_next_parm_idx;
789a7812ae4Spbrook     if (ret != TCG_CALL_DUMMY_ARG) {
79034b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
79134b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
79234b1a49cSRichard Henderson         if (orig_sizemask & 1) {
79334b1a49cSRichard Henderson             /* The 32-bit ABI is going to return the 64-bit value in
79434b1a49cSRichard Henderson                the %o0/%o1 register pair.  Prepare for this by using
79534b1a49cSRichard Henderson                two return temporaries, and reassemble below.  */
79634b1a49cSRichard Henderson             retl = tcg_temp_new_i64();
79734b1a49cSRichard Henderson             reth = tcg_temp_new_i64();
798c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = GET_TCGV_I64(reth);
799c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = GET_TCGV_I64(retl);
80034b1a49cSRichard Henderson             nb_rets = 2;
80134b1a49cSRichard Henderson         } else {
802c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = ret;
80334b1a49cSRichard Henderson             nb_rets = 1;
80434b1a49cSRichard Henderson         }
80534b1a49cSRichard Henderson #else
80634b1a49cSRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) {
80702eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
808c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = ret + 1;
809c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = ret;
810a7812ae4Spbrook #else
811c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = ret;
812c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = ret + 1;
813a7812ae4Spbrook #endif
814a7812ae4Spbrook             nb_rets = 2;
81534b1a49cSRichard Henderson         } else {
816c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = ret;
817a7812ae4Spbrook             nb_rets = 1;
818a7812ae4Spbrook         }
81934b1a49cSRichard Henderson #endif
820a7812ae4Spbrook     } else {
821a7812ae4Spbrook         nb_rets = 0;
822a7812ae4Spbrook     }
823a7812ae4Spbrook     real_args = 0;
824a7812ae4Spbrook     for (i = 0; i < nargs; i++) {
8252bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
826bbb8a1b4SRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
82739cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS
82839cf05d3Sbellard             /* some targets want aligned 64 bit args */
829ebd486d5Smalc             if (real_args & 1) {
830c45cb8bbSRichard Henderson                 s->gen_opparam_buf[pi++] = TCG_CALL_DUMMY_ARG;
831ebd486d5Smalc                 real_args++;
83239cf05d3Sbellard             }
83339cf05d3Sbellard #endif
8343f90f252SRichard Henderson            /* If stack grows up, then we will be placing successive
8353f90f252SRichard Henderson               arguments at lower addresses, which means we need to
8363f90f252SRichard Henderson               reverse the order compared to how we would normally
8373f90f252SRichard Henderson               treat either big or little-endian.  For those arguments
8383f90f252SRichard Henderson               that will wind up in registers, this still works for
8393f90f252SRichard Henderson               HPPA (the only current STACK_GROWSUP target) since the
8403f90f252SRichard Henderson               argument registers are *also* allocated in decreasing
8413f90f252SRichard Henderson               order.  If another such target is added, this logic may
8423f90f252SRichard Henderson               have to get more complicated to differentiate between
8433f90f252SRichard Henderson               stack arguments and register arguments.  */
84402eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
845c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = args[i] + 1;
846c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = args[i];
847c896fe29Sbellard #else
848c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = args[i];
849c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = args[i] + 1;
850c896fe29Sbellard #endif
851a7812ae4Spbrook             real_args += 2;
8522bece2c8SRichard Henderson             continue;
8532bece2c8SRichard Henderson         }
8542bece2c8SRichard Henderson 
855c45cb8bbSRichard Henderson         s->gen_opparam_buf[pi++] = args[i];
856a7812ae4Spbrook         real_args++;
857c896fe29Sbellard     }
858c45cb8bbSRichard Henderson     s->gen_opparam_buf[pi++] = (uintptr_t)func;
859c45cb8bbSRichard Henderson     s->gen_opparam_buf[pi++] = flags;
860a7812ae4Spbrook 
861c45cb8bbSRichard Henderson     i = s->gen_next_op_idx;
862c45cb8bbSRichard Henderson     tcg_debug_assert(i < OPC_BUF_SIZE);
863c45cb8bbSRichard Henderson     tcg_debug_assert(pi <= OPPARAM_BUF_SIZE);
864a7812ae4Spbrook 
865c45cb8bbSRichard Henderson     /* Set links for sequential allocation during translation.  */
866c45cb8bbSRichard Henderson     s->gen_op_buf[i] = (TCGOp){
867c45cb8bbSRichard Henderson         .opc = INDEX_op_call,
868c45cb8bbSRichard Henderson         .callo = nb_rets,
869c45cb8bbSRichard Henderson         .calli = real_args,
870c45cb8bbSRichard Henderson         .args = pi_first,
871c45cb8bbSRichard Henderson         .prev = i - 1,
872c45cb8bbSRichard Henderson         .next = i + 1
873c45cb8bbSRichard Henderson     };
874c45cb8bbSRichard Henderson 
875c45cb8bbSRichard Henderson     /* Make sure the calli field didn't overflow.  */
876c45cb8bbSRichard Henderson     tcg_debug_assert(s->gen_op_buf[i].calli == real_args);
877c45cb8bbSRichard Henderson 
878dcb8e758SRichard Henderson     s->gen_op_buf[0].prev = i;
879c45cb8bbSRichard Henderson     s->gen_next_op_idx = i + 1;
880c45cb8bbSRichard Henderson     s->gen_next_parm_idx = pi;
8812bece2c8SRichard Henderson 
88234b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
88334b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
88434b1a49cSRichard Henderson     /* Free all of the parts we allocated above.  */
88534b1a49cSRichard Henderson     for (i = real_args = 0; i < orig_nargs; ++i) {
88634b1a49cSRichard Henderson         int is_64bit = orig_sizemask & (1 << (i+1)*2);
88734b1a49cSRichard Henderson         if (is_64bit) {
88834b1a49cSRichard Henderson             TCGv_i32 h = MAKE_TCGV_I32(args[real_args++]);
88934b1a49cSRichard Henderson             TCGv_i32 l = MAKE_TCGV_I32(args[real_args++]);
89034b1a49cSRichard Henderson             tcg_temp_free_i32(h);
89134b1a49cSRichard Henderson             tcg_temp_free_i32(l);
89234b1a49cSRichard Henderson         } else {
89334b1a49cSRichard Henderson             real_args++;
89434b1a49cSRichard Henderson         }
89534b1a49cSRichard Henderson     }
89634b1a49cSRichard Henderson     if (orig_sizemask & 1) {
89734b1a49cSRichard Henderson         /* The 32-bit ABI returned two 32-bit pieces.  Re-assemble them.
89834b1a49cSRichard Henderson            Note that describing these as TCGv_i64 eliminates an unnecessary
89934b1a49cSRichard Henderson            zero-extension that tcg_gen_concat_i32_i64 would create.  */
90034b1a49cSRichard Henderson         tcg_gen_concat32_i64(MAKE_TCGV_I64(ret), retl, reth);
90134b1a49cSRichard Henderson         tcg_temp_free_i64(retl);
90234b1a49cSRichard Henderson         tcg_temp_free_i64(reth);
90334b1a49cSRichard Henderson     }
90434b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
9052bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
9062bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
9072bece2c8SRichard Henderson         if (!is_64bit) {
9082bece2c8SRichard Henderson             TCGv_i64 temp = MAKE_TCGV_I64(args[i]);
9092bece2c8SRichard Henderson             tcg_temp_free_i64(temp);
9102bece2c8SRichard Henderson         }
9112bece2c8SRichard Henderson     }
9122bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
913a7812ae4Spbrook }
914c896fe29Sbellard 
9158fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
916c896fe29Sbellard {
917c896fe29Sbellard     int i;
918c896fe29Sbellard     TCGTemp *ts;
919c896fe29Sbellard     for(i = 0; i < s->nb_globals; i++) {
920c896fe29Sbellard         ts = &s->temps[i];
921c896fe29Sbellard         if (ts->fixed_reg) {
922c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
923c896fe29Sbellard         } else {
924c896fe29Sbellard             ts->val_type = TEMP_VAL_MEM;
925c896fe29Sbellard         }
926c896fe29Sbellard     }
927e8996ee0Sbellard     for(i = s->nb_globals; i < s->nb_temps; i++) {
928e8996ee0Sbellard         ts = &s->temps[i];
9297dfd8c6aSAurelien Jarno         if (ts->temp_local) {
9307dfd8c6aSAurelien Jarno             ts->val_type = TEMP_VAL_MEM;
9317dfd8c6aSAurelien Jarno         } else {
932e8996ee0Sbellard             ts->val_type = TEMP_VAL_DEAD;
9337dfd8c6aSAurelien Jarno         }
934e8996ee0Sbellard         ts->mem_allocated = 0;
935e8996ee0Sbellard         ts->fixed_reg = 0;
936e8996ee0Sbellard     }
937f8b2f202SRichard Henderson 
938f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
939c896fe29Sbellard }
940c896fe29Sbellard 
941f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
942f8b2f202SRichard Henderson                                  TCGTemp *ts)
943c896fe29Sbellard {
944f8b2f202SRichard Henderson     int idx = temp_idx(s, ts);
945ac56dd48Spbrook 
946ac56dd48Spbrook     if (idx < s->nb_globals) {
947ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
948f8b2f202SRichard Henderson     } else if (ts->temp_local) {
949641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
950f8b2f202SRichard Henderson     } else {
951ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
952c896fe29Sbellard     }
953c896fe29Sbellard     return buf;
954c896fe29Sbellard }
955c896fe29Sbellard 
956f8b2f202SRichard Henderson static char *tcg_get_arg_str_idx(TCGContext *s, char *buf,
957f8b2f202SRichard Henderson                                  int buf_size, int idx)
958f8b2f202SRichard Henderson {
959eabb7b91SAurelien Jarno     tcg_debug_assert(idx >= 0 && idx < s->nb_temps);
960f8b2f202SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, &s->temps[idx]);
961f8b2f202SRichard Henderson }
962f8b2f202SRichard Henderson 
9636e085f72SRichard Henderson /* Find helper name.  */
9646e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val)
965e8996ee0Sbellard {
9666e085f72SRichard Henderson     const char *ret = NULL;
9676e085f72SRichard Henderson     if (s->helpers) {
96872866e82SRichard Henderson         TCGHelperInfo *info = g_hash_table_lookup(s->helpers, (gpointer)val);
96972866e82SRichard Henderson         if (info) {
97072866e82SRichard Henderson             ret = info->name;
97172866e82SRichard Henderson         }
972e8996ee0Sbellard     }
9736e085f72SRichard Henderson     return ret;
9744dc81f28Sbellard }
9754dc81f28Sbellard 
976f48f3edeSblueswir1 static const char * const cond_name[] =
977f48f3edeSblueswir1 {
9780aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
9790aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
980f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
981f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
982f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
983f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
984f48f3edeSblueswir1     [TCG_COND_LE] = "le",
985f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
986f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
987f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
988f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
989f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
990f48f3edeSblueswir1 };
991f48f3edeSblueswir1 
992f713d6adSRichard Henderson static const char * const ldst_name[] =
993f713d6adSRichard Henderson {
994f713d6adSRichard Henderson     [MO_UB]   = "ub",
995f713d6adSRichard Henderson     [MO_SB]   = "sb",
996f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
997f713d6adSRichard Henderson     [MO_LESW] = "lesw",
998f713d6adSRichard Henderson     [MO_LEUL] = "leul",
999f713d6adSRichard Henderson     [MO_LESL] = "lesl",
1000f713d6adSRichard Henderson     [MO_LEQ]  = "leq",
1001f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
1002f713d6adSRichard Henderson     [MO_BESW] = "besw",
1003f713d6adSRichard Henderson     [MO_BEUL] = "beul",
1004f713d6adSRichard Henderson     [MO_BESL] = "besl",
1005f713d6adSRichard Henderson     [MO_BEQ]  = "beq",
1006f713d6adSRichard Henderson };
1007f713d6adSRichard Henderson 
10081f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
10091f00b27fSSergey Sorokin #ifdef ALIGNED_ONLY
10101f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
10111f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
10121f00b27fSSergey Sorokin #else
10131f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
10141f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
10151f00b27fSSergey Sorokin #endif
10161f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
10171f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
10181f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
10191f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
10201f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
10211f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
10221f00b27fSSergey Sorokin };
10231f00b27fSSergey Sorokin 
1024eeacee4dSBlue Swirl void tcg_dump_ops(TCGContext *s)
1025c896fe29Sbellard {
1026c896fe29Sbellard     char buf[128];
1027c45cb8bbSRichard Henderson     TCGOp *op;
1028c45cb8bbSRichard Henderson     int oi;
1029c896fe29Sbellard 
1030dcb8e758SRichard Henderson     for (oi = s->gen_op_buf[0].next; oi != 0; oi = op->next) {
1031c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
1032c45cb8bbSRichard Henderson         const TCGOpDef *def;
1033c45cb8bbSRichard Henderson         const TCGArg *args;
1034c45cb8bbSRichard Henderson         TCGOpcode c;
1035bdfb460eSRichard Henderson         int col = 0;
1036c45cb8bbSRichard Henderson 
1037c45cb8bbSRichard Henderson         op = &s->gen_op_buf[oi];
1038c45cb8bbSRichard Henderson         c = op->opc;
1039c896fe29Sbellard         def = &tcg_op_defs[c];
1040c45cb8bbSRichard Henderson         args = &s->gen_opparam_buf[op->args];
1041c45cb8bbSRichard Henderson 
1042765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
1043bdfb460eSRichard Henderson             col += qemu_log("%s ----", oi != s->gen_op_buf[0].next ? "\n" : "");
10449aef40edSRichard Henderson 
10459aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
10469aef40edSRichard Henderson                 target_ulong a;
10477e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
10489aef40edSRichard Henderson                 a = ((target_ulong)args[i * 2 + 1] << 32) | args[i * 2];
10497e4597d7Sbellard #else
10509aef40edSRichard Henderson                 a = args[i];
10517e4597d7Sbellard #endif
1052bdfb460eSRichard Henderson                 col += qemu_log(" " TARGET_FMT_lx, a);
1053eeacee4dSBlue Swirl             }
10547e4597d7Sbellard         } else if (c == INDEX_op_call) {
1055c896fe29Sbellard             /* variable number of arguments */
1056c45cb8bbSRichard Henderson             nb_oargs = op->callo;
1057c45cb8bbSRichard Henderson             nb_iargs = op->calli;
1058c896fe29Sbellard             nb_cargs = def->nb_cargs;
1059b03cce8eSbellard 
1060cf066674SRichard Henderson             /* function name, flags, out args */
1061bdfb460eSRichard Henderson             col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name,
1062cf066674SRichard Henderson                             tcg_find_helper(s, args[nb_oargs + nb_iargs]),
1063cf066674SRichard Henderson                             args[nb_oargs + nb_iargs + 1], nb_oargs);
1064b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
1065bdfb460eSRichard Henderson                 col += qemu_log(",%s", tcg_get_arg_str_idx(s, buf, sizeof(buf),
1066eeacee4dSBlue Swirl                                                            args[i]));
1067b03cce8eSbellard             }
1068cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
1069cf066674SRichard Henderson                 TCGArg arg = args[nb_oargs + i];
1070cf066674SRichard Henderson                 const char *t = "<dummy>";
1071cf066674SRichard Henderson                 if (arg != TCG_CALL_DUMMY_ARG) {
1072cf066674SRichard Henderson                     t = tcg_get_arg_str_idx(s, buf, sizeof(buf), arg);
1073b03cce8eSbellard                 }
1074bdfb460eSRichard Henderson                 col += qemu_log(",%s", t);
1075e8996ee0Sbellard             }
1076b03cce8eSbellard         } else {
1077bdfb460eSRichard Henderson             col += qemu_log(" %s ", def->name);
1078c45cb8bbSRichard Henderson 
1079c896fe29Sbellard             nb_oargs = def->nb_oargs;
1080c896fe29Sbellard             nb_iargs = def->nb_iargs;
1081c896fe29Sbellard             nb_cargs = def->nb_cargs;
1082c896fe29Sbellard 
1083c896fe29Sbellard             k = 0;
1084c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
1085eeacee4dSBlue Swirl                 if (k != 0) {
1086bdfb460eSRichard Henderson                     col += qemu_log(",");
1087eeacee4dSBlue Swirl                 }
1088bdfb460eSRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf),
1089eeacee4dSBlue Swirl                                                           args[k++]));
1090c896fe29Sbellard             }
1091c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
1092eeacee4dSBlue Swirl                 if (k != 0) {
1093bdfb460eSRichard Henderson                     col += qemu_log(",");
1094eeacee4dSBlue Swirl                 }
1095bdfb460eSRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf),
1096eeacee4dSBlue Swirl                                                           args[k++]));
1097c896fe29Sbellard             }
1098be210acbSRichard Henderson             switch (c) {
1099be210acbSRichard Henderson             case INDEX_op_brcond_i32:
1100ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
1101ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
1102be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
1103be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
1104ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
1105be210acbSRichard Henderson             case INDEX_op_setcond_i64:
1106ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
1107eeacee4dSBlue Swirl                 if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]]) {
1108bdfb460eSRichard Henderson                     col += qemu_log(",%s", cond_name[args[k++]]);
1109eeacee4dSBlue Swirl                 } else {
1110bdfb460eSRichard Henderson                     col += qemu_log(",$0x%" TCG_PRIlx, args[k++]);
1111eeacee4dSBlue Swirl                 }
1112f48f3edeSblueswir1                 i = 1;
1113be210acbSRichard Henderson                 break;
1114f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
1115f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
1116f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
1117f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
111859227d5dSRichard Henderson                 {
111959227d5dSRichard Henderson                     TCGMemOpIdx oi = args[k++];
112059227d5dSRichard Henderson                     TCGMemOp op = get_memop(oi);
112159227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
112259227d5dSRichard Henderson 
112359c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
1124bdfb460eSRichard Henderson                         col += qemu_log(",$0x%x,%u", op, ix);
112559c4b7e8SRichard Henderson                     } else {
11261f00b27fSSergey Sorokin                         const char *s_al, *s_op;
11271f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
112859c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
1129bdfb460eSRichard Henderson                         col += qemu_log(",%s%s,%u", s_al, s_op, ix);
1130f713d6adSRichard Henderson                     }
1131f713d6adSRichard Henderson                     i = 1;
113259227d5dSRichard Henderson                 }
1133f713d6adSRichard Henderson                 break;
1134be210acbSRichard Henderson             default:
1135f48f3edeSblueswir1                 i = 0;
1136be210acbSRichard Henderson                 break;
1137be210acbSRichard Henderson             }
113851e3972cSRichard Henderson             switch (c) {
113951e3972cSRichard Henderson             case INDEX_op_set_label:
114051e3972cSRichard Henderson             case INDEX_op_br:
114151e3972cSRichard Henderson             case INDEX_op_brcond_i32:
114251e3972cSRichard Henderson             case INDEX_op_brcond_i64:
114351e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
1144bdfb460eSRichard Henderson                 col += qemu_log("%s$L%d", k ? "," : "", arg_label(args[k])->id);
114551e3972cSRichard Henderson                 i++, k++;
114651e3972cSRichard Henderson                 break;
114751e3972cSRichard Henderson             default:
114851e3972cSRichard Henderson                 break;
1149eeacee4dSBlue Swirl             }
115051e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
1151bdfb460eSRichard Henderson                 col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", args[k]);
1152bdfb460eSRichard Henderson             }
1153bdfb460eSRichard Henderson         }
1154bdfb460eSRichard Henderson         if (op->life) {
1155bdfb460eSRichard Henderson             unsigned life = op->life;
1156bdfb460eSRichard Henderson 
1157bdfb460eSRichard Henderson             for (; col < 48; ++col) {
1158bdfb460eSRichard Henderson                 putc(' ', qemu_logfile);
1159bdfb460eSRichard Henderson             }
1160bdfb460eSRichard Henderson 
1161bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
1162bdfb460eSRichard Henderson                 qemu_log("  sync:");
1163bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
1164bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
1165bdfb460eSRichard Henderson                         qemu_log(" %d", i);
1166bdfb460eSRichard Henderson                     }
1167bdfb460eSRichard Henderson                 }
1168bdfb460eSRichard Henderson             }
1169bdfb460eSRichard Henderson             life /= DEAD_ARG;
1170bdfb460eSRichard Henderson             if (life) {
1171bdfb460eSRichard Henderson                 qemu_log("  dead:");
1172bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
1173bdfb460eSRichard Henderson                     if (life & 1) {
1174bdfb460eSRichard Henderson                         qemu_log(" %d", i);
1175bdfb460eSRichard Henderson                     }
1176bdfb460eSRichard Henderson                 }
1177c896fe29Sbellard             }
1178b03cce8eSbellard         }
1179eeacee4dSBlue Swirl         qemu_log("\n");
1180c896fe29Sbellard     }
1181c896fe29Sbellard }
1182c896fe29Sbellard 
1183c896fe29Sbellard /* we give more priority to constraints with less registers */
1184c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
1185c896fe29Sbellard {
1186c896fe29Sbellard     const TCGArgConstraint *arg_ct;
1187c896fe29Sbellard 
1188c896fe29Sbellard     int i, n;
1189c896fe29Sbellard     arg_ct = &def->args_ct[k];
1190c896fe29Sbellard     if (arg_ct->ct & TCG_CT_ALIAS) {
1191c896fe29Sbellard         /* an alias is equivalent to a single register */
1192c896fe29Sbellard         n = 1;
1193c896fe29Sbellard     } else {
1194c896fe29Sbellard         if (!(arg_ct->ct & TCG_CT_REG))
1195c896fe29Sbellard             return 0;
1196c896fe29Sbellard         n = 0;
1197c896fe29Sbellard         for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
1198c896fe29Sbellard             if (tcg_regset_test_reg(arg_ct->u.regs, i))
1199c896fe29Sbellard                 n++;
1200c896fe29Sbellard         }
1201c896fe29Sbellard     }
1202c896fe29Sbellard     return TCG_TARGET_NB_REGS - n + 1;
1203c896fe29Sbellard }
1204c896fe29Sbellard 
1205c896fe29Sbellard /* sort from highest priority to lowest */
1206c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
1207c896fe29Sbellard {
1208c896fe29Sbellard     int i, j, p1, p2, tmp;
1209c896fe29Sbellard 
1210c896fe29Sbellard     for(i = 0; i < n; i++)
1211c896fe29Sbellard         def->sorted_args[start + i] = start + i;
1212c896fe29Sbellard     if (n <= 1)
1213c896fe29Sbellard         return;
1214c896fe29Sbellard     for(i = 0; i < n - 1; i++) {
1215c896fe29Sbellard         for(j = i + 1; j < n; j++) {
1216c896fe29Sbellard             p1 = get_constraint_priority(def, def->sorted_args[start + i]);
1217c896fe29Sbellard             p2 = get_constraint_priority(def, def->sorted_args[start + j]);
1218c896fe29Sbellard             if (p1 < p2) {
1219c896fe29Sbellard                 tmp = def->sorted_args[start + i];
1220c896fe29Sbellard                 def->sorted_args[start + i] = def->sorted_args[start + j];
1221c896fe29Sbellard                 def->sorted_args[start + j] = tmp;
1222c896fe29Sbellard             }
1223c896fe29Sbellard         }
1224c896fe29Sbellard     }
1225c896fe29Sbellard }
1226c896fe29Sbellard 
1227*f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
1228c896fe29Sbellard {
1229a9751609SRichard Henderson     TCGOpcode op;
1230c896fe29Sbellard 
1231*f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
1232*f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
1233*f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
1234*f69d277eSRichard Henderson         int i, nb_args, ok;
1235*f69d277eSRichard Henderson 
1236*f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
1237*f69d277eSRichard Henderson             continue;
1238*f69d277eSRichard Henderson         }
1239*f69d277eSRichard Henderson 
1240c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
1241*f69d277eSRichard Henderson         if (nb_args == 0) {
1242*f69d277eSRichard Henderson             continue;
1243*f69d277eSRichard Henderson         }
1244*f69d277eSRichard Henderson 
1245*f69d277eSRichard Henderson         tdefs = tcg_target_op_def(op);
1246*f69d277eSRichard Henderson         /* Missing TCGTargetOpDef entry. */
1247*f69d277eSRichard Henderson         tcg_debug_assert(tdefs != NULL);
1248*f69d277eSRichard Henderson 
1249c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
1250*f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
1251*f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
1252eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
1253*f69d277eSRichard Henderson 
1254c896fe29Sbellard             tcg_regset_clear(def->args_ct[i].u.regs);
1255c896fe29Sbellard             def->args_ct[i].ct = 0;
1256c896fe29Sbellard             if (ct_str[0] >= '0' && ct_str[0] <= '9') {
1257c896fe29Sbellard                 int oarg;
1258c896fe29Sbellard                 oarg = ct_str[0] - '0';
1259eabb7b91SAurelien Jarno                 tcg_debug_assert(oarg < def->nb_oargs);
1260eabb7b91SAurelien Jarno                 tcg_debug_assert(def->args_ct[oarg].ct & TCG_CT_REG);
1261c896fe29Sbellard                 /* TCG_CT_ALIAS is for the output arguments. The input
12625ff9d6a4Sbellard                    argument is tagged with TCG_CT_IALIAS. */
1263c896fe29Sbellard                 def->args_ct[i] = def->args_ct[oarg];
12645ff9d6a4Sbellard                 def->args_ct[oarg].ct = TCG_CT_ALIAS;
12655ff9d6a4Sbellard                 def->args_ct[oarg].alias_index = i;
1266c896fe29Sbellard                 def->args_ct[i].ct |= TCG_CT_IALIAS;
12675ff9d6a4Sbellard                 def->args_ct[i].alias_index = oarg;
1268c896fe29Sbellard             } else {
1269c896fe29Sbellard                 for(;;) {
1270c896fe29Sbellard                     if (*ct_str == '\0')
1271c896fe29Sbellard                         break;
1272c896fe29Sbellard                     switch(*ct_str) {
127382790a87SRichard Henderson                     case '&':
127482790a87SRichard Henderson                         def->args_ct[i].ct |= TCG_CT_NEWREG;
127582790a87SRichard Henderson                         ct_str++;
127682790a87SRichard Henderson                         break;
1277c896fe29Sbellard                     case 'i':
1278c896fe29Sbellard                         def->args_ct[i].ct |= TCG_CT_CONST;
1279c896fe29Sbellard                         ct_str++;
1280c896fe29Sbellard                         break;
1281c896fe29Sbellard                     default:
1282*f69d277eSRichard Henderson                         ok = target_parse_constraint(&def->args_ct[i], &ct_str);
1283*f69d277eSRichard Henderson                         /* Typo in TCGTargetOpDef constraint. */
1284*f69d277eSRichard Henderson                         tcg_debug_assert(ok == 0);
1285c896fe29Sbellard                     }
1286c896fe29Sbellard                 }
1287c896fe29Sbellard             }
1288c896fe29Sbellard         }
1289c896fe29Sbellard 
1290c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
1291eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
1292c68aaa18SStefan Weil 
1293c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
1294c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
1295c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
1296c896fe29Sbellard     }
1297c896fe29Sbellard }
1298c896fe29Sbellard 
12990c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
13000c627cdcSRichard Henderson {
13010c627cdcSRichard Henderson     int next = op->next;
13020c627cdcSRichard Henderson     int prev = op->prev;
13030c627cdcSRichard Henderson 
1304dcb8e758SRichard Henderson     /* We should never attempt to remove the list terminator.  */
1305dcb8e758SRichard Henderson     tcg_debug_assert(op != &s->gen_op_buf[0]);
13060c627cdcSRichard Henderson 
1307dcb8e758SRichard Henderson     s->gen_op_buf[next].prev = prev;
1308dcb8e758SRichard Henderson     s->gen_op_buf[prev].next = next;
1309dcb8e758SRichard Henderson 
1310dcb8e758SRichard Henderson     memset(op, 0, sizeof(*op));
13110c627cdcSRichard Henderson 
13120c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
13130c627cdcSRichard Henderson     s->del_op_count++;
13140c627cdcSRichard Henderson #endif
13150c627cdcSRichard Henderson }
13160c627cdcSRichard Henderson 
13175a18407fSRichard Henderson TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op,
13185a18407fSRichard Henderson                             TCGOpcode opc, int nargs)
13195a18407fSRichard Henderson {
13205a18407fSRichard Henderson     int oi = s->gen_next_op_idx;
13215a18407fSRichard Henderson     int pi = s->gen_next_parm_idx;
13225a18407fSRichard Henderson     int prev = old_op->prev;
13235a18407fSRichard Henderson     int next = old_op - s->gen_op_buf;
13245a18407fSRichard Henderson     TCGOp *new_op;
13255a18407fSRichard Henderson 
13265a18407fSRichard Henderson     tcg_debug_assert(oi < OPC_BUF_SIZE);
13275a18407fSRichard Henderson     tcg_debug_assert(pi + nargs <= OPPARAM_BUF_SIZE);
13285a18407fSRichard Henderson     s->gen_next_op_idx = oi + 1;
13295a18407fSRichard Henderson     s->gen_next_parm_idx = pi + nargs;
13305a18407fSRichard Henderson 
13315a18407fSRichard Henderson     new_op = &s->gen_op_buf[oi];
13325a18407fSRichard Henderson     *new_op = (TCGOp){
13335a18407fSRichard Henderson         .opc = opc,
13345a18407fSRichard Henderson         .args = pi,
13355a18407fSRichard Henderson         .prev = prev,
13365a18407fSRichard Henderson         .next = next
13375a18407fSRichard Henderson     };
13385a18407fSRichard Henderson     s->gen_op_buf[prev].next = oi;
13395a18407fSRichard Henderson     old_op->prev = oi;
13405a18407fSRichard Henderson 
13415a18407fSRichard Henderson     return new_op;
13425a18407fSRichard Henderson }
13435a18407fSRichard Henderson 
13445a18407fSRichard Henderson TCGOp *tcg_op_insert_after(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 - s->gen_op_buf;
13505a18407fSRichard Henderson     int next = old_op->next;
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[next].prev = oi;
13665a18407fSRichard Henderson     old_op->next = oi;
13675a18407fSRichard Henderson 
13685a18407fSRichard Henderson     return new_op;
13695a18407fSRichard Henderson }
13705a18407fSRichard Henderson 
1371c70fbf0aSRichard Henderson #define TS_DEAD  1
1372c70fbf0aSRichard Henderson #define TS_MEM   2
1373c70fbf0aSRichard Henderson 
13745a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
13755a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
13765a18407fSRichard Henderson 
13779c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
13789c43b68dSAurelien Jarno    should be in memory. */
1379c70fbf0aSRichard Henderson static inline void tcg_la_func_end(TCGContext *s, uint8_t *temp_state)
1380c896fe29Sbellard {
1381c70fbf0aSRichard Henderson     memset(temp_state, TS_DEAD | TS_MEM, s->nb_globals);
1382c70fbf0aSRichard Henderson     memset(temp_state + s->nb_globals, TS_DEAD, s->nb_temps - s->nb_globals);
1383c896fe29Sbellard }
1384c896fe29Sbellard 
13859c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
13869c43b68dSAurelien Jarno    and local temps should be in memory. */
1387c70fbf0aSRichard Henderson static inline void tcg_la_bb_end(TCGContext *s, uint8_t *temp_state)
1388641d5fbeSbellard {
1389c70fbf0aSRichard Henderson     int i, n;
1390641d5fbeSbellard 
1391c70fbf0aSRichard Henderson     tcg_la_func_end(s, temp_state);
1392c70fbf0aSRichard Henderson     for (i = s->nb_globals, n = s->nb_temps; i < n; i++) {
1393c70fbf0aSRichard Henderson         if (s->temps[i].temp_local) {
1394c70fbf0aSRichard Henderson             temp_state[i] |= TS_MEM;
1395c70fbf0aSRichard Henderson         }
1396641d5fbeSbellard     }
1397641d5fbeSbellard }
1398641d5fbeSbellard 
1399a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
1400c896fe29Sbellard    given input arguments is dead. Instructions updating dead
1401c896fe29Sbellard    temporaries are removed. */
14025a18407fSRichard Henderson static void liveness_pass_1(TCGContext *s, uint8_t *temp_state)
1403c896fe29Sbellard {
1404c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
14055a18407fSRichard Henderson     int oi, oi_prev;
1406c896fe29Sbellard 
1407c70fbf0aSRichard Henderson     tcg_la_func_end(s, temp_state);
1408c896fe29Sbellard 
1409dcb8e758SRichard Henderson     for (oi = s->gen_op_buf[0].prev; oi != 0; oi = oi_prev) {
1410c45cb8bbSRichard Henderson         int i, nb_iargs, nb_oargs;
1411c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
1412c45cb8bbSRichard Henderson         bool have_opc_new2;
1413a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
1414c45cb8bbSRichard Henderson         TCGArg arg;
1415c45cb8bbSRichard Henderson 
1416c45cb8bbSRichard Henderson         TCGOp * const op = &s->gen_op_buf[oi];
1417c45cb8bbSRichard Henderson         TCGArg * const args = &s->gen_opparam_buf[op->args];
1418c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
1419c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
1420c45cb8bbSRichard Henderson 
1421c45cb8bbSRichard Henderson         oi_prev = op->prev;
1422c45cb8bbSRichard Henderson 
1423c45cb8bbSRichard Henderson         switch (opc) {
1424c896fe29Sbellard         case INDEX_op_call:
1425c6e113f5Sbellard             {
1426c6e113f5Sbellard                 int call_flags;
1427c6e113f5Sbellard 
1428c45cb8bbSRichard Henderson                 nb_oargs = op->callo;
1429c45cb8bbSRichard Henderson                 nb_iargs = op->calli;
1430cf066674SRichard Henderson                 call_flags = args[nb_oargs + nb_iargs + 1];
1431c6e113f5Sbellard 
1432c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
143378505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
1434c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
1435c6e113f5Sbellard                         arg = args[i];
1436c70fbf0aSRichard Henderson                         if (temp_state[arg] != TS_DEAD) {
1437c6e113f5Sbellard                             goto do_not_remove_call;
1438c6e113f5Sbellard                         }
14399c43b68dSAurelien Jarno                     }
1440c45cb8bbSRichard Henderson                     goto do_remove;
1441c6e113f5Sbellard                 } else {
1442c6e113f5Sbellard                 do_not_remove_call:
1443c896fe29Sbellard 
1444c896fe29Sbellard                     /* output args are dead */
1445c896fe29Sbellard                     for (i = 0; i < nb_oargs; i++) {
1446c896fe29Sbellard                         arg = args[i];
1447c70fbf0aSRichard Henderson                         if (temp_state[arg] & TS_DEAD) {
1448a1b3c48dSRichard Henderson                             arg_life |= DEAD_ARG << i;
14496b64b624SAurelien Jarno                         }
1450c70fbf0aSRichard Henderson                         if (temp_state[arg] & TS_MEM) {
1451a1b3c48dSRichard Henderson                             arg_life |= SYNC_ARG << i;
14529c43b68dSAurelien Jarno                         }
1453c70fbf0aSRichard Henderson                         temp_state[arg] = TS_DEAD;
1454c896fe29Sbellard                     }
1455c896fe29Sbellard 
145678505279SAurelien Jarno                     if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
145778505279SAurelien Jarno                                         TCG_CALL_NO_READ_GLOBALS))) {
14589c43b68dSAurelien Jarno                         /* globals should go back to memory */
1459c70fbf0aSRichard Henderson                         memset(temp_state, TS_DEAD | TS_MEM, nb_globals);
1460c70fbf0aSRichard Henderson                     } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
1461c70fbf0aSRichard Henderson                         /* globals should be synced to memory */
1462c70fbf0aSRichard Henderson                         for (i = 0; i < nb_globals; i++) {
1463c70fbf0aSRichard Henderson                             temp_state[i] |= TS_MEM;
1464c70fbf0aSRichard Henderson                         }
1465b9c18f56Saurel32                     }
1466c896fe29Sbellard 
1467c19f47bfSAurelien Jarno                     /* record arguments that die in this helper */
1468866cb6cbSAurelien Jarno                     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
1469866cb6cbSAurelien Jarno                         arg = args[i];
147039cf05d3Sbellard                         if (arg != TCG_CALL_DUMMY_ARG) {
1471c70fbf0aSRichard Henderson                             if (temp_state[arg] & TS_DEAD) {
1472a1b3c48dSRichard Henderson                                 arg_life |= DEAD_ARG << i;
1473c896fe29Sbellard                             }
1474c896fe29Sbellard                         }
147539cf05d3Sbellard                     }
147667cc32ebSVeres Lajos                     /* input arguments are live for preceding opcodes */
1477c70fbf0aSRichard Henderson                     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
1478c19f47bfSAurelien Jarno                         arg = args[i];
1479c70fbf0aSRichard Henderson                         if (arg != TCG_CALL_DUMMY_ARG) {
1480c70fbf0aSRichard Henderson                             temp_state[arg] &= ~TS_DEAD;
1481c70fbf0aSRichard Henderson                         }
1482c19f47bfSAurelien Jarno                     }
1483c6e113f5Sbellard                 }
1484c6e113f5Sbellard             }
1485c896fe29Sbellard             break;
1486765b842aSRichard Henderson         case INDEX_op_insn_start:
1487c896fe29Sbellard             break;
14885ff9d6a4Sbellard         case INDEX_op_discard:
14895ff9d6a4Sbellard             /* mark the temporary as dead */
1490c70fbf0aSRichard Henderson             temp_state[args[0]] = TS_DEAD;
14915ff9d6a4Sbellard             break;
14921305c451SRichard Henderson 
14931305c451SRichard Henderson         case INDEX_op_add2_i32:
1494c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
1495f1fae40cSRichard Henderson             goto do_addsub2;
14961305c451SRichard Henderson         case INDEX_op_sub2_i32:
1497c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
1498f1fae40cSRichard Henderson             goto do_addsub2;
1499f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
1500c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
1501f1fae40cSRichard Henderson             goto do_addsub2;
1502f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
1503c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
1504f1fae40cSRichard Henderson         do_addsub2:
15051305c451SRichard Henderson             nb_iargs = 4;
15061305c451SRichard Henderson             nb_oargs = 2;
15071305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
15081305c451SRichard Henderson                the low part.  The result can be optimized to a simple
15091305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
15101305c451SRichard Henderson                cpu mode is set to 32 bit.  */
1511c70fbf0aSRichard Henderson             if (temp_state[args[1]] == TS_DEAD) {
1512c70fbf0aSRichard Henderson                 if (temp_state[args[0]] == TS_DEAD) {
15131305c451SRichard Henderson                     goto do_remove;
15141305c451SRichard Henderson                 }
1515c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
1516c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
1517c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
15181305c451SRichard Henderson                 args[1] = args[2];
15191305c451SRichard Henderson                 args[2] = args[4];
15201305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
15211305c451SRichard Henderson                 nb_iargs = 2;
15221305c451SRichard Henderson                 nb_oargs = 1;
15231305c451SRichard Henderson             }
15241305c451SRichard Henderson             goto do_not_remove;
15251305c451SRichard Henderson 
15261414968aSRichard Henderson         case INDEX_op_mulu2_i32:
1527c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
1528c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
1529c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
153003271524SRichard Henderson             goto do_mul2;
1531f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
1532c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
1533c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
1534c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
1535f1fae40cSRichard Henderson             goto do_mul2;
1536f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
1537c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
1538c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
1539c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
154003271524SRichard Henderson             goto do_mul2;
1541f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
1542c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
1543c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
1544c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
154503271524SRichard Henderson             goto do_mul2;
1546f1fae40cSRichard Henderson         do_mul2:
15471414968aSRichard Henderson             nb_iargs = 2;
15481414968aSRichard Henderson             nb_oargs = 2;
1549c70fbf0aSRichard Henderson             if (temp_state[args[1]] == TS_DEAD) {
1550c70fbf0aSRichard Henderson                 if (temp_state[args[0]] == TS_DEAD) {
155103271524SRichard Henderson                     /* Both parts of the operation are dead.  */
15521414968aSRichard Henderson                     goto do_remove;
15531414968aSRichard Henderson                 }
155403271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
1555c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
15561414968aSRichard Henderson                 args[1] = args[2];
15571414968aSRichard Henderson                 args[2] = args[3];
1558c70fbf0aSRichard Henderson             } else if (temp_state[args[0]] == TS_DEAD && have_opc_new2) {
155903271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
1560c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
156103271524SRichard Henderson                 args[0] = args[1];
156203271524SRichard Henderson                 args[1] = args[2];
156303271524SRichard Henderson                 args[2] = args[3];
156403271524SRichard Henderson             } else {
156503271524SRichard Henderson                 goto do_not_remove;
156603271524SRichard Henderson             }
156703271524SRichard Henderson             /* Mark the single-word operation live.  */
15681414968aSRichard Henderson             nb_oargs = 1;
15691414968aSRichard Henderson             goto do_not_remove;
15701414968aSRichard Henderson 
1571c896fe29Sbellard         default:
15721305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1573c896fe29Sbellard             nb_iargs = def->nb_iargs;
1574c896fe29Sbellard             nb_oargs = def->nb_oargs;
1575c896fe29Sbellard 
1576c896fe29Sbellard             /* Test if the operation can be removed because all
15775ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
15785ff9d6a4Sbellard                implies side effects */
15795ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
1580c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
1581c70fbf0aSRichard Henderson                     if (temp_state[args[i]] != TS_DEAD) {
1582c896fe29Sbellard                         goto do_not_remove;
1583c896fe29Sbellard                     }
15849c43b68dSAurelien Jarno                 }
15851305c451SRichard Henderson             do_remove:
15860c627cdcSRichard Henderson                 tcg_op_remove(s, op);
1587c896fe29Sbellard             } else {
1588c896fe29Sbellard             do_not_remove:
1589c896fe29Sbellard                 /* output args are dead */
1590c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
1591c896fe29Sbellard                     arg = args[i];
1592c70fbf0aSRichard Henderson                     if (temp_state[arg] & TS_DEAD) {
1593a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
15946b64b624SAurelien Jarno                     }
1595c70fbf0aSRichard Henderson                     if (temp_state[arg] & TS_MEM) {
1596a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
15979c43b68dSAurelien Jarno                     }
1598c70fbf0aSRichard Henderson                     temp_state[arg] = TS_DEAD;
1599c896fe29Sbellard                 }
1600c896fe29Sbellard 
1601c896fe29Sbellard                 /* if end of basic block, update */
1602c896fe29Sbellard                 if (def->flags & TCG_OPF_BB_END) {
1603c70fbf0aSRichard Henderson                     tcg_la_bb_end(s, temp_state);
16043d5c5f87SAurelien Jarno                 } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
16053d5c5f87SAurelien Jarno                     /* globals should be synced to memory */
1606c70fbf0aSRichard Henderson                     for (i = 0; i < nb_globals; i++) {
1607c70fbf0aSRichard Henderson                         temp_state[i] |= TS_MEM;
1608c70fbf0aSRichard Henderson                     }
1609c896fe29Sbellard                 }
1610c896fe29Sbellard 
1611c19f47bfSAurelien Jarno                 /* record arguments that die in this opcode */
1612866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
1613866cb6cbSAurelien Jarno                     arg = args[i];
1614c70fbf0aSRichard Henderson                     if (temp_state[arg] & TS_DEAD) {
1615a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
1616c896fe29Sbellard                     }
1617c19f47bfSAurelien Jarno                 }
161867cc32ebSVeres Lajos                 /* input arguments are live for preceding opcodes */
1619c19f47bfSAurelien Jarno                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
1620c70fbf0aSRichard Henderson                     temp_state[args[i]] &= ~TS_DEAD;
1621c896fe29Sbellard                 }
1622c896fe29Sbellard             }
1623c896fe29Sbellard             break;
1624c896fe29Sbellard         }
1625bee158cbSRichard Henderson         op->life = arg_life;
1626c896fe29Sbellard     }
16271ff0a2c5SEvgeny Voevodin }
1628c896fe29Sbellard 
16295a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
16305a18407fSRichard Henderson static bool liveness_pass_2(TCGContext *s, uint8_t *temp_state)
16315a18407fSRichard Henderson {
16325a18407fSRichard Henderson     int nb_globals = s->nb_globals;
16335a18407fSRichard Henderson     int16_t *dir_temps;
16345a18407fSRichard Henderson     int i, oi, oi_next;
16355a18407fSRichard Henderson     bool changes = false;
16365a18407fSRichard Henderson 
16375a18407fSRichard Henderson     dir_temps = tcg_malloc(nb_globals * sizeof(int16_t));
16385a18407fSRichard Henderson     memset(dir_temps, 0, nb_globals * sizeof(int16_t));
16395a18407fSRichard Henderson 
16405a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
16415a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
16425a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
16435a18407fSRichard Henderson         if (its->indirect_reg) {
16445a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
16455a18407fSRichard Henderson             dts->type = its->type;
16465a18407fSRichard Henderson             dts->base_type = its->base_type;
16475a18407fSRichard Henderson             dir_temps[i] = temp_idx(s, dts);
16485a18407fSRichard Henderson         }
16495a18407fSRichard Henderson     }
16505a18407fSRichard Henderson 
16515a18407fSRichard Henderson     memset(temp_state, TS_DEAD, nb_globals);
16525a18407fSRichard Henderson 
16535a18407fSRichard Henderson     for (oi = s->gen_op_buf[0].next; oi != 0; oi = oi_next) {
16545a18407fSRichard Henderson         TCGOp *op = &s->gen_op_buf[oi];
16555a18407fSRichard Henderson         TCGArg *args = &s->gen_opparam_buf[op->args];
16565a18407fSRichard Henderson         TCGOpcode opc = op->opc;
16575a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
16585a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
16595a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
16605a18407fSRichard Henderson         TCGArg arg, dir;
16615a18407fSRichard Henderson 
16625a18407fSRichard Henderson         oi_next = op->next;
16635a18407fSRichard Henderson 
16645a18407fSRichard Henderson         if (opc == INDEX_op_call) {
16655a18407fSRichard Henderson             nb_oargs = op->callo;
16665a18407fSRichard Henderson             nb_iargs = op->calli;
16675a18407fSRichard Henderson             call_flags = args[nb_oargs + nb_iargs + 1];
16685a18407fSRichard Henderson         } else {
16695a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
16705a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
16715a18407fSRichard Henderson 
16725a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
16735a18407fSRichard Henderson             if (def->flags & TCG_OPF_BB_END) {
16745a18407fSRichard Henderson                 /* Like writing globals: save_globals */
16755a18407fSRichard Henderson                 call_flags = 0;
16765a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
16775a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
16785a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
16795a18407fSRichard Henderson             } else {
16805a18407fSRichard Henderson                 /* No effect on globals.  */
16815a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
16825a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
16835a18407fSRichard Henderson             }
16845a18407fSRichard Henderson         }
16855a18407fSRichard Henderson 
16865a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
16875a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
16885a18407fSRichard Henderson             arg = args[i];
16895a18407fSRichard Henderson             /* Note this unsigned test catches TCG_CALL_ARG_DUMMY too.  */
16905a18407fSRichard Henderson             if (arg < nb_globals) {
16915a18407fSRichard Henderson                 dir = dir_temps[arg];
16925a18407fSRichard Henderson                 if (dir != 0 && temp_state[arg] == TS_DEAD) {
16935a18407fSRichard Henderson                     TCGTemp *its = &s->temps[arg];
16945a18407fSRichard Henderson                     TCGOpcode lopc = (its->type == TCG_TYPE_I32
16955a18407fSRichard Henderson                                       ? INDEX_op_ld_i32
16965a18407fSRichard Henderson                                       : INDEX_op_ld_i64);
16975a18407fSRichard Henderson                     TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3);
16985a18407fSRichard Henderson                     TCGArg *largs = &s->gen_opparam_buf[lop->args];
16995a18407fSRichard Henderson 
17005a18407fSRichard Henderson                     largs[0] = dir;
17015a18407fSRichard Henderson                     largs[1] = temp_idx(s, its->mem_base);
17025a18407fSRichard Henderson                     largs[2] = its->mem_offset;
17035a18407fSRichard Henderson 
17045a18407fSRichard Henderson                     /* Loaded, but synced with memory.  */
17055a18407fSRichard Henderson                     temp_state[arg] = TS_MEM;
17065a18407fSRichard Henderson                 }
17075a18407fSRichard Henderson             }
17085a18407fSRichard Henderson         }
17095a18407fSRichard Henderson 
17105a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
17115a18407fSRichard Henderson            No action is required except keeping temp_state up to date
17125a18407fSRichard Henderson            so that we reload when needed.  */
17135a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
17145a18407fSRichard Henderson             arg = args[i];
17155a18407fSRichard Henderson             if (arg < nb_globals) {
17165a18407fSRichard Henderson                 dir = dir_temps[arg];
17175a18407fSRichard Henderson                 if (dir != 0) {
17185a18407fSRichard Henderson                     args[i] = dir;
17195a18407fSRichard Henderson                     changes = true;
17205a18407fSRichard Henderson                     if (IS_DEAD_ARG(i)) {
17215a18407fSRichard Henderson                         temp_state[arg] = TS_DEAD;
17225a18407fSRichard Henderson                     }
17235a18407fSRichard Henderson                 }
17245a18407fSRichard Henderson             }
17255a18407fSRichard Henderson         }
17265a18407fSRichard Henderson 
17275a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
17285a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
17295a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
17305a18407fSRichard Henderson             /* Nothing to do */
17315a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
17325a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
17335a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
17345a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
17355a18407fSRichard Henderson                 tcg_debug_assert(dir_temps[i] == 0
17365a18407fSRichard Henderson                                  || temp_state[i] != 0);
17375a18407fSRichard Henderson             }
17385a18407fSRichard Henderson         } else {
17395a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
17405a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
17415a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
17425a18407fSRichard Henderson                 tcg_debug_assert(dir_temps[i] == 0
17435a18407fSRichard Henderson                                  || temp_state[i] == TS_DEAD);
17445a18407fSRichard Henderson             }
17455a18407fSRichard Henderson         }
17465a18407fSRichard Henderson 
17475a18407fSRichard Henderson         /* Outputs become available.  */
17485a18407fSRichard Henderson         for (i = 0; i < nb_oargs; i++) {
17495a18407fSRichard Henderson             arg = args[i];
17505a18407fSRichard Henderson             if (arg >= nb_globals) {
17515a18407fSRichard Henderson                 continue;
17525a18407fSRichard Henderson             }
17535a18407fSRichard Henderson             dir = dir_temps[arg];
17545a18407fSRichard Henderson             if (dir == 0) {
17555a18407fSRichard Henderson                 continue;
17565a18407fSRichard Henderson             }
17575a18407fSRichard Henderson             args[i] = dir;
17585a18407fSRichard Henderson             changes = true;
17595a18407fSRichard Henderson 
17605a18407fSRichard Henderson             /* The output is now live and modified.  */
17615a18407fSRichard Henderson             temp_state[arg] = 0;
17625a18407fSRichard Henderson 
17635a18407fSRichard Henderson             /* Sync outputs upon their last write.  */
17645a18407fSRichard Henderson             if (NEED_SYNC_ARG(i)) {
17655a18407fSRichard Henderson                 TCGTemp *its = &s->temps[arg];
17665a18407fSRichard Henderson                 TCGOpcode sopc = (its->type == TCG_TYPE_I32
17675a18407fSRichard Henderson                                   ? INDEX_op_st_i32
17685a18407fSRichard Henderson                                   : INDEX_op_st_i64);
17695a18407fSRichard Henderson                 TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
17705a18407fSRichard Henderson                 TCGArg *sargs = &s->gen_opparam_buf[sop->args];
17715a18407fSRichard Henderson 
17725a18407fSRichard Henderson                 sargs[0] = dir;
17735a18407fSRichard Henderson                 sargs[1] = temp_idx(s, its->mem_base);
17745a18407fSRichard Henderson                 sargs[2] = its->mem_offset;
17755a18407fSRichard Henderson 
17765a18407fSRichard Henderson                 temp_state[arg] = TS_MEM;
17775a18407fSRichard Henderson             }
17785a18407fSRichard Henderson             /* Drop outputs that are dead.  */
17795a18407fSRichard Henderson             if (IS_DEAD_ARG(i)) {
17805a18407fSRichard Henderson                 temp_state[arg] = TS_DEAD;
17815a18407fSRichard Henderson             }
17825a18407fSRichard Henderson         }
17835a18407fSRichard Henderson     }
17845a18407fSRichard Henderson 
17855a18407fSRichard Henderson     return changes;
17865a18407fSRichard Henderson }
17875a18407fSRichard Henderson 
17888d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
1789c896fe29Sbellard static void dump_regs(TCGContext *s)
1790c896fe29Sbellard {
1791c896fe29Sbellard     TCGTemp *ts;
1792c896fe29Sbellard     int i;
1793c896fe29Sbellard     char buf[64];
1794c896fe29Sbellard 
1795c896fe29Sbellard     for(i = 0; i < s->nb_temps; i++) {
1796c896fe29Sbellard         ts = &s->temps[i];
1797ac56dd48Spbrook         printf("  %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i));
1798c896fe29Sbellard         switch(ts->val_type) {
1799c896fe29Sbellard         case TEMP_VAL_REG:
1800c896fe29Sbellard             printf("%s", tcg_target_reg_names[ts->reg]);
1801c896fe29Sbellard             break;
1802c896fe29Sbellard         case TEMP_VAL_MEM:
1803b3a62939SRichard Henderson             printf("%d(%s)", (int)ts->mem_offset,
1804b3a62939SRichard Henderson                    tcg_target_reg_names[ts->mem_base->reg]);
1805c896fe29Sbellard             break;
1806c896fe29Sbellard         case TEMP_VAL_CONST:
1807c896fe29Sbellard             printf("$0x%" TCG_PRIlx, ts->val);
1808c896fe29Sbellard             break;
1809c896fe29Sbellard         case TEMP_VAL_DEAD:
1810c896fe29Sbellard             printf("D");
1811c896fe29Sbellard             break;
1812c896fe29Sbellard         default:
1813c896fe29Sbellard             printf("???");
1814c896fe29Sbellard             break;
1815c896fe29Sbellard         }
1816c896fe29Sbellard         printf("\n");
1817c896fe29Sbellard     }
1818c896fe29Sbellard 
1819c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
1820f8b2f202SRichard Henderson         if (s->reg_to_temp[i] != NULL) {
1821c896fe29Sbellard             printf("%s: %s\n",
1822c896fe29Sbellard                    tcg_target_reg_names[i],
1823f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i]));
1824c896fe29Sbellard         }
1825c896fe29Sbellard     }
1826c896fe29Sbellard }
1827c896fe29Sbellard 
1828c896fe29Sbellard static void check_regs(TCGContext *s)
1829c896fe29Sbellard {
1830869938aeSRichard Henderson     int reg;
1831b6638662SRichard Henderson     int k;
1832c896fe29Sbellard     TCGTemp *ts;
1833c896fe29Sbellard     char buf[64];
1834c896fe29Sbellard 
1835c896fe29Sbellard     for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1836f8b2f202SRichard Henderson         ts = s->reg_to_temp[reg];
1837f8b2f202SRichard Henderson         if (ts != NULL) {
1838f8b2f202SRichard Henderson             if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) {
1839c896fe29Sbellard                 printf("Inconsistency for register %s:\n",
1840c896fe29Sbellard                        tcg_target_reg_names[reg]);
1841b03cce8eSbellard                 goto fail;
1842c896fe29Sbellard             }
1843c896fe29Sbellard         }
1844c896fe29Sbellard     }
1845c896fe29Sbellard     for (k = 0; k < s->nb_temps; k++) {
1846c896fe29Sbellard         ts = &s->temps[k];
1847f8b2f202SRichard Henderson         if (ts->val_type == TEMP_VAL_REG && !ts->fixed_reg
1848f8b2f202SRichard Henderson             && s->reg_to_temp[ts->reg] != ts) {
1849c896fe29Sbellard             printf("Inconsistency for temp %s:\n",
1850f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
1851b03cce8eSbellard         fail:
1852c896fe29Sbellard             printf("reg state:\n");
1853c896fe29Sbellard             dump_regs(s);
1854c896fe29Sbellard             tcg_abort();
1855c896fe29Sbellard         }
1856c896fe29Sbellard     }
1857c896fe29Sbellard }
1858c896fe29Sbellard #endif
1859c896fe29Sbellard 
1860c896fe29Sbellard static void temp_allocate_frame(TCGContext *s, int temp)
1861c896fe29Sbellard {
1862c896fe29Sbellard     TCGTemp *ts;
1863c896fe29Sbellard     ts = &s->temps[temp];
18649b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64)
18659b9c37c3SRichard Henderson     /* Sparc64 stack is accessed with offset of 2047 */
1866b591dc59SBlue Swirl     s->current_frame_offset = (s->current_frame_offset +
1867b591dc59SBlue Swirl                                (tcg_target_long)sizeof(tcg_target_long) - 1) &
1868b591dc59SBlue Swirl         ~(sizeof(tcg_target_long) - 1);
1869f44c9960SBlue Swirl #endif
1870b591dc59SBlue Swirl     if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
1871b591dc59SBlue Swirl         s->frame_end) {
18725ff9d6a4Sbellard         tcg_abort();
1873b591dc59SBlue Swirl     }
1874c896fe29Sbellard     ts->mem_offset = s->current_frame_offset;
1875b3a62939SRichard Henderson     ts->mem_base = s->frame_temp;
1876c896fe29Sbellard     ts->mem_allocated = 1;
1877e2c6d1b4SRichard Henderson     s->current_frame_offset += sizeof(tcg_target_long);
1878c896fe29Sbellard }
1879c896fe29Sbellard 
1880b3915dbbSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet);
1881b3915dbbSRichard Henderson 
188259d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
188359d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
188459d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
1885c896fe29Sbellard {
188659d7c14eSRichard Henderson     if (ts->fixed_reg) {
188759d7c14eSRichard Henderson         return;
188859d7c14eSRichard Henderson     }
188959d7c14eSRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
189059d7c14eSRichard Henderson         s->reg_to_temp[ts->reg] = NULL;
189159d7c14eSRichard Henderson     }
189259d7c14eSRichard Henderson     ts->val_type = (free_or_dead < 0
189359d7c14eSRichard Henderson                     || ts->temp_local
189459d7c14eSRichard Henderson                     || temp_idx(s, ts) < s->nb_globals
189559d7c14eSRichard Henderson                     ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
189659d7c14eSRichard Henderson }
1897c896fe29Sbellard 
189859d7c14eSRichard Henderson /* Mark a temporary as dead.  */
189959d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
190059d7c14eSRichard Henderson {
190159d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
190259d7c14eSRichard Henderson }
190359d7c14eSRichard Henderson 
190459d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
190559d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
190659d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
190759d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
190859d7c14eSRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts,
190959d7c14eSRichard Henderson                       TCGRegSet allocated_regs, int free_or_dead)
191059d7c14eSRichard Henderson {
191159d7c14eSRichard Henderson     if (ts->fixed_reg) {
191259d7c14eSRichard Henderson         return;
191359d7c14eSRichard Henderson     }
191459d7c14eSRichard Henderson     if (!ts->mem_coherent) {
19157f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
1916f8b2f202SRichard Henderson             temp_allocate_frame(s, temp_idx(s, ts));
191759d7c14eSRichard Henderson         }
191859d7c14eSRichard Henderson         switch (ts->val_type) {
191959d7c14eSRichard Henderson         case TEMP_VAL_CONST:
192059d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
192159d7c14eSRichard Henderson                require it later in a register, so attempt to store the
192259d7c14eSRichard Henderson                constant to memory directly.  */
192359d7c14eSRichard Henderson             if (free_or_dead
192459d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
192559d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
192659d7c14eSRichard Henderson                 break;
192759d7c14eSRichard Henderson             }
192859d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
192959d7c14eSRichard Henderson                       allocated_regs);
193059d7c14eSRichard Henderson             /* fallthrough */
193159d7c14eSRichard Henderson 
193259d7c14eSRichard Henderson         case TEMP_VAL_REG:
193359d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
193459d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
193559d7c14eSRichard Henderson             break;
193659d7c14eSRichard Henderson 
193759d7c14eSRichard Henderson         case TEMP_VAL_MEM:
193859d7c14eSRichard Henderson             break;
193959d7c14eSRichard Henderson 
194059d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
194159d7c14eSRichard Henderson         default:
194259d7c14eSRichard Henderson             tcg_abort();
1943c896fe29Sbellard         }
19447f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
19457f6ceedfSAurelien Jarno     }
194659d7c14eSRichard Henderson     if (free_or_dead) {
194759d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
194859d7c14eSRichard Henderson     }
194959d7c14eSRichard Henderson }
19507f6ceedfSAurelien Jarno 
19517f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
1952b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
19537f6ceedfSAurelien Jarno {
1954f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
1955f8b2f202SRichard Henderson     if (ts != NULL) {
195659d7c14eSRichard Henderson         temp_sync(s, ts, allocated_regs, -1);
1957c896fe29Sbellard     }
1958c896fe29Sbellard }
1959c896fe29Sbellard 
1960c896fe29Sbellard /* Allocate a register belonging to reg1 & ~reg2 */
1961b3915dbbSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet desired_regs,
196291478cefSRichard Henderson                             TCGRegSet allocated_regs, bool rev)
1963c896fe29Sbellard {
196491478cefSRichard Henderson     int i, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
196591478cefSRichard Henderson     const int *order;
1966b6638662SRichard Henderson     TCGReg reg;
1967c896fe29Sbellard     TCGRegSet reg_ct;
1968c896fe29Sbellard 
1969b3915dbbSRichard Henderson     tcg_regset_andnot(reg_ct, desired_regs, allocated_regs);
197091478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
1971c896fe29Sbellard 
1972c896fe29Sbellard     /* first try free registers */
197391478cefSRichard Henderson     for(i = 0; i < n; i++) {
197491478cefSRichard Henderson         reg = order[i];
1975f8b2f202SRichard Henderson         if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == NULL)
1976c896fe29Sbellard             return reg;
1977c896fe29Sbellard     }
1978c896fe29Sbellard 
1979c896fe29Sbellard     /* XXX: do better spill choice */
198091478cefSRichard Henderson     for(i = 0; i < n; i++) {
198191478cefSRichard Henderson         reg = order[i];
1982c896fe29Sbellard         if (tcg_regset_test_reg(reg_ct, reg)) {
1983b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
1984c896fe29Sbellard             return reg;
1985c896fe29Sbellard         }
1986c896fe29Sbellard     }
1987c896fe29Sbellard 
1988c896fe29Sbellard     tcg_abort();
1989c896fe29Sbellard }
1990c896fe29Sbellard 
199140ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
199240ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
199340ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
199440ae5c62SRichard Henderson                       TCGRegSet allocated_regs)
199540ae5c62SRichard Henderson {
199640ae5c62SRichard Henderson     TCGReg reg;
199740ae5c62SRichard Henderson 
199840ae5c62SRichard Henderson     switch (ts->val_type) {
199940ae5c62SRichard Henderson     case TEMP_VAL_REG:
200040ae5c62SRichard Henderson         return;
200140ae5c62SRichard Henderson     case TEMP_VAL_CONST:
200291478cefSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs, ts->indirect_base);
200340ae5c62SRichard Henderson         tcg_out_movi(s, ts->type, reg, ts->val);
200440ae5c62SRichard Henderson         ts->mem_coherent = 0;
200540ae5c62SRichard Henderson         break;
200640ae5c62SRichard Henderson     case TEMP_VAL_MEM:
200791478cefSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs, ts->indirect_base);
200840ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
200940ae5c62SRichard Henderson         ts->mem_coherent = 1;
201040ae5c62SRichard Henderson         break;
201140ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
201240ae5c62SRichard Henderson     default:
201340ae5c62SRichard Henderson         tcg_abort();
201440ae5c62SRichard Henderson     }
201540ae5c62SRichard Henderson     ts->reg = reg;
201640ae5c62SRichard Henderson     ts->val_type = TEMP_VAL_REG;
201740ae5c62SRichard Henderson     s->reg_to_temp[reg] = ts;
201840ae5c62SRichard Henderson }
201940ae5c62SRichard Henderson 
202059d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
2021e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
202259d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
20231ad80729SAurelien Jarno {
20242c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
2025eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
2026f8bf00f1SRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg);
20271ad80729SAurelien Jarno }
20281ad80729SAurelien Jarno 
20299814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
2030641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
2031641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
2032641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
2033641d5fbeSbellard {
2034641d5fbeSbellard     int i;
2035641d5fbeSbellard 
2036641d5fbeSbellard     for (i = 0; i < s->nb_globals; i++) {
2037b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
2038641d5fbeSbellard     }
2039e5097dc8Sbellard }
2040e5097dc8Sbellard 
20413d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
20423d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
20433d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
20443d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
20453d5c5f87SAurelien Jarno {
20463d5c5f87SAurelien Jarno     int i;
20473d5c5f87SAurelien Jarno 
20483d5c5f87SAurelien Jarno     for (i = 0; i < s->nb_globals; i++) {
204912b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
205012b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
205112b9b11aSRichard Henderson                          || ts->fixed_reg
205212b9b11aSRichard Henderson                          || ts->mem_coherent);
20533d5c5f87SAurelien Jarno     }
20543d5c5f87SAurelien Jarno }
20553d5c5f87SAurelien Jarno 
2056e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
2057e8996ee0Sbellard    all globals are stored at their canonical location. */
2058e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
2059e5097dc8Sbellard {
2060e5097dc8Sbellard     int i;
2061e5097dc8Sbellard 
2062c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
2063b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
2064641d5fbeSbellard         if (ts->temp_local) {
2065b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
2066641d5fbeSbellard         } else {
20672c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
2068eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
2069eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
2070c896fe29Sbellard         }
2071641d5fbeSbellard     }
2072e8996ee0Sbellard 
2073e8996ee0Sbellard     save_globals(s, allocated_regs);
2074c896fe29Sbellard }
2075c896fe29Sbellard 
20760fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
20770fe4fca4SPaolo Bonzini                                   tcg_target_ulong val, TCGLifeData arg_life)
2078e8996ee0Sbellard {
2079e8996ee0Sbellard     if (ots->fixed_reg) {
208059d7c14eSRichard Henderson         /* For fixed registers, we do not do any constant propagation.  */
2081e8996ee0Sbellard         tcg_out_movi(s, ots->type, ots->reg, val);
208259d7c14eSRichard Henderson         return;
208359d7c14eSRichard Henderson     }
208459d7c14eSRichard Henderson 
208559d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
2086f8b2f202SRichard Henderson     if (ots->val_type == TEMP_VAL_REG) {
2087f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = NULL;
2088f8b2f202SRichard Henderson     }
2089e8996ee0Sbellard     ots->val_type = TEMP_VAL_CONST;
2090e8996ee0Sbellard     ots->val = val;
209159d7c14eSRichard Henderson     ots->mem_coherent = 0;
2092ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
209359d7c14eSRichard Henderson         temp_sync(s, ots, s->reserved_regs, IS_DEAD_ARG(0));
209459d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
2095f8bf00f1SRichard Henderson         temp_dead(s, ots);
20964c4e1ab2SAurelien Jarno     }
2097e8996ee0Sbellard }
2098e8996ee0Sbellard 
20990fe4fca4SPaolo Bonzini static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args,
21000fe4fca4SPaolo Bonzini                                TCGLifeData arg_life)
21010fe4fca4SPaolo Bonzini {
21020fe4fca4SPaolo Bonzini     TCGTemp *ots = &s->temps[args[0]];
21030fe4fca4SPaolo Bonzini     tcg_target_ulong val = args[1];
21040fe4fca4SPaolo Bonzini 
21050fe4fca4SPaolo Bonzini     tcg_reg_alloc_do_movi(s, ots, val, arg_life);
21060fe4fca4SPaolo Bonzini }
21070fe4fca4SPaolo Bonzini 
2108c896fe29Sbellard static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
2109a1b3c48dSRichard Henderson                               const TCGArg *args, TCGLifeData arg_life)
2110c896fe29Sbellard {
2111c29c1d7eSAurelien Jarno     TCGRegSet allocated_regs;
2112c896fe29Sbellard     TCGTemp *ts, *ots;
2113450445d5SRichard Henderson     TCGType otype, itype;
2114c896fe29Sbellard 
2115c29c1d7eSAurelien Jarno     tcg_regset_set(allocated_regs, s->reserved_regs);
2116c896fe29Sbellard     ots = &s->temps[args[0]];
2117c896fe29Sbellard     ts = &s->temps[args[1]];
2118450445d5SRichard Henderson 
2119450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
2120450445d5SRichard Henderson     otype = ots->type;
2121450445d5SRichard Henderson     itype = ts->type;
2122c896fe29Sbellard 
21230fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
21240fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
21250fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
21260fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
21270fe4fca4SPaolo Bonzini             temp_dead(s, ts);
21280fe4fca4SPaolo Bonzini         }
21290fe4fca4SPaolo Bonzini         tcg_reg_alloc_do_movi(s, ots, val, arg_life);
21300fe4fca4SPaolo Bonzini         return;
21310fe4fca4SPaolo Bonzini     }
21320fe4fca4SPaolo Bonzini 
21330fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
21340fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
21350fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
21360fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
21370fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
213840ae5c62SRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype], allocated_regs);
2139c29c1d7eSAurelien Jarno     }
2140c29c1d7eSAurelien Jarno 
21410fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
2142c29c1d7eSAurelien Jarno     if (IS_DEAD_ARG(0) && !ots->fixed_reg) {
2143c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
2144c29c1d7eSAurelien Jarno            liveness analysis disabled). */
2145eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
2146c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
2147c29c1d7eSAurelien Jarno             temp_allocate_frame(s, args[0]);
2148c29c1d7eSAurelien Jarno         }
2149b3a62939SRichard Henderson         tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset);
2150c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
2151f8bf00f1SRichard Henderson             temp_dead(s, ts);
2152c29c1d7eSAurelien Jarno         }
2153f8bf00f1SRichard Henderson         temp_dead(s, ots);
2154e8996ee0Sbellard     } else {
2155c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1) && !ts->fixed_reg && !ots->fixed_reg) {
2156c29c1d7eSAurelien Jarno             /* the mov can be suppressed */
2157c29c1d7eSAurelien Jarno             if (ots->val_type == TEMP_VAL_REG) {
2158f8b2f202SRichard Henderson                 s->reg_to_temp[ots->reg] = NULL;
2159c896fe29Sbellard             }
2160c29c1d7eSAurelien Jarno             ots->reg = ts->reg;
2161f8bf00f1SRichard Henderson             temp_dead(s, ts);
2162c29c1d7eSAurelien Jarno         } else {
2163c29c1d7eSAurelien Jarno             if (ots->val_type != TEMP_VAL_REG) {
2164c29c1d7eSAurelien Jarno                 /* When allocating a new register, make sure to not spill the
2165c29c1d7eSAurelien Jarno                    input one. */
2166c29c1d7eSAurelien Jarno                 tcg_regset_set_reg(allocated_regs, ts->reg);
2167450445d5SRichard Henderson                 ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
216891478cefSRichard Henderson                                          allocated_regs, ots->indirect_base);
2169c29c1d7eSAurelien Jarno             }
2170450445d5SRichard Henderson             tcg_out_mov(s, otype, ots->reg, ts->reg);
2171c29c1d7eSAurelien Jarno         }
2172c896fe29Sbellard         ots->val_type = TEMP_VAL_REG;
2173c896fe29Sbellard         ots->mem_coherent = 0;
2174f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
2175ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(0)) {
217659d7c14eSRichard Henderson             temp_sync(s, ots, allocated_regs, 0);
2177c29c1d7eSAurelien Jarno         }
2178ec7a869dSAurelien Jarno     }
2179c896fe29Sbellard }
2180c896fe29Sbellard 
2181c896fe29Sbellard static void tcg_reg_alloc_op(TCGContext *s,
2182a9751609SRichard Henderson                              const TCGOpDef *def, TCGOpcode opc,
2183a1b3c48dSRichard Henderson                              const TCGArg *args, TCGLifeData arg_life)
2184c896fe29Sbellard {
218582790a87SRichard Henderson     TCGRegSet i_allocated_regs;
218682790a87SRichard Henderson     TCGRegSet o_allocated_regs;
2187b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
2188b6638662SRichard Henderson     TCGReg reg;
2189c896fe29Sbellard     TCGArg arg;
2190c896fe29Sbellard     const TCGArgConstraint *arg_ct;
2191c896fe29Sbellard     TCGTemp *ts;
2192c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
2193c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
2194c896fe29Sbellard 
2195c896fe29Sbellard     nb_oargs = def->nb_oargs;
2196c896fe29Sbellard     nb_iargs = def->nb_iargs;
2197c896fe29Sbellard 
2198c896fe29Sbellard     /* copy constants */
2199c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
2200c896fe29Sbellard            args + nb_oargs + nb_iargs,
2201c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
2202c896fe29Sbellard 
220382790a87SRichard Henderson     tcg_regset_set(i_allocated_regs, s->reserved_regs);
220482790a87SRichard Henderson     tcg_regset_set(o_allocated_regs, s->reserved_regs);
220582790a87SRichard Henderson 
2206c896fe29Sbellard     /* satisfy input constraints */
2207c896fe29Sbellard     for(k = 0; k < nb_iargs; k++) {
2208c896fe29Sbellard         i = def->sorted_args[nb_oargs + k];
2209c896fe29Sbellard         arg = args[i];
2210c896fe29Sbellard         arg_ct = &def->args_ct[i];
2211c896fe29Sbellard         ts = &s->temps[arg];
221240ae5c62SRichard Henderson 
221340ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
221440ae5c62SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct)) {
2215c896fe29Sbellard             /* constant is OK for instruction */
2216c896fe29Sbellard             const_args[i] = 1;
2217c896fe29Sbellard             new_args[i] = ts->val;
2218c896fe29Sbellard             goto iarg_end;
2219c896fe29Sbellard         }
222040ae5c62SRichard Henderson 
222182790a87SRichard Henderson         temp_load(s, ts, arg_ct->u.regs, i_allocated_regs);
222240ae5c62SRichard Henderson 
22235ff9d6a4Sbellard         if (arg_ct->ct & TCG_CT_IALIAS) {
22245ff9d6a4Sbellard             if (ts->fixed_reg) {
22255ff9d6a4Sbellard                 /* if fixed register, we must allocate a new register
22265ff9d6a4Sbellard                    if the alias is not the same register */
22275ff9d6a4Sbellard                 if (arg != args[arg_ct->alias_index])
22285ff9d6a4Sbellard                     goto allocate_in_reg;
22295ff9d6a4Sbellard             } else {
2230c896fe29Sbellard                 /* if the input is aliased to an output and if it is
2231c896fe29Sbellard                    not dead after the instruction, we must allocate
2232c896fe29Sbellard                    a new register and move it */
2233866cb6cbSAurelien Jarno                 if (!IS_DEAD_ARG(i)) {
2234c896fe29Sbellard                     goto allocate_in_reg;
2235c896fe29Sbellard                 }
22367e1df267SAurelien Jarno                 /* check if the current register has already been allocated
22377e1df267SAurelien Jarno                    for another input aliased to an output */
22387e1df267SAurelien Jarno                 int k2, i2;
22397e1df267SAurelien Jarno                 for (k2 = 0 ; k2 < k ; k2++) {
22407e1df267SAurelien Jarno                     i2 = def->sorted_args[nb_oargs + k2];
22417e1df267SAurelien Jarno                     if ((def->args_ct[i2].ct & TCG_CT_IALIAS) &&
22427e1df267SAurelien Jarno                         (new_args[i2] == ts->reg)) {
22437e1df267SAurelien Jarno                         goto allocate_in_reg;
22447e1df267SAurelien Jarno                     }
22457e1df267SAurelien Jarno                 }
22465ff9d6a4Sbellard             }
2247866cb6cbSAurelien Jarno         }
2248c896fe29Sbellard         reg = ts->reg;
2249c896fe29Sbellard         if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
2250c896fe29Sbellard             /* nothing to do : the constraint is satisfied */
2251c896fe29Sbellard         } else {
2252c896fe29Sbellard         allocate_in_reg:
2253c896fe29Sbellard             /* allocate a new register matching the constraint
2254c896fe29Sbellard                and move the temporary register into it */
225582790a87SRichard Henderson             reg = tcg_reg_alloc(s, arg_ct->u.regs, i_allocated_regs,
225691478cefSRichard Henderson                                 ts->indirect_base);
22573b6dac34SRichard Henderson             tcg_out_mov(s, ts->type, reg, ts->reg);
2258c896fe29Sbellard         }
2259c896fe29Sbellard         new_args[i] = reg;
2260c896fe29Sbellard         const_args[i] = 0;
226182790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
2262c896fe29Sbellard     iarg_end: ;
2263c896fe29Sbellard     }
2264c896fe29Sbellard 
2265c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
2266866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
2267866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
2268f8bf00f1SRichard Henderson             temp_dead(s, &s->temps[args[i]]);
2269c896fe29Sbellard         }
2270c896fe29Sbellard     }
2271c896fe29Sbellard 
2272a52ad07eSAurelien Jarno     if (def->flags & TCG_OPF_BB_END) {
227382790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
2274a52ad07eSAurelien Jarno     } else {
2275c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
2276b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
2277c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
2278c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
227982790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
2280c896fe29Sbellard                 }
2281c896fe29Sbellard             }
22823d5c5f87SAurelien Jarno         }
22833d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
22843d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
22853d5c5f87SAurelien Jarno                an exception. */
228682790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
2287c896fe29Sbellard         }
2288c896fe29Sbellard 
2289c896fe29Sbellard         /* satisfy the output constraints */
2290c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
2291c896fe29Sbellard             i = def->sorted_args[k];
2292c896fe29Sbellard             arg = args[i];
2293c896fe29Sbellard             arg_ct = &def->args_ct[i];
2294c896fe29Sbellard             ts = &s->temps[arg];
2295c896fe29Sbellard             if (arg_ct->ct & TCG_CT_ALIAS) {
22965ff9d6a4Sbellard                 reg = new_args[arg_ct->alias_index];
229782790a87SRichard Henderson             } else if (arg_ct->ct & TCG_CT_NEWREG) {
229882790a87SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->u.regs,
229982790a87SRichard Henderson                                     i_allocated_regs | o_allocated_regs,
230082790a87SRichard Henderson                                     ts->indirect_base);
2301c896fe29Sbellard             } else {
2302c896fe29Sbellard                 /* if fixed register, we try to use it */
2303c896fe29Sbellard                 reg = ts->reg;
2304c896fe29Sbellard                 if (ts->fixed_reg &&
2305c896fe29Sbellard                     tcg_regset_test_reg(arg_ct->u.regs, reg)) {
2306c896fe29Sbellard                     goto oarg_end;
2307c896fe29Sbellard                 }
230882790a87SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->u.regs, o_allocated_regs,
230991478cefSRichard Henderson                                     ts->indirect_base);
2310c896fe29Sbellard             }
231182790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
2312c896fe29Sbellard             /* if a fixed register is used, then a move will be done afterwards */
2313c896fe29Sbellard             if (!ts->fixed_reg) {
2314639368ddSAurelien Jarno                 if (ts->val_type == TEMP_VAL_REG) {
2315f8b2f202SRichard Henderson                     s->reg_to_temp[ts->reg] = NULL;
2316639368ddSAurelien Jarno                 }
2317c896fe29Sbellard                 ts->val_type = TEMP_VAL_REG;
2318c896fe29Sbellard                 ts->reg = reg;
2319c896fe29Sbellard                 /* temp value is modified, so the value kept in memory is
2320c896fe29Sbellard                    potentially not the same */
2321c896fe29Sbellard                 ts->mem_coherent = 0;
2322f8b2f202SRichard Henderson                 s->reg_to_temp[reg] = ts;
2323c896fe29Sbellard             }
2324c896fe29Sbellard         oarg_end:
2325c896fe29Sbellard             new_args[i] = reg;
2326c896fe29Sbellard         }
2327e8996ee0Sbellard     }
2328c896fe29Sbellard 
2329c896fe29Sbellard     /* emit instruction */
2330c896fe29Sbellard     tcg_out_op(s, opc, new_args, const_args);
2331c896fe29Sbellard 
2332c896fe29Sbellard     /* move the outputs in the correct register if needed */
2333c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
2334c896fe29Sbellard         ts = &s->temps[args[i]];
2335c896fe29Sbellard         reg = new_args[i];
2336c896fe29Sbellard         if (ts->fixed_reg && ts->reg != reg) {
23373b6dac34SRichard Henderson             tcg_out_mov(s, ts->type, ts->reg, reg);
2338c896fe29Sbellard         }
2339ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
234082790a87SRichard Henderson             temp_sync(s, ts, o_allocated_regs, IS_DEAD_ARG(i));
234159d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
2342f8bf00f1SRichard Henderson             temp_dead(s, ts);
2343ec7a869dSAurelien Jarno         }
2344c896fe29Sbellard     }
2345c896fe29Sbellard }
2346c896fe29Sbellard 
2347b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP
2348b03cce8eSbellard #define STACK_DIR(x) (-(x))
2349b03cce8eSbellard #else
2350b03cce8eSbellard #define STACK_DIR(x) (x)
2351b03cce8eSbellard #endif
2352b03cce8eSbellard 
2353c45cb8bbSRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, int nb_oargs, int nb_iargs,
2354a1b3c48dSRichard Henderson                                const TCGArg * const args, TCGLifeData arg_life)
2355c896fe29Sbellard {
2356b6638662SRichard Henderson     int flags, nb_regs, i;
2357b6638662SRichard Henderson     TCGReg reg;
2358cf066674SRichard Henderson     TCGArg arg;
2359c896fe29Sbellard     TCGTemp *ts;
2360d3452f1fSRichard Henderson     intptr_t stack_offset;
2361d3452f1fSRichard Henderson     size_t call_stack_size;
2362cf066674SRichard Henderson     tcg_insn_unit *func_addr;
2363cf066674SRichard Henderson     int allocate_args;
2364c896fe29Sbellard     TCGRegSet allocated_regs;
2365c896fe29Sbellard 
2366cf066674SRichard Henderson     func_addr = (tcg_insn_unit *)(intptr_t)args[nb_oargs + nb_iargs];
2367cf066674SRichard Henderson     flags = args[nb_oargs + nb_iargs + 1];
2368c896fe29Sbellard 
23696e17d0c5SStefan Weil     nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
2370c45cb8bbSRichard Henderson     if (nb_regs > nb_iargs) {
2371c45cb8bbSRichard Henderson         nb_regs = nb_iargs;
2372cf066674SRichard Henderson     }
2373c896fe29Sbellard 
2374c896fe29Sbellard     /* assign stack slots first */
2375c45cb8bbSRichard Henderson     call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long);
2376c896fe29Sbellard     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
2377c896fe29Sbellard         ~(TCG_TARGET_STACK_ALIGN - 1);
2378b03cce8eSbellard     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
2379b03cce8eSbellard     if (allocate_args) {
2380345649c0SBlue Swirl         /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
2381345649c0SBlue Swirl            preallocate call stack */
2382345649c0SBlue Swirl         tcg_abort();
2383b03cce8eSbellard     }
238439cf05d3Sbellard 
238539cf05d3Sbellard     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
2386c45cb8bbSRichard Henderson     for(i = nb_regs; i < nb_iargs; i++) {
2387c896fe29Sbellard         arg = args[nb_oargs + i];
238839cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP
238939cf05d3Sbellard         stack_offset -= sizeof(tcg_target_long);
239039cf05d3Sbellard #endif
239139cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
2392c896fe29Sbellard             ts = &s->temps[arg];
239340ae5c62SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
239440ae5c62SRichard Henderson                       s->reserved_regs);
2395e4d5434cSblueswir1             tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
239639cf05d3Sbellard         }
239739cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP
239839cf05d3Sbellard         stack_offset += sizeof(tcg_target_long);
239939cf05d3Sbellard #endif
2400c896fe29Sbellard     }
2401c896fe29Sbellard 
2402c896fe29Sbellard     /* assign input registers */
2403c896fe29Sbellard     tcg_regset_set(allocated_regs, s->reserved_regs);
2404c896fe29Sbellard     for(i = 0; i < nb_regs; i++) {
2405c896fe29Sbellard         arg = args[nb_oargs + i];
240639cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
2407c896fe29Sbellard             ts = &s->temps[arg];
2408c896fe29Sbellard             reg = tcg_target_call_iarg_regs[i];
2409b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
241040ae5c62SRichard Henderson 
2411c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
2412c896fe29Sbellard                 if (ts->reg != reg) {
24133b6dac34SRichard Henderson                     tcg_out_mov(s, ts->type, reg, ts->reg);
2414c896fe29Sbellard                 }
2415c896fe29Sbellard             } else {
241640ae5c62SRichard Henderson                 TCGRegSet arg_set;
241740ae5c62SRichard Henderson 
241840ae5c62SRichard Henderson                 tcg_regset_clear(arg_set);
241940ae5c62SRichard Henderson                 tcg_regset_set_reg(arg_set, reg);
242040ae5c62SRichard Henderson                 temp_load(s, ts, arg_set, allocated_regs);
2421c896fe29Sbellard             }
242240ae5c62SRichard Henderson 
2423c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
2424c896fe29Sbellard         }
242539cf05d3Sbellard     }
2426c896fe29Sbellard 
2427c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
2428866cb6cbSAurelien Jarno     for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2429866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
2430f8bf00f1SRichard Henderson             temp_dead(s, &s->temps[args[i]]);
2431c896fe29Sbellard         }
2432c896fe29Sbellard     }
2433c896fe29Sbellard 
2434c896fe29Sbellard     /* clobber call registers */
2435c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
2436c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
2437b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
2438c896fe29Sbellard         }
2439c896fe29Sbellard     }
2440c896fe29Sbellard 
244178505279SAurelien Jarno     /* Save globals if they might be written by the helper, sync them if
244278505279SAurelien Jarno        they might be read. */
244378505279SAurelien Jarno     if (flags & TCG_CALL_NO_READ_GLOBALS) {
244478505279SAurelien Jarno         /* Nothing to do */
244578505279SAurelien Jarno     } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) {
244678505279SAurelien Jarno         sync_globals(s, allocated_regs);
244778505279SAurelien Jarno     } else {
2448e8996ee0Sbellard         save_globals(s, allocated_regs);
2449b9c18f56Saurel32     }
2450c896fe29Sbellard 
2451cf066674SRichard Henderson     tcg_out_call(s, func_addr);
2452c896fe29Sbellard 
2453c896fe29Sbellard     /* assign output registers and emit moves if needed */
2454c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
2455c896fe29Sbellard         arg = args[i];
2456c896fe29Sbellard         ts = &s->temps[arg];
2457c896fe29Sbellard         reg = tcg_target_call_oarg_regs[i];
2458eabb7b91SAurelien Jarno         tcg_debug_assert(s->reg_to_temp[reg] == NULL);
245934b1a49cSRichard Henderson 
2460c896fe29Sbellard         if (ts->fixed_reg) {
2461c896fe29Sbellard             if (ts->reg != reg) {
24623b6dac34SRichard Henderson                 tcg_out_mov(s, ts->type, ts->reg, reg);
2463c896fe29Sbellard             }
2464c896fe29Sbellard         } else {
2465639368ddSAurelien Jarno             if (ts->val_type == TEMP_VAL_REG) {
2466f8b2f202SRichard Henderson                 s->reg_to_temp[ts->reg] = NULL;
2467639368ddSAurelien Jarno             }
2468c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
2469c896fe29Sbellard             ts->reg = reg;
2470c896fe29Sbellard             ts->mem_coherent = 0;
2471f8b2f202SRichard Henderson             s->reg_to_temp[reg] = ts;
2472ec7a869dSAurelien Jarno             if (NEED_SYNC_ARG(i)) {
247359d7c14eSRichard Henderson                 temp_sync(s, ts, allocated_regs, IS_DEAD_ARG(i));
247459d7c14eSRichard Henderson             } else if (IS_DEAD_ARG(i)) {
2475f8bf00f1SRichard Henderson                 temp_dead(s, ts);
2476c896fe29Sbellard             }
2477c896fe29Sbellard         }
24788c11ad25SAurelien Jarno     }
2479c896fe29Sbellard }
2480c896fe29Sbellard 
2481c896fe29Sbellard #ifdef CONFIG_PROFILER
2482c896fe29Sbellard 
248354604f74Saurel32 static int64_t tcg_table_op_count[NB_OPS];
2484c896fe29Sbellard 
2485246ae24dSMax Filippov void tcg_dump_op_count(FILE *f, fprintf_function cpu_fprintf)
2486c896fe29Sbellard {
2487c896fe29Sbellard     int i;
2488d70724ceSzhanghailiang 
248915fc7daaSRichard Henderson     for (i = 0; i < NB_OPS; i++) {
2490246ae24dSMax Filippov         cpu_fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name,
2491246ae24dSMax Filippov                     tcg_table_op_count[i]);
2492c896fe29Sbellard     }
2493c896fe29Sbellard }
2494246ae24dSMax Filippov #else
2495246ae24dSMax Filippov void tcg_dump_op_count(FILE *f, fprintf_function cpu_fprintf)
2496246ae24dSMax Filippov {
2497246ae24dSMax Filippov     cpu_fprintf(f, "[TCG profiler not compiled]\n");
2498246ae24dSMax Filippov }
2499c896fe29Sbellard #endif
2500c896fe29Sbellard 
2501c896fe29Sbellard 
25025bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
2503c896fe29Sbellard {
2504fca8a500SRichard Henderson     int i, oi, oi_next, num_insns;
2505c896fe29Sbellard 
250604fe6400SRichard Henderson #ifdef CONFIG_PROFILER
250704fe6400SRichard Henderson     {
250804fe6400SRichard Henderson         int n;
250904fe6400SRichard Henderson 
2510dcb8e758SRichard Henderson         n = s->gen_op_buf[0].prev + 1;
251104fe6400SRichard Henderson         s->op_count += n;
251204fe6400SRichard Henderson         if (n > s->op_count_max) {
251304fe6400SRichard Henderson             s->op_count_max = n;
251404fe6400SRichard Henderson         }
251504fe6400SRichard Henderson 
251604fe6400SRichard Henderson         n = s->nb_temps;
251704fe6400SRichard Henderson         s->temp_count += n;
251804fe6400SRichard Henderson         if (n > s->temp_count_max) {
251904fe6400SRichard Henderson             s->temp_count_max = n;
252004fe6400SRichard Henderson         }
252104fe6400SRichard Henderson     }
252204fe6400SRichard Henderson #endif
252304fe6400SRichard Henderson 
2524c896fe29Sbellard #ifdef DEBUG_DISAS
2525d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
2526d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
25271ee73216SRichard Henderson         qemu_log_lock();
252893fcfe39Saliguori         qemu_log("OP:\n");
2529eeacee4dSBlue Swirl         tcg_dump_ops(s);
253093fcfe39Saliguori         qemu_log("\n");
25311ee73216SRichard Henderson         qemu_log_unlock();
2532c896fe29Sbellard     }
2533c896fe29Sbellard #endif
2534c896fe29Sbellard 
2535c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
2536c5cc28ffSAurelien Jarno     s->opt_time -= profile_getclock();
2537c5cc28ffSAurelien Jarno #endif
2538c5cc28ffSAurelien Jarno 
25398f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
2540c45cb8bbSRichard Henderson     tcg_optimize(s);
25418f2e8c07SKirill Batuzov #endif
25428f2e8c07SKirill Batuzov 
2543a23a9ec6Sbellard #ifdef CONFIG_PROFILER
2544c5cc28ffSAurelien Jarno     s->opt_time += profile_getclock();
2545a23a9ec6Sbellard     s->la_time -= profile_getclock();
2546a23a9ec6Sbellard #endif
2547c5cc28ffSAurelien Jarno 
25485a18407fSRichard Henderson     {
25495a18407fSRichard Henderson         uint8_t *temp_state = tcg_malloc(s->nb_temps + s->nb_indirects);
25505a18407fSRichard Henderson 
25515a18407fSRichard Henderson         liveness_pass_1(s, temp_state);
25525a18407fSRichard Henderson 
25535a18407fSRichard Henderson         if (s->nb_indirects > 0) {
25545a18407fSRichard Henderson #ifdef DEBUG_DISAS
25555a18407fSRichard Henderson             if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
25565a18407fSRichard Henderson                          && qemu_log_in_addr_range(tb->pc))) {
25571ee73216SRichard Henderson                 qemu_log_lock();
25585a18407fSRichard Henderson                 qemu_log("OP before indirect lowering:\n");
25595a18407fSRichard Henderson                 tcg_dump_ops(s);
25605a18407fSRichard Henderson                 qemu_log("\n");
25611ee73216SRichard Henderson                 qemu_log_unlock();
25625a18407fSRichard Henderson             }
25635a18407fSRichard Henderson #endif
25645a18407fSRichard Henderson             /* Replace indirect temps with direct temps.  */
25655a18407fSRichard Henderson             if (liveness_pass_2(s, temp_state)) {
25665a18407fSRichard Henderson                 /* If changes were made, re-run liveness.  */
25675a18407fSRichard Henderson                 liveness_pass_1(s, temp_state);
25685a18407fSRichard Henderson             }
25695a18407fSRichard Henderson         }
25705a18407fSRichard Henderson     }
2571c5cc28ffSAurelien Jarno 
2572a23a9ec6Sbellard #ifdef CONFIG_PROFILER
2573a23a9ec6Sbellard     s->la_time += profile_getclock();
2574a23a9ec6Sbellard #endif
2575c896fe29Sbellard 
2576c896fe29Sbellard #ifdef DEBUG_DISAS
2577d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
2578d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
25791ee73216SRichard Henderson         qemu_log_lock();
2580c5cc28ffSAurelien Jarno         qemu_log("OP after optimization and liveness analysis:\n");
2581eeacee4dSBlue Swirl         tcg_dump_ops(s);
258293fcfe39Saliguori         qemu_log("\n");
25831ee73216SRichard Henderson         qemu_log_unlock();
2584c896fe29Sbellard     }
2585c896fe29Sbellard #endif
2586c896fe29Sbellard 
2587c896fe29Sbellard     tcg_reg_alloc_start(s);
2588c896fe29Sbellard 
25895bd2ec3dSAlex Bennée     s->code_buf = tb->tc_ptr;
25905bd2ec3dSAlex Bennée     s->code_ptr = tb->tc_ptr;
2591c896fe29Sbellard 
25929ecefc84SRichard Henderson     tcg_out_tb_init(s);
25939ecefc84SRichard Henderson 
2594fca8a500SRichard Henderson     num_insns = -1;
2595dcb8e758SRichard Henderson     for (oi = s->gen_op_buf[0].next; oi != 0; oi = oi_next) {
2596c45cb8bbSRichard Henderson         TCGOp * const op = &s->gen_op_buf[oi];
2597c45cb8bbSRichard Henderson         TCGArg * const args = &s->gen_opparam_buf[op->args];
2598c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2599c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2600bee158cbSRichard Henderson         TCGLifeData arg_life = op->life;
2601b3db8758Sblueswir1 
2602c45cb8bbSRichard Henderson         oi_next = op->next;
2603c896fe29Sbellard #ifdef CONFIG_PROFILER
260454604f74Saurel32         tcg_table_op_count[opc]++;
2605c896fe29Sbellard #endif
2606c45cb8bbSRichard Henderson 
2607c896fe29Sbellard         switch (opc) {
2608c896fe29Sbellard         case INDEX_op_mov_i32:
2609c896fe29Sbellard         case INDEX_op_mov_i64:
2610a1b3c48dSRichard Henderson             tcg_reg_alloc_mov(s, def, args, arg_life);
2611c896fe29Sbellard             break;
2612e8996ee0Sbellard         case INDEX_op_movi_i32:
2613e8996ee0Sbellard         case INDEX_op_movi_i64:
2614a1b3c48dSRichard Henderson             tcg_reg_alloc_movi(s, args, arg_life);
2615e8996ee0Sbellard             break;
2616765b842aSRichard Henderson         case INDEX_op_insn_start:
2617fca8a500SRichard Henderson             if (num_insns >= 0) {
2618fca8a500SRichard Henderson                 s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
2619fca8a500SRichard Henderson             }
2620fca8a500SRichard Henderson             num_insns++;
2621bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
2622bad729e2SRichard Henderson                 target_ulong a;
2623bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
2624bad729e2SRichard Henderson                 a = ((target_ulong)args[i * 2 + 1] << 32) | args[i * 2];
2625bad729e2SRichard Henderson #else
2626bad729e2SRichard Henderson                 a = args[i];
2627bad729e2SRichard Henderson #endif
2628fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
2629bad729e2SRichard Henderson             }
2630c896fe29Sbellard             break;
26315ff9d6a4Sbellard         case INDEX_op_discard:
2632f8bf00f1SRichard Henderson             temp_dead(s, &s->temps[args[0]]);
26335ff9d6a4Sbellard             break;
2634c896fe29Sbellard         case INDEX_op_set_label:
2635e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
2636bec16311SRichard Henderson             tcg_out_label(s, arg_label(args[0]), s->code_ptr);
2637c896fe29Sbellard             break;
2638c896fe29Sbellard         case INDEX_op_call:
2639a1b3c48dSRichard Henderson             tcg_reg_alloc_call(s, op->callo, op->calli, args, arg_life);
2640c45cb8bbSRichard Henderson             break;
2641c896fe29Sbellard         default:
264225c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
264325c4d9ccSRichard Henderson             if (def->flags & TCG_OPF_NOT_PRESENT) {
264425c4d9ccSRichard Henderson                 tcg_abort();
264525c4d9ccSRichard Henderson             }
2646c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
2647c896fe29Sbellard                faster to have specialized register allocator functions for
2648c896fe29Sbellard                some common argument patterns */
2649a1b3c48dSRichard Henderson             tcg_reg_alloc_op(s, def, opc, args, arg_life);
2650c896fe29Sbellard             break;
2651c896fe29Sbellard         }
26528d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
2653c896fe29Sbellard         check_regs(s);
2654c896fe29Sbellard #endif
2655b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
2656b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
2657b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
2658b125f9dcSRichard Henderson            generating code without having to check during generation.  */
2659644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
2660b125f9dcSRichard Henderson             return -1;
2661b125f9dcSRichard Henderson         }
2662c896fe29Sbellard     }
2663fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
2664fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
2665c45cb8bbSRichard Henderson 
2666b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
266723dceda6SRichard Henderson     if (!tcg_out_tb_finalize(s)) {
266823dceda6SRichard Henderson         return -1;
266923dceda6SRichard Henderson     }
2670c896fe29Sbellard 
2671c896fe29Sbellard     /* flush instruction cache */
26721813e175SRichard Henderson     flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr);
26732aeabc08SStefan Weil 
26741813e175SRichard Henderson     return tcg_current_code_size(s);
2675c896fe29Sbellard }
2676c896fe29Sbellard 
2677a23a9ec6Sbellard #ifdef CONFIG_PROFILER
2678405cf9ffSStefan Weil void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
2679a23a9ec6Sbellard {
2680a23a9ec6Sbellard     TCGContext *s = &tcg_ctx;
2681fca8a500SRichard Henderson     int64_t tb_count = s->tb_count;
2682fca8a500SRichard Henderson     int64_t tb_div_count = tb_count ? tb_count : 1;
2683fca8a500SRichard Henderson     int64_t tot = s->interm_time + s->code_time;
2684a23a9ec6Sbellard 
2685a23a9ec6Sbellard     cpu_fprintf(f, "JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
2686a23a9ec6Sbellard                 tot, tot / 2.4e9);
2687a23a9ec6Sbellard     cpu_fprintf(f, "translated TBs      %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n",
2688fca8a500SRichard Henderson                 tb_count, s->tb_count1 - tb_count,
2689fca8a500SRichard Henderson                 (double)(s->tb_count1 - s->tb_count)
2690fca8a500SRichard Henderson                 / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
2691a23a9ec6Sbellard     cpu_fprintf(f, "avg ops/TB          %0.1f max=%d\n",
2692fca8a500SRichard Henderson                 (double)s->op_count / tb_div_count, s->op_count_max);
2693a23a9ec6Sbellard     cpu_fprintf(f, "deleted ops/TB      %0.2f\n",
2694fca8a500SRichard Henderson                 (double)s->del_op_count / tb_div_count);
2695a23a9ec6Sbellard     cpu_fprintf(f, "avg temps/TB        %0.2f max=%d\n",
2696fca8a500SRichard Henderson                 (double)s->temp_count / tb_div_count, s->temp_count_max);
2697fca8a500SRichard Henderson     cpu_fprintf(f, "avg host code/TB    %0.1f\n",
2698fca8a500SRichard Henderson                 (double)s->code_out_len / tb_div_count);
2699fca8a500SRichard Henderson     cpu_fprintf(f, "avg search data/TB  %0.1f\n",
2700fca8a500SRichard Henderson                 (double)s->search_out_len / tb_div_count);
2701a23a9ec6Sbellard 
2702a23a9ec6Sbellard     cpu_fprintf(f, "cycles/op           %0.1f\n",
2703a23a9ec6Sbellard                 s->op_count ? (double)tot / s->op_count : 0);
2704a23a9ec6Sbellard     cpu_fprintf(f, "cycles/in byte      %0.1f\n",
2705a23a9ec6Sbellard                 s->code_in_len ? (double)tot / s->code_in_len : 0);
2706a23a9ec6Sbellard     cpu_fprintf(f, "cycles/out byte     %0.1f\n",
2707a23a9ec6Sbellard                 s->code_out_len ? (double)tot / s->code_out_len : 0);
2708fca8a500SRichard Henderson     cpu_fprintf(f, "cycles/search byte     %0.1f\n",
2709fca8a500SRichard Henderson                 s->search_out_len ? (double)tot / s->search_out_len : 0);
2710fca8a500SRichard Henderson     if (tot == 0) {
2711a23a9ec6Sbellard         tot = 1;
2712fca8a500SRichard Henderson     }
2713a23a9ec6Sbellard     cpu_fprintf(f, "  gen_interm time   %0.1f%%\n",
2714a23a9ec6Sbellard                 (double)s->interm_time / tot * 100.0);
2715a23a9ec6Sbellard     cpu_fprintf(f, "  gen_code time     %0.1f%%\n",
2716a23a9ec6Sbellard                 (double)s->code_time / tot * 100.0);
2717c5cc28ffSAurelien Jarno     cpu_fprintf(f, "optim./code time    %0.1f%%\n",
2718c5cc28ffSAurelien Jarno                 (double)s->opt_time / (s->code_time ? s->code_time : 1)
2719c5cc28ffSAurelien Jarno                 * 100.0);
2720a23a9ec6Sbellard     cpu_fprintf(f, "liveness/code time  %0.1f%%\n",
2721a23a9ec6Sbellard                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
2722a23a9ec6Sbellard     cpu_fprintf(f, "cpu_restore count   %" PRId64 "\n",
2723a23a9ec6Sbellard                 s->restore_count);
2724a23a9ec6Sbellard     cpu_fprintf(f, "  avg cycles        %0.1f\n",
2725a23a9ec6Sbellard                 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
2726a23a9ec6Sbellard }
2727a23a9ec6Sbellard #else
2728405cf9ffSStefan Weil void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
2729a23a9ec6Sbellard {
273024bf7b3aSbellard     cpu_fprintf(f, "[TCG profiler not compiled]\n");
2731a23a9ec6Sbellard }
2732a23a9ec6Sbellard #endif
2733813da627SRichard Henderson 
2734813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
27355872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
27365872bbf2SRichard Henderson 
27375872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
27385872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
27395872bbf2SRichard Henderson 
27405872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
27415872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
27425872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
27435872bbf2SRichard Henderson 
27445872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
27455872bbf2SRichard Henderson */
2746813da627SRichard Henderson 
2747813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
2748813da627SRichard Henderson typedef enum {
2749813da627SRichard Henderson     JIT_NOACTION = 0,
2750813da627SRichard Henderson     JIT_REGISTER_FN,
2751813da627SRichard Henderson     JIT_UNREGISTER_FN
2752813da627SRichard Henderson } jit_actions_t;
2753813da627SRichard Henderson 
2754813da627SRichard Henderson struct jit_code_entry {
2755813da627SRichard Henderson     struct jit_code_entry *next_entry;
2756813da627SRichard Henderson     struct jit_code_entry *prev_entry;
2757813da627SRichard Henderson     const void *symfile_addr;
2758813da627SRichard Henderson     uint64_t symfile_size;
2759813da627SRichard Henderson };
2760813da627SRichard Henderson 
2761813da627SRichard Henderson struct jit_descriptor {
2762813da627SRichard Henderson     uint32_t version;
2763813da627SRichard Henderson     uint32_t action_flag;
2764813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
2765813da627SRichard Henderson     struct jit_code_entry *first_entry;
2766813da627SRichard Henderson };
2767813da627SRichard Henderson 
2768813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
2769813da627SRichard Henderson void __jit_debug_register_code(void)
2770813da627SRichard Henderson {
2771813da627SRichard Henderson     asm("");
2772813da627SRichard Henderson }
2773813da627SRichard Henderson 
2774813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
2775813da627SRichard Henderson    the version before we can set it.  */
2776813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
2777813da627SRichard Henderson 
2778813da627SRichard Henderson /* End GDB interface.  */
2779813da627SRichard Henderson 
2780813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
2781813da627SRichard Henderson {
2782813da627SRichard Henderson     const char *p = strtab + 1;
2783813da627SRichard Henderson 
2784813da627SRichard Henderson     while (1) {
2785813da627SRichard Henderson         if (strcmp(p, str) == 0) {
2786813da627SRichard Henderson             return p - strtab;
2787813da627SRichard Henderson         }
2788813da627SRichard Henderson         p += strlen(p) + 1;
2789813da627SRichard Henderson     }
2790813da627SRichard Henderson }
2791813da627SRichard Henderson 
27925872bbf2SRichard Henderson static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
27932c90784aSRichard Henderson                                  const void *debug_frame,
27942c90784aSRichard Henderson                                  size_t debug_frame_size)
2795813da627SRichard Henderson {
27965872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
27975872bbf2SRichard Henderson         uint32_t  len;
27985872bbf2SRichard Henderson         uint16_t  version;
27995872bbf2SRichard Henderson         uint32_t  abbrev;
28005872bbf2SRichard Henderson         uint8_t   ptr_size;
28015872bbf2SRichard Henderson         uint8_t   cu_die;
28025872bbf2SRichard Henderson         uint16_t  cu_lang;
28035872bbf2SRichard Henderson         uintptr_t cu_low_pc;
28045872bbf2SRichard Henderson         uintptr_t cu_high_pc;
28055872bbf2SRichard Henderson         uint8_t   fn_die;
28065872bbf2SRichard Henderson         char      fn_name[16];
28075872bbf2SRichard Henderson         uintptr_t fn_low_pc;
28085872bbf2SRichard Henderson         uintptr_t fn_high_pc;
28095872bbf2SRichard Henderson         uint8_t   cu_eoc;
28105872bbf2SRichard Henderson     };
2811813da627SRichard Henderson 
2812813da627SRichard Henderson     struct ElfImage {
2813813da627SRichard Henderson         ElfW(Ehdr) ehdr;
2814813da627SRichard Henderson         ElfW(Phdr) phdr;
28155872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
28165872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
28175872bbf2SRichard Henderson         struct DebugInfo di;
28185872bbf2SRichard Henderson         uint8_t    da[24];
28195872bbf2SRichard Henderson         char       str[80];
28205872bbf2SRichard Henderson     };
28215872bbf2SRichard Henderson 
28225872bbf2SRichard Henderson     struct ElfImage *img;
28235872bbf2SRichard Henderson 
28245872bbf2SRichard Henderson     static const struct ElfImage img_template = {
28255872bbf2SRichard Henderson         .ehdr = {
28265872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
28275872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
28285872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
28295872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
28305872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
28315872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
28325872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
28335872bbf2SRichard Henderson             .e_type = ET_EXEC,
28345872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
28355872bbf2SRichard Henderson             .e_version = EV_CURRENT,
28365872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
28375872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
28385872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
28395872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
28405872bbf2SRichard Henderson             .e_phnum = 1,
28415872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
28425872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
28435872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
2844abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
2845abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
2846abbb3eaeSRichard Henderson #endif
2847abbb3eaeSRichard Henderson #ifdef ELF_OSABI
2848abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
2849abbb3eaeSRichard Henderson #endif
28505872bbf2SRichard Henderson         },
28515872bbf2SRichard Henderson         .phdr = {
28525872bbf2SRichard Henderson             .p_type = PT_LOAD,
28535872bbf2SRichard Henderson             .p_flags = PF_X,
28545872bbf2SRichard Henderson         },
28555872bbf2SRichard Henderson         .shdr = {
28565872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
28575872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
28585872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
28595872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
28605872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
28615872bbf2SRichard Henderson             [1] = { /* .text */
28625872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
28635872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
28645872bbf2SRichard Henderson             },
28655872bbf2SRichard Henderson             [2] = { /* .debug_info */
28665872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
28675872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
28685872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
28695872bbf2SRichard Henderson             },
28705872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
28715872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
28725872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
28735872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
28745872bbf2SRichard Henderson             },
28755872bbf2SRichard Henderson             [4] = { /* .debug_frame */
28765872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
28775872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
28785872bbf2SRichard Henderson             },
28795872bbf2SRichard Henderson             [5] = { /* .symtab */
28805872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
28815872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
28825872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
28835872bbf2SRichard Henderson                 .sh_info = 1,
28845872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
28855872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
28865872bbf2SRichard Henderson             },
28875872bbf2SRichard Henderson             [6] = { /* .strtab */
28885872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
28895872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
28905872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
28915872bbf2SRichard Henderson             }
28925872bbf2SRichard Henderson         },
28935872bbf2SRichard Henderson         .sym = {
28945872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
28955872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
28965872bbf2SRichard Henderson                 .st_shndx = 1,
28975872bbf2SRichard Henderson             }
28985872bbf2SRichard Henderson         },
28995872bbf2SRichard Henderson         .di = {
29005872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
29015872bbf2SRichard Henderson             .version = 2,
29025872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
29035872bbf2SRichard Henderson             .cu_die = 1,
29045872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
29055872bbf2SRichard Henderson             .fn_die = 2,
29065872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
29075872bbf2SRichard Henderson         },
29085872bbf2SRichard Henderson         .da = {
29095872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
29105872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
29115872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
29125872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
29135872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
29145872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
29155872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
29165872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
29175872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
29185872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
29195872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
29205872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
29215872bbf2SRichard Henderson             0           /* no more abbrev */
29225872bbf2SRichard Henderson         },
29235872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
29245872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
2925813da627SRichard Henderson     };
2926813da627SRichard Henderson 
2927813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
2928813da627SRichard Henderson     static struct jit_code_entry one_entry;
2929813da627SRichard Henderson 
29305872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
2931813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
29322c90784aSRichard Henderson     DebugFrameHeader *dfh;
2933813da627SRichard Henderson 
29345872bbf2SRichard Henderson     img = g_malloc(img_size);
29355872bbf2SRichard Henderson     *img = img_template;
2936813da627SRichard Henderson 
29375872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
29385872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
29395872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
2940813da627SRichard Henderson 
29415872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
29425872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
29435872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
2944813da627SRichard Henderson 
29455872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
29465872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
29475872bbf2SRichard Henderson 
29485872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
29495872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
29505872bbf2SRichard Henderson 
29515872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
29525872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
29535872bbf2SRichard Henderson 
29545872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
29555872bbf2SRichard Henderson     img->sym[1].st_value = buf;
29565872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
29575872bbf2SRichard Henderson 
29585872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
295945aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
29605872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
296145aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
2962813da627SRichard Henderson 
29632c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
29642c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
29652c90784aSRichard Henderson     dfh->fde.func_start = buf;
29662c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
29672c90784aSRichard Henderson 
2968813da627SRichard Henderson #ifdef DEBUG_JIT
2969813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
2970813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
2971813da627SRichard Henderson     {
2972813da627SRichard Henderson         FILE *f = fopen("/tmp/qemu.jit", "w+b");
2973813da627SRichard Henderson         if (f) {
29745872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
2975813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
2976813da627SRichard Henderson             }
2977813da627SRichard Henderson             fclose(f);
2978813da627SRichard Henderson         }
2979813da627SRichard Henderson     }
2980813da627SRichard Henderson #endif
2981813da627SRichard Henderson 
2982813da627SRichard Henderson     one_entry.symfile_addr = img;
2983813da627SRichard Henderson     one_entry.symfile_size = img_size;
2984813da627SRichard Henderson 
2985813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
2986813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
2987813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
2988813da627SRichard Henderson     __jit_debug_register_code();
2989813da627SRichard Henderson }
2990813da627SRichard Henderson #else
29915872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
29925872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
2993813da627SRichard Henderson 
2994813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size,
29952c90784aSRichard Henderson                                  const void *debug_frame,
29962c90784aSRichard Henderson                                  size_t debug_frame_size)
2997813da627SRichard Henderson {
2998813da627SRichard Henderson }
2999813da627SRichard Henderson 
3000813da627SRichard Henderson void tcg_register_jit(void *buf, size_t buf_size)
3001813da627SRichard Henderson {
3002813da627SRichard Henderson }
3003813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
3004