xref: /openbmc/qemu/tcg/tcg.c (revision 069ea736)
1c896fe29Sbellard /*
2c896fe29Sbellard  * Tiny Code Generator for QEMU
3c896fe29Sbellard  *
4c896fe29Sbellard  * Copyright (c) 2008 Fabrice Bellard
5c896fe29Sbellard  *
6c896fe29Sbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
7c896fe29Sbellard  * of this software and associated documentation files (the "Software"), to deal
8c896fe29Sbellard  * in the Software without restriction, including without limitation the rights
9c896fe29Sbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10c896fe29Sbellard  * copies of the Software, and to permit persons to whom the Software is
11c896fe29Sbellard  * furnished to do so, subject to the following conditions:
12c896fe29Sbellard  *
13c896fe29Sbellard  * The above copyright notice and this permission notice shall be included in
14c896fe29Sbellard  * all copies or substantial portions of the Software.
15c896fe29Sbellard  *
16c896fe29Sbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17c896fe29Sbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18c896fe29Sbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19c896fe29Sbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20c896fe29Sbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21c896fe29Sbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22c896fe29Sbellard  * THE SOFTWARE.
23c896fe29Sbellard  */
24c896fe29Sbellard 
25c896fe29Sbellard /* define it to use liveness analysis (better code) */
268f2e8c07SKirill Batuzov #define USE_TCG_OPTIMIZATIONS
27c896fe29Sbellard 
28757e725bSPeter Maydell #include "qemu/osdep.h"
29cca82982Saurel32 
30813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB.  */
31813da627SRichard Henderson #undef DEBUG_JIT
32813da627SRichard Henderson 
33f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
341de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
351de7afc9SPaolo Bonzini #include "qemu/timer.h"
36c896fe29Sbellard 
37c5d3c498SStefan Weil /* Note: the long term plan is to reduce the dependencies on the QEMU
38c896fe29Sbellard    CPU definitions. Currently they are used for qemu_ld/st
39c896fe29Sbellard    instructions */
40c896fe29Sbellard #define NO_CPU_IO_DEFS
41c896fe29Sbellard #include "cpu.h"
42c896fe29Sbellard 
4363c91552SPaolo Bonzini #include "exec/cpu-common.h"
4463c91552SPaolo Bonzini #include "exec/exec-all.h"
4563c91552SPaolo Bonzini 
46c896fe29Sbellard #include "tcg-op.h"
47813da627SRichard Henderson 
48edee2579SRichard Henderson #if UINTPTR_MAX == UINT32_MAX
49813da627SRichard Henderson # define ELF_CLASS  ELFCLASS32
50edee2579SRichard Henderson #else
51edee2579SRichard Henderson # define ELF_CLASS  ELFCLASS64
52813da627SRichard Henderson #endif
53813da627SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
54813da627SRichard Henderson # define ELF_DATA   ELFDATA2MSB
55813da627SRichard Henderson #else
56813da627SRichard Henderson # define ELF_DATA   ELFDATA2LSB
57813da627SRichard Henderson #endif
58813da627SRichard Henderson 
59c896fe29Sbellard #include "elf.h"
60508127e2SPaolo Bonzini #include "exec/log.h"
61c896fe29Sbellard 
62ce151109SPeter Maydell /* Forward declarations for functions declared in tcg-target.inc.c and
63ce151109SPeter Maydell    used here. */
64e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s);
65f69d277eSRichard Henderson static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode);
66e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
671813e175SRichard Henderson static void patch_reloc(tcg_insn_unit *code_ptr, int type,
682ba7fae2SRichard Henderson                         intptr_t value, intptr_t addend);
69c896fe29Sbellard 
70497a22ebSRichard Henderson /* The CIE and FDE header definitions will be common to all hosts.  */
71497a22ebSRichard Henderson typedef struct {
72497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
73497a22ebSRichard Henderson     uint32_t id;
74497a22ebSRichard Henderson     uint8_t version;
75497a22ebSRichard Henderson     char augmentation[1];
76497a22ebSRichard Henderson     uint8_t code_align;
77497a22ebSRichard Henderson     uint8_t data_align;
78497a22ebSRichard Henderson     uint8_t return_column;
79497a22ebSRichard Henderson } DebugFrameCIE;
80497a22ebSRichard Henderson 
81497a22ebSRichard Henderson typedef struct QEMU_PACKED {
82497a22ebSRichard Henderson     uint32_t len __attribute__((aligned((sizeof(void *)))));
83497a22ebSRichard Henderson     uint32_t cie_offset;
84edee2579SRichard Henderson     uintptr_t func_start;
85edee2579SRichard Henderson     uintptr_t func_len;
86497a22ebSRichard Henderson } DebugFrameFDEHeader;
87497a22ebSRichard Henderson 
882c90784aSRichard Henderson typedef struct QEMU_PACKED {
892c90784aSRichard Henderson     DebugFrameCIE cie;
902c90784aSRichard Henderson     DebugFrameFDEHeader fde;
912c90784aSRichard Henderson } DebugFrameHeader;
922c90784aSRichard Henderson 
93813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size,
942c90784aSRichard Henderson                                  const void *debug_frame,
952c90784aSRichard Henderson                                  size_t debug_frame_size)
96813da627SRichard Henderson     __attribute__((unused));
97813da627SRichard Henderson 
98ce151109SPeter Maydell /* Forward declarations for functions declared and used in tcg-target.inc.c. */
99*069ea736SRichard Henderson static const char *target_parse_constraint(TCGArgConstraint *ct,
100*069ea736SRichard Henderson                                            const char *ct_str, TCGType type);
1012a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
102a05b5b9bSRichard Henderson                        intptr_t arg2);
1032a534affSRichard Henderson static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
104c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
1052a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
106c0ad3001SStefan Weil static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
107c0ad3001SStefan Weil                        const int *const_args);
1082a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
109a05b5b9bSRichard Henderson                        intptr_t arg2);
11059d7c14eSRichard Henderson static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
11159d7c14eSRichard Henderson                         TCGReg base, intptr_t ofs);
112cf066674SRichard Henderson static void tcg_out_call(TCGContext *s, tcg_insn_unit *target);
113f6c6afc1SRichard Henderson static int tcg_target_const_match(tcg_target_long val, TCGType type,
114c0ad3001SStefan Weil                                   const TCGArgConstraint *arg_ct);
1159ecefc84SRichard Henderson static void tcg_out_tb_init(TCGContext *s);
11623dceda6SRichard Henderson static bool tcg_out_tb_finalize(TCGContext *s);
1179ecefc84SRichard Henderson 
118c0ad3001SStefan Weil 
119c896fe29Sbellard 
120b1d8e52eSblueswir1 static TCGRegSet tcg_target_available_regs[2];
121b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
122c896fe29Sbellard 
1231813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE == 1
1244196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
125c896fe29Sbellard {
126c896fe29Sbellard     *s->code_ptr++ = v;
127c896fe29Sbellard }
128c896fe29Sbellard 
1294196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
1304196dca6SPeter Maydell                                                       uint8_t v)
1315c53bb81SPeter Maydell {
1321813e175SRichard Henderson     *p = v;
1335c53bb81SPeter Maydell }
1341813e175SRichard Henderson #endif
1355c53bb81SPeter Maydell 
1361813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 2
1374196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
138c896fe29Sbellard {
1391813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
1401813e175SRichard Henderson         *s->code_ptr++ = v;
1411813e175SRichard Henderson     } else {
1421813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
1434387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
1441813e175SRichard Henderson         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
1451813e175SRichard Henderson     }
146c896fe29Sbellard }
147c896fe29Sbellard 
1484196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
1494196dca6SPeter Maydell                                                        uint16_t v)
1505c53bb81SPeter Maydell {
1511813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
1521813e175SRichard Henderson         *p = v;
1531813e175SRichard Henderson     } else {
1545c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
1555c53bb81SPeter Maydell     }
1561813e175SRichard Henderson }
1571813e175SRichard Henderson #endif
1585c53bb81SPeter Maydell 
1591813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 4
1604196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
161c896fe29Sbellard {
1621813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
1631813e175SRichard Henderson         *s->code_ptr++ = v;
1641813e175SRichard Henderson     } else {
1651813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
1664387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
1671813e175SRichard Henderson         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
1681813e175SRichard Henderson     }
169c896fe29Sbellard }
170c896fe29Sbellard 
1714196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
1724196dca6SPeter Maydell                                                        uint32_t v)
1735c53bb81SPeter Maydell {
1741813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
1751813e175SRichard Henderson         *p = v;
1761813e175SRichard Henderson     } else {
1775c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
1785c53bb81SPeter Maydell     }
1791813e175SRichard Henderson }
1801813e175SRichard Henderson #endif
1815c53bb81SPeter Maydell 
1821813e175SRichard Henderson #if TCG_TARGET_INSN_UNIT_SIZE <= 8
1834196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
184ac26eb69SRichard Henderson {
1851813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
1861813e175SRichard Henderson         *s->code_ptr++ = v;
1871813e175SRichard Henderson     } else {
1881813e175SRichard Henderson         tcg_insn_unit *p = s->code_ptr;
1894387345aSPeter Maydell         memcpy(p, &v, sizeof(v));
1901813e175SRichard Henderson         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
1911813e175SRichard Henderson     }
192ac26eb69SRichard Henderson }
193ac26eb69SRichard Henderson 
1944196dca6SPeter Maydell static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
1954196dca6SPeter Maydell                                                        uint64_t v)
1965c53bb81SPeter Maydell {
1971813e175SRichard Henderson     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
1981813e175SRichard Henderson         *p = v;
1991813e175SRichard Henderson     } else {
2005c53bb81SPeter Maydell         memcpy(p, &v, sizeof(v));
2015c53bb81SPeter Maydell     }
2021813e175SRichard Henderson }
2031813e175SRichard Henderson #endif
2045c53bb81SPeter Maydell 
205c896fe29Sbellard /* label relocation processing */
206c896fe29Sbellard 
2071813e175SRichard Henderson static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
208bec16311SRichard Henderson                           TCGLabel *l, intptr_t addend)
209c896fe29Sbellard {
210c896fe29Sbellard     TCGRelocation *r;
211c896fe29Sbellard 
212c896fe29Sbellard     if (l->has_value) {
213623e265cSpbrook         /* FIXME: This may break relocations on RISC targets that
214623e265cSpbrook            modify instruction fields in place.  The caller may not have
215623e265cSpbrook            written the initial value.  */
216f54b3f92Saurel32         patch_reloc(code_ptr, type, l->u.value, addend);
217c896fe29Sbellard     } else {
218c896fe29Sbellard         /* add a new relocation entry */
219c896fe29Sbellard         r = tcg_malloc(sizeof(TCGRelocation));
220c896fe29Sbellard         r->type = type;
221c896fe29Sbellard         r->ptr = code_ptr;
222c896fe29Sbellard         r->addend = addend;
223c896fe29Sbellard         r->next = l->u.first_reloc;
224c896fe29Sbellard         l->u.first_reloc = r;
225c896fe29Sbellard     }
226c896fe29Sbellard }
227c896fe29Sbellard 
228bec16311SRichard Henderson static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr)
229c896fe29Sbellard {
2302ba7fae2SRichard Henderson     intptr_t value = (intptr_t)ptr;
2311813e175SRichard Henderson     TCGRelocation *r;
232c896fe29Sbellard 
233eabb7b91SAurelien Jarno     tcg_debug_assert(!l->has_value);
2341813e175SRichard Henderson 
2351813e175SRichard Henderson     for (r = l->u.first_reloc; r != NULL; r = r->next) {
236f54b3f92Saurel32         patch_reloc(r->ptr, r->type, value, r->addend);
237c896fe29Sbellard     }
2381813e175SRichard Henderson 
239c896fe29Sbellard     l->has_value = 1;
2401813e175SRichard Henderson     l->u.value_ptr = ptr;
241c896fe29Sbellard }
242c896fe29Sbellard 
24342a268c2SRichard Henderson TCGLabel *gen_new_label(void)
244c896fe29Sbellard {
245c896fe29Sbellard     TCGContext *s = &tcg_ctx;
24651e3972cSRichard Henderson     TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
247c896fe29Sbellard 
24851e3972cSRichard Henderson     *l = (TCGLabel){
24951e3972cSRichard Henderson         .id = s->nb_labels++
25051e3972cSRichard Henderson     };
25142a268c2SRichard Henderson 
25242a268c2SRichard Henderson     return l;
253c896fe29Sbellard }
254c896fe29Sbellard 
255ce151109SPeter Maydell #include "tcg-target.inc.c"
256c896fe29Sbellard 
257c896fe29Sbellard /* pool based memory allocation */
258c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
259c896fe29Sbellard {
260c896fe29Sbellard     TCGPool *p;
261c896fe29Sbellard     int pool_size;
262c896fe29Sbellard 
263c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
264c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
2657267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
266c896fe29Sbellard         p->size = size;
2674055299eSKirill Batuzov         p->next = s->pool_first_large;
2684055299eSKirill Batuzov         s->pool_first_large = p;
2694055299eSKirill Batuzov         return p->data;
270c896fe29Sbellard     } else {
271c896fe29Sbellard         p = s->pool_current;
272c896fe29Sbellard         if (!p) {
273c896fe29Sbellard             p = s->pool_first;
274c896fe29Sbellard             if (!p)
275c896fe29Sbellard                 goto new_pool;
276c896fe29Sbellard         } else {
277c896fe29Sbellard             if (!p->next) {
278c896fe29Sbellard             new_pool:
279c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
2807267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
281c896fe29Sbellard                 p->size = pool_size;
282c896fe29Sbellard                 p->next = NULL;
283c896fe29Sbellard                 if (s->pool_current)
284c896fe29Sbellard                     s->pool_current->next = p;
285c896fe29Sbellard                 else
286c896fe29Sbellard                     s->pool_first = p;
287c896fe29Sbellard             } else {
288c896fe29Sbellard                 p = p->next;
289c896fe29Sbellard             }
290c896fe29Sbellard         }
291c896fe29Sbellard     }
292c896fe29Sbellard     s->pool_current = p;
293c896fe29Sbellard     s->pool_cur = p->data + size;
294c896fe29Sbellard     s->pool_end = p->data + p->size;
295c896fe29Sbellard     return p->data;
296c896fe29Sbellard }
297c896fe29Sbellard 
298c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
299c896fe29Sbellard {
3004055299eSKirill Batuzov     TCGPool *p, *t;
3014055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
3024055299eSKirill Batuzov         t = p->next;
3034055299eSKirill Batuzov         g_free(p);
3044055299eSKirill Batuzov     }
3054055299eSKirill Batuzov     s->pool_first_large = NULL;
306c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
307c896fe29Sbellard     s->pool_current = NULL;
308c896fe29Sbellard }
309c896fe29Sbellard 
310100b5e01SRichard Henderson typedef struct TCGHelperInfo {
311100b5e01SRichard Henderson     void *func;
312100b5e01SRichard Henderson     const char *name;
313afb49896SRichard Henderson     unsigned flags;
314afb49896SRichard Henderson     unsigned sizemask;
315100b5e01SRichard Henderson } TCGHelperInfo;
316100b5e01SRichard Henderson 
3172ef6175aSRichard Henderson #include "exec/helper-proto.h"
3182ef6175aSRichard Henderson 
319100b5e01SRichard Henderson static const TCGHelperInfo all_helpers[] = {
3202ef6175aSRichard Henderson #include "exec/helper-tcg.h"
321100b5e01SRichard Henderson };
322100b5e01SRichard Henderson 
32391478cefSRichard Henderson static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
324f69d277eSRichard Henderson static void process_op_defs(TCGContext *s);
32591478cefSRichard Henderson 
326c896fe29Sbellard void tcg_context_init(TCGContext *s)
327c896fe29Sbellard {
328100b5e01SRichard Henderson     int op, total_args, n, i;
329c896fe29Sbellard     TCGOpDef *def;
330c896fe29Sbellard     TCGArgConstraint *args_ct;
331c896fe29Sbellard     int *sorted_args;
33284fd9dd3SRichard Henderson     GHashTable *helper_table;
333c896fe29Sbellard 
334c896fe29Sbellard     memset(s, 0, sizeof(*s));
335c896fe29Sbellard     s->nb_globals = 0;
336c896fe29Sbellard 
337c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
338c896fe29Sbellard        space */
339c896fe29Sbellard     total_args = 0;
340c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
341c896fe29Sbellard         def = &tcg_op_defs[op];
342c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
343c896fe29Sbellard         total_args += n;
344c896fe29Sbellard     }
345c896fe29Sbellard 
3467267c094SAnthony Liguori     args_ct = g_malloc(sizeof(TCGArgConstraint) * total_args);
3477267c094SAnthony Liguori     sorted_args = g_malloc(sizeof(int) * total_args);
348c896fe29Sbellard 
349c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
350c896fe29Sbellard         def = &tcg_op_defs[op];
351c896fe29Sbellard         def->args_ct = args_ct;
352c896fe29Sbellard         def->sorted_args = sorted_args;
353c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
354c896fe29Sbellard         sorted_args += n;
355c896fe29Sbellard         args_ct += n;
356c896fe29Sbellard     }
357c896fe29Sbellard 
3585cd8f621SRichard Henderson     /* Register helpers.  */
35984fd9dd3SRichard Henderson     /* Use g_direct_hash/equal for direct pointer comparisons on func.  */
36084fd9dd3SRichard Henderson     s->helpers = helper_table = g_hash_table_new(NULL, NULL);
36184fd9dd3SRichard Henderson 
362100b5e01SRichard Henderson     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
36384fd9dd3SRichard Henderson         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
36472866e82SRichard Henderson                             (gpointer)&all_helpers[i]);
365100b5e01SRichard Henderson     }
3665cd8f621SRichard Henderson 
367c896fe29Sbellard     tcg_target_init(s);
368f69d277eSRichard Henderson     process_op_defs(s);
36991478cefSRichard Henderson 
37091478cefSRichard Henderson     /* Reverse the order of the saved registers, assuming they're all at
37191478cefSRichard Henderson        the start of tcg_target_reg_alloc_order.  */
37291478cefSRichard Henderson     for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) {
37391478cefSRichard Henderson         int r = tcg_target_reg_alloc_order[n];
37491478cefSRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) {
37591478cefSRichard Henderson             break;
37691478cefSRichard Henderson         }
37791478cefSRichard Henderson     }
37891478cefSRichard Henderson     for (i = 0; i < n; ++i) {
37991478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i];
38091478cefSRichard Henderson     }
38191478cefSRichard Henderson     for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) {
38291478cefSRichard Henderson         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
38391478cefSRichard Henderson     }
3849002ec79SRichard Henderson }
385b03cce8eSbellard 
3869002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
3879002ec79SRichard Henderson {
3888163b749SRichard Henderson     size_t prologue_size, total_size;
3898163b749SRichard Henderson     void *buf0, *buf1;
3908163b749SRichard Henderson 
3918163b749SRichard Henderson     /* Put the prologue at the beginning of code_gen_buffer.  */
3928163b749SRichard Henderson     buf0 = s->code_gen_buffer;
3938163b749SRichard Henderson     s->code_ptr = buf0;
3948163b749SRichard Henderson     s->code_buf = buf0;
3958163b749SRichard Henderson     s->code_gen_prologue = buf0;
3968163b749SRichard Henderson 
3978163b749SRichard Henderson     /* Generate the prologue.  */
398b03cce8eSbellard     tcg_target_qemu_prologue(s);
3998163b749SRichard Henderson     buf1 = s->code_ptr;
4008163b749SRichard Henderson     flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1);
4018163b749SRichard Henderson 
4028163b749SRichard Henderson     /* Deduct the prologue from the buffer.  */
4038163b749SRichard Henderson     prologue_size = tcg_current_code_size(s);
4048163b749SRichard Henderson     s->code_gen_ptr = buf1;
4058163b749SRichard Henderson     s->code_gen_buffer = buf1;
4068163b749SRichard Henderson     s->code_buf = buf1;
4078163b749SRichard Henderson     total_size = s->code_gen_buffer_size - prologue_size;
4088163b749SRichard Henderson     s->code_gen_buffer_size = total_size;
4098163b749SRichard Henderson 
410b125f9dcSRichard Henderson     /* Compute a high-water mark, at which we voluntarily flush the buffer
411b125f9dcSRichard Henderson        and start over.  The size here is arbitrary, significantly larger
412b125f9dcSRichard Henderson        than we expect the code generation for any one opcode to require.  */
41323dceda6SRichard Henderson     s->code_gen_highwater = s->code_gen_buffer + (total_size - 1024);
4148163b749SRichard Henderson 
4158163b749SRichard Henderson     tcg_register_jit(s->code_gen_buffer, total_size);
416d6b64b2bSRichard Henderson 
417d6b64b2bSRichard Henderson #ifdef DEBUG_DISAS
418d6b64b2bSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
4191ee73216SRichard Henderson         qemu_log_lock();
4208163b749SRichard Henderson         qemu_log("PROLOGUE: [size=%zu]\n", prologue_size);
4218163b749SRichard Henderson         log_disas(buf0, prologue_size);
422d6b64b2bSRichard Henderson         qemu_log("\n");
423d6b64b2bSRichard Henderson         qemu_log_flush();
4241ee73216SRichard Henderson         qemu_log_unlock();
425d6b64b2bSRichard Henderson     }
426d6b64b2bSRichard Henderson #endif
427c896fe29Sbellard }
428c896fe29Sbellard 
429c896fe29Sbellard void tcg_func_start(TCGContext *s)
430c896fe29Sbellard {
431c896fe29Sbellard     tcg_pool_reset(s);
432c896fe29Sbellard     s->nb_temps = s->nb_globals;
4330ec9eabcSRichard Henderson 
4340ec9eabcSRichard Henderson     /* No temps have been previously allocated for size or locality.  */
4350ec9eabcSRichard Henderson     memset(s->free_temps, 0, sizeof(s->free_temps));
4360ec9eabcSRichard Henderson 
437c896fe29Sbellard     s->nb_labels = 0;
438c896fe29Sbellard     s->current_frame_offset = s->frame_start;
439c896fe29Sbellard 
4400a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
4410a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
4420a209d4bSRichard Henderson #endif
4430a209d4bSRichard Henderson 
444dcb8e758SRichard Henderson     s->gen_op_buf[0].next = 1;
445dcb8e758SRichard Henderson     s->gen_op_buf[0].prev = 0;
446dcb8e758SRichard Henderson     s->gen_next_op_idx = 1;
447c45cb8bbSRichard Henderson     s->gen_next_parm_idx = 0;
448b76f0d8cSYeongkyoon Lee 
4499ecefc84SRichard Henderson     s->be = tcg_malloc(sizeof(TCGBackendData));
450c896fe29Sbellard }
451c896fe29Sbellard 
4527ca4b752SRichard Henderson static inline int temp_idx(TCGContext *s, TCGTemp *ts)
453c896fe29Sbellard {
4547ca4b752SRichard Henderson     ptrdiff_t n = ts - s->temps;
4557ca4b752SRichard Henderson     tcg_debug_assert(n >= 0 && n < s->nb_temps);
4567ca4b752SRichard Henderson     return n;
4577ca4b752SRichard Henderson }
4587ca4b752SRichard Henderson 
4597ca4b752SRichard Henderson static inline TCGTemp *tcg_temp_alloc(TCGContext *s)
4607ca4b752SRichard Henderson {
4617ca4b752SRichard Henderson     int n = s->nb_temps++;
4627ca4b752SRichard Henderson     tcg_debug_assert(n < TCG_MAX_TEMPS);
4637ca4b752SRichard Henderson     return memset(&s->temps[n], 0, sizeof(TCGTemp));
4647ca4b752SRichard Henderson }
4657ca4b752SRichard Henderson 
4667ca4b752SRichard Henderson static inline TCGTemp *tcg_global_alloc(TCGContext *s)
4677ca4b752SRichard Henderson {
4687ca4b752SRichard Henderson     tcg_debug_assert(s->nb_globals == s->nb_temps);
4697ca4b752SRichard Henderson     s->nb_globals++;
4707ca4b752SRichard Henderson     return tcg_temp_alloc(s);
471c896fe29Sbellard }
472c896fe29Sbellard 
473b3a62939SRichard Henderson static int tcg_global_reg_new_internal(TCGContext *s, TCGType type,
474b6638662SRichard Henderson                                        TCGReg reg, const char *name)
475c896fe29Sbellard {
476c896fe29Sbellard     TCGTemp *ts;
477c896fe29Sbellard 
478b3a62939SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type != TCG_TYPE_I32) {
479c896fe29Sbellard         tcg_abort();
480b3a62939SRichard Henderson     }
4817ca4b752SRichard Henderson 
4827ca4b752SRichard Henderson     ts = tcg_global_alloc(s);
483c896fe29Sbellard     ts->base_type = type;
484c896fe29Sbellard     ts->type = type;
485c896fe29Sbellard     ts->fixed_reg = 1;
486c896fe29Sbellard     ts->reg = reg;
487c896fe29Sbellard     ts->name = name;
488c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
4897ca4b752SRichard Henderson 
4907ca4b752SRichard Henderson     return temp_idx(s, ts);
491a7812ae4Spbrook }
492a7812ae4Spbrook 
493b6638662SRichard Henderson void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size)
494a7812ae4Spbrook {
495a7812ae4Spbrook     int idx;
496b3a62939SRichard Henderson     s->frame_start = start;
497b3a62939SRichard Henderson     s->frame_end = start + size;
498b3a62939SRichard Henderson     idx = tcg_global_reg_new_internal(s, TCG_TYPE_PTR, reg, "_frame");
499b3a62939SRichard Henderson     s->frame_temp = &s->temps[idx];
500b3a62939SRichard Henderson }
501a7812ae4Spbrook 
502b6638662SRichard Henderson TCGv_i32 tcg_global_reg_new_i32(TCGReg reg, const char *name)
503b3a62939SRichard Henderson {
504b3a62939SRichard Henderson     TCGContext *s = &tcg_ctx;
505b3a62939SRichard Henderson     int idx;
506b3a62939SRichard Henderson 
507b3a62939SRichard Henderson     if (tcg_regset_test_reg(s->reserved_regs, reg)) {
508b3a62939SRichard Henderson         tcg_abort();
509b3a62939SRichard Henderson     }
510b3a62939SRichard Henderson     idx = tcg_global_reg_new_internal(s, TCG_TYPE_I32, reg, name);
511a7812ae4Spbrook     return MAKE_TCGV_I32(idx);
512a7812ae4Spbrook }
513a7812ae4Spbrook 
514b6638662SRichard Henderson TCGv_i64 tcg_global_reg_new_i64(TCGReg reg, const char *name)
515a7812ae4Spbrook {
516b3a62939SRichard Henderson     TCGContext *s = &tcg_ctx;
517a7812ae4Spbrook     int idx;
518a7812ae4Spbrook 
519b3a62939SRichard Henderson     if (tcg_regset_test_reg(s->reserved_regs, reg)) {
520b3a62939SRichard Henderson         tcg_abort();
521b3a62939SRichard Henderson     }
522b3a62939SRichard Henderson     idx = tcg_global_reg_new_internal(s, TCG_TYPE_I64, reg, name);
523a7812ae4Spbrook     return MAKE_TCGV_I64(idx);
524c896fe29Sbellard }
525c896fe29Sbellard 
526e1ccc054SRichard Henderson int tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
527e1ccc054SRichard Henderson                                 intptr_t offset, const char *name)
528c896fe29Sbellard {
529c896fe29Sbellard     TCGContext *s = &tcg_ctx;
5307ca4b752SRichard Henderson     TCGTemp *base_ts = &s->temps[GET_TCGV_PTR(base)];
5317ca4b752SRichard Henderson     TCGTemp *ts = tcg_global_alloc(s);
532b3915dbbSRichard Henderson     int indirect_reg = 0, bigendian = 0;
5337ca4b752SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
5347ca4b752SRichard Henderson     bigendian = 1;
5357ca4b752SRichard Henderson #endif
536c896fe29Sbellard 
537b3915dbbSRichard Henderson     if (!base_ts->fixed_reg) {
5385a18407fSRichard Henderson         /* We do not support double-indirect registers.  */
5395a18407fSRichard Henderson         tcg_debug_assert(!base_ts->indirect_reg);
540b3915dbbSRichard Henderson         base_ts->indirect_base = 1;
5415a18407fSRichard Henderson         s->nb_indirects += (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64
5425a18407fSRichard Henderson                             ? 2 : 1);
5435a18407fSRichard Henderson         indirect_reg = 1;
544b3915dbbSRichard Henderson     }
545b3915dbbSRichard Henderson 
5467ca4b752SRichard Henderson     if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
5477ca4b752SRichard Henderson         TCGTemp *ts2 = tcg_global_alloc(s);
548c896fe29Sbellard         char buf[64];
5497ca4b752SRichard Henderson 
5507ca4b752SRichard Henderson         ts->base_type = TCG_TYPE_I64;
551c896fe29Sbellard         ts->type = TCG_TYPE_I32;
552b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
553c896fe29Sbellard         ts->mem_allocated = 1;
554b3a62939SRichard Henderson         ts->mem_base = base_ts;
5557ca4b752SRichard Henderson         ts->mem_offset = offset + bigendian * 4;
556c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
557c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
558c896fe29Sbellard         ts->name = strdup(buf);
559c896fe29Sbellard 
5607ca4b752SRichard Henderson         tcg_debug_assert(ts2 == ts + 1);
5617ca4b752SRichard Henderson         ts2->base_type = TCG_TYPE_I64;
5627ca4b752SRichard Henderson         ts2->type = TCG_TYPE_I32;
563b3915dbbSRichard Henderson         ts2->indirect_reg = indirect_reg;
5647ca4b752SRichard Henderson         ts2->mem_allocated = 1;
5657ca4b752SRichard Henderson         ts2->mem_base = base_ts;
5667ca4b752SRichard Henderson         ts2->mem_offset = offset + (1 - bigendian) * 4;
567c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
568c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
569120c1084SRichard Henderson         ts2->name = strdup(buf);
5707ca4b752SRichard Henderson     } else {
571c896fe29Sbellard         ts->base_type = type;
572c896fe29Sbellard         ts->type = type;
573b3915dbbSRichard Henderson         ts->indirect_reg = indirect_reg;
574c896fe29Sbellard         ts->mem_allocated = 1;
575b3a62939SRichard Henderson         ts->mem_base = base_ts;
576c896fe29Sbellard         ts->mem_offset = offset;
577c896fe29Sbellard         ts->name = name;
578c896fe29Sbellard     }
5797ca4b752SRichard Henderson     return temp_idx(s, ts);
580c896fe29Sbellard }
581c896fe29Sbellard 
5827ca4b752SRichard Henderson static int tcg_temp_new_internal(TCGType type, int temp_local)
583c896fe29Sbellard {
584c896fe29Sbellard     TCGContext *s = &tcg_ctx;
585c896fe29Sbellard     TCGTemp *ts;
586641d5fbeSbellard     int idx, k;
587c896fe29Sbellard 
5880ec9eabcSRichard Henderson     k = type + (temp_local ? TCG_TYPE_COUNT : 0);
5890ec9eabcSRichard Henderson     idx = find_first_bit(s->free_temps[k].l, TCG_MAX_TEMPS);
5900ec9eabcSRichard Henderson     if (idx < TCG_MAX_TEMPS) {
5910ec9eabcSRichard Henderson         /* There is already an available temp with the right type.  */
5920ec9eabcSRichard Henderson         clear_bit(idx, s->free_temps[k].l);
5930ec9eabcSRichard Henderson 
594e8996ee0Sbellard         ts = &s->temps[idx];
595e8996ee0Sbellard         ts->temp_allocated = 1;
5967ca4b752SRichard Henderson         tcg_debug_assert(ts->base_type == type);
5977ca4b752SRichard Henderson         tcg_debug_assert(ts->temp_local == temp_local);
598e8996ee0Sbellard     } else {
5997ca4b752SRichard Henderson         ts = tcg_temp_alloc(s);
6007ca4b752SRichard Henderson         if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) {
6017ca4b752SRichard Henderson             TCGTemp *ts2 = tcg_temp_alloc(s);
6027ca4b752SRichard Henderson 
603c896fe29Sbellard             ts->base_type = type;
604c896fe29Sbellard             ts->type = TCG_TYPE_I32;
605e8996ee0Sbellard             ts->temp_allocated = 1;
606641d5fbeSbellard             ts->temp_local = temp_local;
6077ca4b752SRichard Henderson 
6087ca4b752SRichard Henderson             tcg_debug_assert(ts2 == ts + 1);
6097ca4b752SRichard Henderson             ts2->base_type = TCG_TYPE_I64;
6107ca4b752SRichard Henderson             ts2->type = TCG_TYPE_I32;
6117ca4b752SRichard Henderson             ts2->temp_allocated = 1;
6127ca4b752SRichard Henderson             ts2->temp_local = temp_local;
6137ca4b752SRichard Henderson         } else {
614c896fe29Sbellard             ts->base_type = type;
615c896fe29Sbellard             ts->type = type;
616e8996ee0Sbellard             ts->temp_allocated = 1;
617641d5fbeSbellard             ts->temp_local = temp_local;
618c896fe29Sbellard         }
6197ca4b752SRichard Henderson         idx = temp_idx(s, ts);
620e8996ee0Sbellard     }
62127bfd83cSPeter Maydell 
62227bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
62327bfd83cSPeter Maydell     s->temps_in_use++;
62427bfd83cSPeter Maydell #endif
625a7812ae4Spbrook     return idx;
626c896fe29Sbellard }
627c896fe29Sbellard 
628a7812ae4Spbrook TCGv_i32 tcg_temp_new_internal_i32(int temp_local)
629a7812ae4Spbrook {
630a7812ae4Spbrook     int idx;
631a7812ae4Spbrook 
632a7812ae4Spbrook     idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local);
633a7812ae4Spbrook     return MAKE_TCGV_I32(idx);
634a7812ae4Spbrook }
635a7812ae4Spbrook 
636a7812ae4Spbrook TCGv_i64 tcg_temp_new_internal_i64(int temp_local)
637a7812ae4Spbrook {
638a7812ae4Spbrook     int idx;
639a7812ae4Spbrook 
640a7812ae4Spbrook     idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local);
641a7812ae4Spbrook     return MAKE_TCGV_I64(idx);
642a7812ae4Spbrook }
643a7812ae4Spbrook 
6440ec9eabcSRichard Henderson static void tcg_temp_free_internal(int idx)
645c896fe29Sbellard {
646c896fe29Sbellard     TCGContext *s = &tcg_ctx;
647c896fe29Sbellard     TCGTemp *ts;
648641d5fbeSbellard     int k;
649c896fe29Sbellard 
65027bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
65127bfd83cSPeter Maydell     s->temps_in_use--;
65227bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
65327bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
65427bfd83cSPeter Maydell     }
65527bfd83cSPeter Maydell #endif
65627bfd83cSPeter Maydell 
657eabb7b91SAurelien Jarno     tcg_debug_assert(idx >= s->nb_globals && idx < s->nb_temps);
658c896fe29Sbellard     ts = &s->temps[idx];
659eabb7b91SAurelien Jarno     tcg_debug_assert(ts->temp_allocated != 0);
660e8996ee0Sbellard     ts->temp_allocated = 0;
6610ec9eabcSRichard Henderson 
66218d13fa2SAlexander Graf     k = ts->base_type + (ts->temp_local ? TCG_TYPE_COUNT : 0);
6630ec9eabcSRichard Henderson     set_bit(idx, s->free_temps[k].l);
664e8996ee0Sbellard }
665e8996ee0Sbellard 
666a7812ae4Spbrook void tcg_temp_free_i32(TCGv_i32 arg)
667e8996ee0Sbellard {
668a7812ae4Spbrook     tcg_temp_free_internal(GET_TCGV_I32(arg));
669a7812ae4Spbrook }
670a7812ae4Spbrook 
671a7812ae4Spbrook void tcg_temp_free_i64(TCGv_i64 arg)
672a7812ae4Spbrook {
673a7812ae4Spbrook     tcg_temp_free_internal(GET_TCGV_I64(arg));
674a7812ae4Spbrook }
675a7812ae4Spbrook 
676a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
677a7812ae4Spbrook {
678a7812ae4Spbrook     TCGv_i32 t0;
679a7812ae4Spbrook     t0 = tcg_temp_new_i32();
680e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
681e8996ee0Sbellard     return t0;
682c896fe29Sbellard }
683c896fe29Sbellard 
684a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
685c896fe29Sbellard {
686a7812ae4Spbrook     TCGv_i64 t0;
687a7812ae4Spbrook     t0 = tcg_temp_new_i64();
688e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
689e8996ee0Sbellard     return t0;
690c896fe29Sbellard }
691c896fe29Sbellard 
692a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
693bdffd4a9Saurel32 {
694a7812ae4Spbrook     TCGv_i32 t0;
695a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
696bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
697bdffd4a9Saurel32     return t0;
698bdffd4a9Saurel32 }
699bdffd4a9Saurel32 
700a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
701bdffd4a9Saurel32 {
702a7812ae4Spbrook     TCGv_i64 t0;
703a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
704bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
705bdffd4a9Saurel32     return t0;
706bdffd4a9Saurel32 }
707bdffd4a9Saurel32 
70827bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
70927bfd83cSPeter Maydell void tcg_clear_temp_count(void)
71027bfd83cSPeter Maydell {
71127bfd83cSPeter Maydell     TCGContext *s = &tcg_ctx;
71227bfd83cSPeter Maydell     s->temps_in_use = 0;
71327bfd83cSPeter Maydell }
71427bfd83cSPeter Maydell 
71527bfd83cSPeter Maydell int tcg_check_temp_count(void)
71627bfd83cSPeter Maydell {
71727bfd83cSPeter Maydell     TCGContext *s = &tcg_ctx;
71827bfd83cSPeter Maydell     if (s->temps_in_use) {
71927bfd83cSPeter Maydell         /* Clear the count so that we don't give another
72027bfd83cSPeter Maydell          * warning immediately next time around.
72127bfd83cSPeter Maydell          */
72227bfd83cSPeter Maydell         s->temps_in_use = 0;
72327bfd83cSPeter Maydell         return 1;
72427bfd83cSPeter Maydell     }
72527bfd83cSPeter Maydell     return 0;
72627bfd83cSPeter Maydell }
72727bfd83cSPeter Maydell #endif
72827bfd83cSPeter Maydell 
72939cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment
73039cf05d3Sbellard    and endian swap. Maybe it would be better to do the alignment
73139cf05d3Sbellard    and endian swap in tcg_reg_alloc_call(). */
732bbb8a1b4SRichard Henderson void tcg_gen_callN(TCGContext *s, void *func, TCGArg ret,
733bbb8a1b4SRichard Henderson                    int nargs, TCGArg *args)
734c896fe29Sbellard {
735c45cb8bbSRichard Henderson     int i, real_args, nb_rets, pi, pi_first;
736bbb8a1b4SRichard Henderson     unsigned sizemask, flags;
737afb49896SRichard Henderson     TCGHelperInfo *info;
738afb49896SRichard Henderson 
739afb49896SRichard Henderson     info = g_hash_table_lookup(s->helpers, (gpointer)func);
740bbb8a1b4SRichard Henderson     flags = info->flags;
741bbb8a1b4SRichard Henderson     sizemask = info->sizemask;
7422bece2c8SRichard Henderson 
74334b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
74434b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
74534b1a49cSRichard Henderson     /* We have 64-bit values in one register, but need to pass as two
74634b1a49cSRichard Henderson        separate parameters.  Split them.  */
74734b1a49cSRichard Henderson     int orig_sizemask = sizemask;
74834b1a49cSRichard Henderson     int orig_nargs = nargs;
74934b1a49cSRichard Henderson     TCGv_i64 retl, reth;
75034b1a49cSRichard Henderson 
75134b1a49cSRichard Henderson     TCGV_UNUSED_I64(retl);
75234b1a49cSRichard Henderson     TCGV_UNUSED_I64(reth);
75334b1a49cSRichard Henderson     if (sizemask != 0) {
75434b1a49cSRichard Henderson         TCGArg *split_args = __builtin_alloca(sizeof(TCGArg) * nargs * 2);
75534b1a49cSRichard Henderson         for (i = real_args = 0; i < nargs; ++i) {
75634b1a49cSRichard Henderson             int is_64bit = sizemask & (1 << (i+1)*2);
75734b1a49cSRichard Henderson             if (is_64bit) {
75834b1a49cSRichard Henderson                 TCGv_i64 orig = MAKE_TCGV_I64(args[i]);
75934b1a49cSRichard Henderson                 TCGv_i32 h = tcg_temp_new_i32();
76034b1a49cSRichard Henderson                 TCGv_i32 l = tcg_temp_new_i32();
76134b1a49cSRichard Henderson                 tcg_gen_extr_i64_i32(l, h, orig);
76234b1a49cSRichard Henderson                 split_args[real_args++] = GET_TCGV_I32(h);
76334b1a49cSRichard Henderson                 split_args[real_args++] = GET_TCGV_I32(l);
76434b1a49cSRichard Henderson             } else {
76534b1a49cSRichard Henderson                 split_args[real_args++] = args[i];
76634b1a49cSRichard Henderson             }
76734b1a49cSRichard Henderson         }
76834b1a49cSRichard Henderson         nargs = real_args;
76934b1a49cSRichard Henderson         args = split_args;
77034b1a49cSRichard Henderson         sizemask = 0;
77134b1a49cSRichard Henderson     }
77234b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
7732bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
7742bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
7752bece2c8SRichard Henderson         int is_signed = sizemask & (2 << (i+1)*2);
7762bece2c8SRichard Henderson         if (!is_64bit) {
7772bece2c8SRichard Henderson             TCGv_i64 temp = tcg_temp_new_i64();
7782bece2c8SRichard Henderson             TCGv_i64 orig = MAKE_TCGV_I64(args[i]);
7792bece2c8SRichard Henderson             if (is_signed) {
7802bece2c8SRichard Henderson                 tcg_gen_ext32s_i64(temp, orig);
7812bece2c8SRichard Henderson             } else {
7822bece2c8SRichard Henderson                 tcg_gen_ext32u_i64(temp, orig);
7832bece2c8SRichard Henderson             }
7842bece2c8SRichard Henderson             args[i] = GET_TCGV_I64(temp);
7852bece2c8SRichard Henderson         }
7862bece2c8SRichard Henderson     }
7872bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
7882bece2c8SRichard Henderson 
789c45cb8bbSRichard Henderson     pi_first = pi = s->gen_next_parm_idx;
790a7812ae4Spbrook     if (ret != TCG_CALL_DUMMY_ARG) {
79134b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
79234b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
79334b1a49cSRichard Henderson         if (orig_sizemask & 1) {
79434b1a49cSRichard Henderson             /* The 32-bit ABI is going to return the 64-bit value in
79534b1a49cSRichard Henderson                the %o0/%o1 register pair.  Prepare for this by using
79634b1a49cSRichard Henderson                two return temporaries, and reassemble below.  */
79734b1a49cSRichard Henderson             retl = tcg_temp_new_i64();
79834b1a49cSRichard Henderson             reth = tcg_temp_new_i64();
799c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = GET_TCGV_I64(reth);
800c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = GET_TCGV_I64(retl);
80134b1a49cSRichard Henderson             nb_rets = 2;
80234b1a49cSRichard Henderson         } else {
803c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = ret;
80434b1a49cSRichard Henderson             nb_rets = 1;
80534b1a49cSRichard Henderson         }
80634b1a49cSRichard Henderson #else
80734b1a49cSRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) {
80802eb19d0SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
809c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = ret + 1;
810c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = ret;
811a7812ae4Spbrook #else
812c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = ret;
813c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = ret + 1;
814a7812ae4Spbrook #endif
815a7812ae4Spbrook             nb_rets = 2;
81634b1a49cSRichard Henderson         } else {
817c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = ret;
818a7812ae4Spbrook             nb_rets = 1;
819a7812ae4Spbrook         }
82034b1a49cSRichard Henderson #endif
821a7812ae4Spbrook     } else {
822a7812ae4Spbrook         nb_rets = 0;
823a7812ae4Spbrook     }
824a7812ae4Spbrook     real_args = 0;
825a7812ae4Spbrook     for (i = 0; i < nargs; i++) {
8262bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
827bbb8a1b4SRichard Henderson         if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
82839cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS
82939cf05d3Sbellard             /* some targets want aligned 64 bit args */
830ebd486d5Smalc             if (real_args & 1) {
831c45cb8bbSRichard Henderson                 s->gen_opparam_buf[pi++] = TCG_CALL_DUMMY_ARG;
832ebd486d5Smalc                 real_args++;
83339cf05d3Sbellard             }
83439cf05d3Sbellard #endif
8353f90f252SRichard Henderson            /* If stack grows up, then we will be placing successive
8363f90f252SRichard Henderson               arguments at lower addresses, which means we need to
8373f90f252SRichard Henderson               reverse the order compared to how we would normally
8383f90f252SRichard Henderson               treat either big or little-endian.  For those arguments
8393f90f252SRichard Henderson               that will wind up in registers, this still works for
8403f90f252SRichard Henderson               HPPA (the only current STACK_GROWSUP target) since the
8413f90f252SRichard Henderson               argument registers are *also* allocated in decreasing
8423f90f252SRichard Henderson               order.  If another such target is added, this logic may
8433f90f252SRichard Henderson               have to get more complicated to differentiate between
8443f90f252SRichard Henderson               stack arguments and register arguments.  */
84502eb19d0SRichard Henderson #if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
846c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = args[i] + 1;
847c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = args[i];
848c896fe29Sbellard #else
849c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = args[i];
850c45cb8bbSRichard Henderson             s->gen_opparam_buf[pi++] = args[i] + 1;
851c896fe29Sbellard #endif
852a7812ae4Spbrook             real_args += 2;
8532bece2c8SRichard Henderson             continue;
8542bece2c8SRichard Henderson         }
8552bece2c8SRichard Henderson 
856c45cb8bbSRichard Henderson         s->gen_opparam_buf[pi++] = args[i];
857a7812ae4Spbrook         real_args++;
858c896fe29Sbellard     }
859c45cb8bbSRichard Henderson     s->gen_opparam_buf[pi++] = (uintptr_t)func;
860c45cb8bbSRichard Henderson     s->gen_opparam_buf[pi++] = flags;
861a7812ae4Spbrook 
862c45cb8bbSRichard Henderson     i = s->gen_next_op_idx;
863c45cb8bbSRichard Henderson     tcg_debug_assert(i < OPC_BUF_SIZE);
864c45cb8bbSRichard Henderson     tcg_debug_assert(pi <= OPPARAM_BUF_SIZE);
865a7812ae4Spbrook 
866c45cb8bbSRichard Henderson     /* Set links for sequential allocation during translation.  */
867c45cb8bbSRichard Henderson     s->gen_op_buf[i] = (TCGOp){
868c45cb8bbSRichard Henderson         .opc = INDEX_op_call,
869c45cb8bbSRichard Henderson         .callo = nb_rets,
870c45cb8bbSRichard Henderson         .calli = real_args,
871c45cb8bbSRichard Henderson         .args = pi_first,
872c45cb8bbSRichard Henderson         .prev = i - 1,
873c45cb8bbSRichard Henderson         .next = i + 1
874c45cb8bbSRichard Henderson     };
875c45cb8bbSRichard Henderson 
876c45cb8bbSRichard Henderson     /* Make sure the calli field didn't overflow.  */
877c45cb8bbSRichard Henderson     tcg_debug_assert(s->gen_op_buf[i].calli == real_args);
878c45cb8bbSRichard Henderson 
879dcb8e758SRichard Henderson     s->gen_op_buf[0].prev = i;
880c45cb8bbSRichard Henderson     s->gen_next_op_idx = i + 1;
881c45cb8bbSRichard Henderson     s->gen_next_parm_idx = pi;
8822bece2c8SRichard Henderson 
88334b1a49cSRichard Henderson #if defined(__sparc__) && !defined(__arch64__) \
88434b1a49cSRichard Henderson     && !defined(CONFIG_TCG_INTERPRETER)
88534b1a49cSRichard Henderson     /* Free all of the parts we allocated above.  */
88634b1a49cSRichard Henderson     for (i = real_args = 0; i < orig_nargs; ++i) {
88734b1a49cSRichard Henderson         int is_64bit = orig_sizemask & (1 << (i+1)*2);
88834b1a49cSRichard Henderson         if (is_64bit) {
88934b1a49cSRichard Henderson             TCGv_i32 h = MAKE_TCGV_I32(args[real_args++]);
89034b1a49cSRichard Henderson             TCGv_i32 l = MAKE_TCGV_I32(args[real_args++]);
89134b1a49cSRichard Henderson             tcg_temp_free_i32(h);
89234b1a49cSRichard Henderson             tcg_temp_free_i32(l);
89334b1a49cSRichard Henderson         } else {
89434b1a49cSRichard Henderson             real_args++;
89534b1a49cSRichard Henderson         }
89634b1a49cSRichard Henderson     }
89734b1a49cSRichard Henderson     if (orig_sizemask & 1) {
89834b1a49cSRichard Henderson         /* The 32-bit ABI returned two 32-bit pieces.  Re-assemble them.
89934b1a49cSRichard Henderson            Note that describing these as TCGv_i64 eliminates an unnecessary
90034b1a49cSRichard Henderson            zero-extension that tcg_gen_concat_i32_i64 would create.  */
90134b1a49cSRichard Henderson         tcg_gen_concat32_i64(MAKE_TCGV_I64(ret), retl, reth);
90234b1a49cSRichard Henderson         tcg_temp_free_i64(retl);
90334b1a49cSRichard Henderson         tcg_temp_free_i64(reth);
90434b1a49cSRichard Henderson     }
90534b1a49cSRichard Henderson #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
9062bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
9072bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
9082bece2c8SRichard Henderson         if (!is_64bit) {
9092bece2c8SRichard Henderson             TCGv_i64 temp = MAKE_TCGV_I64(args[i]);
9102bece2c8SRichard Henderson             tcg_temp_free_i64(temp);
9112bece2c8SRichard Henderson         }
9122bece2c8SRichard Henderson     }
9132bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
914a7812ae4Spbrook }
915c896fe29Sbellard 
9168fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
917c896fe29Sbellard {
918c896fe29Sbellard     int i;
919c896fe29Sbellard     TCGTemp *ts;
920c896fe29Sbellard     for(i = 0; i < s->nb_globals; i++) {
921c896fe29Sbellard         ts = &s->temps[i];
922c896fe29Sbellard         if (ts->fixed_reg) {
923c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
924c896fe29Sbellard         } else {
925c896fe29Sbellard             ts->val_type = TEMP_VAL_MEM;
926c896fe29Sbellard         }
927c896fe29Sbellard     }
928e8996ee0Sbellard     for(i = s->nb_globals; i < s->nb_temps; i++) {
929e8996ee0Sbellard         ts = &s->temps[i];
9307dfd8c6aSAurelien Jarno         if (ts->temp_local) {
9317dfd8c6aSAurelien Jarno             ts->val_type = TEMP_VAL_MEM;
9327dfd8c6aSAurelien Jarno         } else {
933e8996ee0Sbellard             ts->val_type = TEMP_VAL_DEAD;
9347dfd8c6aSAurelien Jarno         }
935e8996ee0Sbellard         ts->mem_allocated = 0;
936e8996ee0Sbellard         ts->fixed_reg = 0;
937e8996ee0Sbellard     }
938f8b2f202SRichard Henderson 
939f8b2f202SRichard Henderson     memset(s->reg_to_temp, 0, sizeof(s->reg_to_temp));
940c896fe29Sbellard }
941c896fe29Sbellard 
942f8b2f202SRichard Henderson static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
943f8b2f202SRichard Henderson                                  TCGTemp *ts)
944c896fe29Sbellard {
945f8b2f202SRichard Henderson     int idx = temp_idx(s, ts);
946ac56dd48Spbrook 
947ac56dd48Spbrook     if (idx < s->nb_globals) {
948ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
949f8b2f202SRichard Henderson     } else if (ts->temp_local) {
950641d5fbeSbellard         snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
951f8b2f202SRichard Henderson     } else {
952ac56dd48Spbrook         snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
953c896fe29Sbellard     }
954c896fe29Sbellard     return buf;
955c896fe29Sbellard }
956c896fe29Sbellard 
957f8b2f202SRichard Henderson static char *tcg_get_arg_str_idx(TCGContext *s, char *buf,
958f8b2f202SRichard Henderson                                  int buf_size, int idx)
959f8b2f202SRichard Henderson {
960eabb7b91SAurelien Jarno     tcg_debug_assert(idx >= 0 && idx < s->nb_temps);
961f8b2f202SRichard Henderson     return tcg_get_arg_str_ptr(s, buf, buf_size, &s->temps[idx]);
962f8b2f202SRichard Henderson }
963f8b2f202SRichard Henderson 
9646e085f72SRichard Henderson /* Find helper name.  */
9656e085f72SRichard Henderson static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val)
966e8996ee0Sbellard {
9676e085f72SRichard Henderson     const char *ret = NULL;
9686e085f72SRichard Henderson     if (s->helpers) {
96972866e82SRichard Henderson         TCGHelperInfo *info = g_hash_table_lookup(s->helpers, (gpointer)val);
97072866e82SRichard Henderson         if (info) {
97172866e82SRichard Henderson             ret = info->name;
97272866e82SRichard Henderson         }
973e8996ee0Sbellard     }
9746e085f72SRichard Henderson     return ret;
9754dc81f28Sbellard }
9764dc81f28Sbellard 
977f48f3edeSblueswir1 static const char * const cond_name[] =
978f48f3edeSblueswir1 {
9790aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
9800aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
981f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
982f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
983f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
984f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
985f48f3edeSblueswir1     [TCG_COND_LE] = "le",
986f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
987f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
988f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
989f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
990f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
991f48f3edeSblueswir1 };
992f48f3edeSblueswir1 
993f713d6adSRichard Henderson static const char * const ldst_name[] =
994f713d6adSRichard Henderson {
995f713d6adSRichard Henderson     [MO_UB]   = "ub",
996f713d6adSRichard Henderson     [MO_SB]   = "sb",
997f713d6adSRichard Henderson     [MO_LEUW] = "leuw",
998f713d6adSRichard Henderson     [MO_LESW] = "lesw",
999f713d6adSRichard Henderson     [MO_LEUL] = "leul",
1000f713d6adSRichard Henderson     [MO_LESL] = "lesl",
1001f713d6adSRichard Henderson     [MO_LEQ]  = "leq",
1002f713d6adSRichard Henderson     [MO_BEUW] = "beuw",
1003f713d6adSRichard Henderson     [MO_BESW] = "besw",
1004f713d6adSRichard Henderson     [MO_BEUL] = "beul",
1005f713d6adSRichard Henderson     [MO_BESL] = "besl",
1006f713d6adSRichard Henderson     [MO_BEQ]  = "beq",
1007f713d6adSRichard Henderson };
1008f713d6adSRichard Henderson 
10091f00b27fSSergey Sorokin static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
10101f00b27fSSergey Sorokin #ifdef ALIGNED_ONLY
10111f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "un+",
10121f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "",
10131f00b27fSSergey Sorokin #else
10141f00b27fSSergey Sorokin     [MO_UNALN >> MO_ASHIFT]    = "",
10151f00b27fSSergey Sorokin     [MO_ALIGN >> MO_ASHIFT]    = "al+",
10161f00b27fSSergey Sorokin #endif
10171f00b27fSSergey Sorokin     [MO_ALIGN_2 >> MO_ASHIFT]  = "al2+",
10181f00b27fSSergey Sorokin     [MO_ALIGN_4 >> MO_ASHIFT]  = "al4+",
10191f00b27fSSergey Sorokin     [MO_ALIGN_8 >> MO_ASHIFT]  = "al8+",
10201f00b27fSSergey Sorokin     [MO_ALIGN_16 >> MO_ASHIFT] = "al16+",
10211f00b27fSSergey Sorokin     [MO_ALIGN_32 >> MO_ASHIFT] = "al32+",
10221f00b27fSSergey Sorokin     [MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
10231f00b27fSSergey Sorokin };
10241f00b27fSSergey Sorokin 
1025eeacee4dSBlue Swirl void tcg_dump_ops(TCGContext *s)
1026c896fe29Sbellard {
1027c896fe29Sbellard     char buf[128];
1028c45cb8bbSRichard Henderson     TCGOp *op;
1029c45cb8bbSRichard Henderson     int oi;
1030c896fe29Sbellard 
1031dcb8e758SRichard Henderson     for (oi = s->gen_op_buf[0].next; oi != 0; oi = op->next) {
1032c45cb8bbSRichard Henderson         int i, k, nb_oargs, nb_iargs, nb_cargs;
1033c45cb8bbSRichard Henderson         const TCGOpDef *def;
1034c45cb8bbSRichard Henderson         const TCGArg *args;
1035c45cb8bbSRichard Henderson         TCGOpcode c;
1036bdfb460eSRichard Henderson         int col = 0;
1037c45cb8bbSRichard Henderson 
1038c45cb8bbSRichard Henderson         op = &s->gen_op_buf[oi];
1039c45cb8bbSRichard Henderson         c = op->opc;
1040c896fe29Sbellard         def = &tcg_op_defs[c];
1041c45cb8bbSRichard Henderson         args = &s->gen_opparam_buf[op->args];
1042c45cb8bbSRichard Henderson 
1043765b842aSRichard Henderson         if (c == INDEX_op_insn_start) {
1044bdfb460eSRichard Henderson             col += qemu_log("%s ----", oi != s->gen_op_buf[0].next ? "\n" : "");
10459aef40edSRichard Henderson 
10469aef40edSRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
10479aef40edSRichard Henderson                 target_ulong a;
10487e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
10499aef40edSRichard Henderson                 a = ((target_ulong)args[i * 2 + 1] << 32) | args[i * 2];
10507e4597d7Sbellard #else
10519aef40edSRichard Henderson                 a = args[i];
10527e4597d7Sbellard #endif
1053bdfb460eSRichard Henderson                 col += qemu_log(" " TARGET_FMT_lx, a);
1054eeacee4dSBlue Swirl             }
10557e4597d7Sbellard         } else if (c == INDEX_op_call) {
1056c896fe29Sbellard             /* variable number of arguments */
1057c45cb8bbSRichard Henderson             nb_oargs = op->callo;
1058c45cb8bbSRichard Henderson             nb_iargs = op->calli;
1059c896fe29Sbellard             nb_cargs = def->nb_cargs;
1060b03cce8eSbellard 
1061cf066674SRichard Henderson             /* function name, flags, out args */
1062bdfb460eSRichard Henderson             col += qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name,
1063cf066674SRichard Henderson                             tcg_find_helper(s, args[nb_oargs + nb_iargs]),
1064cf066674SRichard Henderson                             args[nb_oargs + nb_iargs + 1], nb_oargs);
1065b03cce8eSbellard             for (i = 0; i < nb_oargs; i++) {
1066bdfb460eSRichard Henderson                 col += qemu_log(",%s", tcg_get_arg_str_idx(s, buf, sizeof(buf),
1067eeacee4dSBlue Swirl                                                            args[i]));
1068b03cce8eSbellard             }
1069cf066674SRichard Henderson             for (i = 0; i < nb_iargs; i++) {
1070cf066674SRichard Henderson                 TCGArg arg = args[nb_oargs + i];
1071cf066674SRichard Henderson                 const char *t = "<dummy>";
1072cf066674SRichard Henderson                 if (arg != TCG_CALL_DUMMY_ARG) {
1073cf066674SRichard Henderson                     t = tcg_get_arg_str_idx(s, buf, sizeof(buf), arg);
1074b03cce8eSbellard                 }
1075bdfb460eSRichard Henderson                 col += qemu_log(",%s", t);
1076e8996ee0Sbellard             }
1077b03cce8eSbellard         } else {
1078bdfb460eSRichard Henderson             col += qemu_log(" %s ", def->name);
1079c45cb8bbSRichard Henderson 
1080c896fe29Sbellard             nb_oargs = def->nb_oargs;
1081c896fe29Sbellard             nb_iargs = def->nb_iargs;
1082c896fe29Sbellard             nb_cargs = def->nb_cargs;
1083c896fe29Sbellard 
1084c896fe29Sbellard             k = 0;
1085c896fe29Sbellard             for (i = 0; i < nb_oargs; i++) {
1086eeacee4dSBlue Swirl                 if (k != 0) {
1087bdfb460eSRichard Henderson                     col += qemu_log(",");
1088eeacee4dSBlue Swirl                 }
1089bdfb460eSRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf),
1090eeacee4dSBlue Swirl                                                           args[k++]));
1091c896fe29Sbellard             }
1092c896fe29Sbellard             for (i = 0; i < nb_iargs; i++) {
1093eeacee4dSBlue Swirl                 if (k != 0) {
1094bdfb460eSRichard Henderson                     col += qemu_log(",");
1095eeacee4dSBlue Swirl                 }
1096bdfb460eSRichard Henderson                 col += qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf),
1097eeacee4dSBlue Swirl                                                           args[k++]));
1098c896fe29Sbellard             }
1099be210acbSRichard Henderson             switch (c) {
1100be210acbSRichard Henderson             case INDEX_op_brcond_i32:
1101ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
1102ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
1103be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
1104be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
1105ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
1106be210acbSRichard Henderson             case INDEX_op_setcond_i64:
1107ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
1108eeacee4dSBlue Swirl                 if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]]) {
1109bdfb460eSRichard Henderson                     col += qemu_log(",%s", cond_name[args[k++]]);
1110eeacee4dSBlue Swirl                 } else {
1111bdfb460eSRichard Henderson                     col += qemu_log(",$0x%" TCG_PRIlx, args[k++]);
1112eeacee4dSBlue Swirl                 }
1113f48f3edeSblueswir1                 i = 1;
1114be210acbSRichard Henderson                 break;
1115f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i32:
1116f713d6adSRichard Henderson             case INDEX_op_qemu_st_i32:
1117f713d6adSRichard Henderson             case INDEX_op_qemu_ld_i64:
1118f713d6adSRichard Henderson             case INDEX_op_qemu_st_i64:
111959227d5dSRichard Henderson                 {
112059227d5dSRichard Henderson                     TCGMemOpIdx oi = args[k++];
112159227d5dSRichard Henderson                     TCGMemOp op = get_memop(oi);
112259227d5dSRichard Henderson                     unsigned ix = get_mmuidx(oi);
112359227d5dSRichard Henderson 
112459c4b7e8SRichard Henderson                     if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
1125bdfb460eSRichard Henderson                         col += qemu_log(",$0x%x,%u", op, ix);
112659c4b7e8SRichard Henderson                     } else {
11271f00b27fSSergey Sorokin                         const char *s_al, *s_op;
11281f00b27fSSergey Sorokin                         s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
112959c4b7e8SRichard Henderson                         s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
1130bdfb460eSRichard Henderson                         col += qemu_log(",%s%s,%u", s_al, s_op, ix);
1131f713d6adSRichard Henderson                     }
1132f713d6adSRichard Henderson                     i = 1;
113359227d5dSRichard Henderson                 }
1134f713d6adSRichard Henderson                 break;
1135be210acbSRichard Henderson             default:
1136f48f3edeSblueswir1                 i = 0;
1137be210acbSRichard Henderson                 break;
1138be210acbSRichard Henderson             }
113951e3972cSRichard Henderson             switch (c) {
114051e3972cSRichard Henderson             case INDEX_op_set_label:
114151e3972cSRichard Henderson             case INDEX_op_br:
114251e3972cSRichard Henderson             case INDEX_op_brcond_i32:
114351e3972cSRichard Henderson             case INDEX_op_brcond_i64:
114451e3972cSRichard Henderson             case INDEX_op_brcond2_i32:
1145bdfb460eSRichard Henderson                 col += qemu_log("%s$L%d", k ? "," : "", arg_label(args[k])->id);
114651e3972cSRichard Henderson                 i++, k++;
114751e3972cSRichard Henderson                 break;
114851e3972cSRichard Henderson             default:
114951e3972cSRichard Henderson                 break;
1150eeacee4dSBlue Swirl             }
115151e3972cSRichard Henderson             for (; i < nb_cargs; i++, k++) {
1152bdfb460eSRichard Henderson                 col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", args[k]);
1153bdfb460eSRichard Henderson             }
1154bdfb460eSRichard Henderson         }
1155bdfb460eSRichard Henderson         if (op->life) {
1156bdfb460eSRichard Henderson             unsigned life = op->life;
1157bdfb460eSRichard Henderson 
1158bdfb460eSRichard Henderson             for (; col < 48; ++col) {
1159bdfb460eSRichard Henderson                 putc(' ', qemu_logfile);
1160bdfb460eSRichard Henderson             }
1161bdfb460eSRichard Henderson 
1162bdfb460eSRichard Henderson             if (life & (SYNC_ARG * 3)) {
1163bdfb460eSRichard Henderson                 qemu_log("  sync:");
1164bdfb460eSRichard Henderson                 for (i = 0; i < 2; ++i) {
1165bdfb460eSRichard Henderson                     if (life & (SYNC_ARG << i)) {
1166bdfb460eSRichard Henderson                         qemu_log(" %d", i);
1167bdfb460eSRichard Henderson                     }
1168bdfb460eSRichard Henderson                 }
1169bdfb460eSRichard Henderson             }
1170bdfb460eSRichard Henderson             life /= DEAD_ARG;
1171bdfb460eSRichard Henderson             if (life) {
1172bdfb460eSRichard Henderson                 qemu_log("  dead:");
1173bdfb460eSRichard Henderson                 for (i = 0; life; ++i, life >>= 1) {
1174bdfb460eSRichard Henderson                     if (life & 1) {
1175bdfb460eSRichard Henderson                         qemu_log(" %d", i);
1176bdfb460eSRichard Henderson                     }
1177bdfb460eSRichard Henderson                 }
1178c896fe29Sbellard             }
1179b03cce8eSbellard         }
1180eeacee4dSBlue Swirl         qemu_log("\n");
1181c896fe29Sbellard     }
1182c896fe29Sbellard }
1183c896fe29Sbellard 
1184c896fe29Sbellard /* we give more priority to constraints with less registers */
1185c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
1186c896fe29Sbellard {
1187c896fe29Sbellard     const TCGArgConstraint *arg_ct;
1188c896fe29Sbellard 
1189c896fe29Sbellard     int i, n;
1190c896fe29Sbellard     arg_ct = &def->args_ct[k];
1191c896fe29Sbellard     if (arg_ct->ct & TCG_CT_ALIAS) {
1192c896fe29Sbellard         /* an alias is equivalent to a single register */
1193c896fe29Sbellard         n = 1;
1194c896fe29Sbellard     } else {
1195c896fe29Sbellard         if (!(arg_ct->ct & TCG_CT_REG))
1196c896fe29Sbellard             return 0;
1197c896fe29Sbellard         n = 0;
1198c896fe29Sbellard         for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
1199c896fe29Sbellard             if (tcg_regset_test_reg(arg_ct->u.regs, i))
1200c896fe29Sbellard                 n++;
1201c896fe29Sbellard         }
1202c896fe29Sbellard     }
1203c896fe29Sbellard     return TCG_TARGET_NB_REGS - n + 1;
1204c896fe29Sbellard }
1205c896fe29Sbellard 
1206c896fe29Sbellard /* sort from highest priority to lowest */
1207c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
1208c896fe29Sbellard {
1209c896fe29Sbellard     int i, j, p1, p2, tmp;
1210c896fe29Sbellard 
1211c896fe29Sbellard     for(i = 0; i < n; i++)
1212c896fe29Sbellard         def->sorted_args[start + i] = start + i;
1213c896fe29Sbellard     if (n <= 1)
1214c896fe29Sbellard         return;
1215c896fe29Sbellard     for(i = 0; i < n - 1; i++) {
1216c896fe29Sbellard         for(j = i + 1; j < n; j++) {
1217c896fe29Sbellard             p1 = get_constraint_priority(def, def->sorted_args[start + i]);
1218c896fe29Sbellard             p2 = get_constraint_priority(def, def->sorted_args[start + j]);
1219c896fe29Sbellard             if (p1 < p2) {
1220c896fe29Sbellard                 tmp = def->sorted_args[start + i];
1221c896fe29Sbellard                 def->sorted_args[start + i] = def->sorted_args[start + j];
1222c896fe29Sbellard                 def->sorted_args[start + j] = tmp;
1223c896fe29Sbellard             }
1224c896fe29Sbellard         }
1225c896fe29Sbellard     }
1226c896fe29Sbellard }
1227c896fe29Sbellard 
1228f69d277eSRichard Henderson static void process_op_defs(TCGContext *s)
1229c896fe29Sbellard {
1230a9751609SRichard Henderson     TCGOpcode op;
1231c896fe29Sbellard 
1232f69d277eSRichard Henderson     for (op = 0; op < NB_OPS; op++) {
1233f69d277eSRichard Henderson         TCGOpDef *def = &tcg_op_defs[op];
1234f69d277eSRichard Henderson         const TCGTargetOpDef *tdefs;
1235*069ea736SRichard Henderson         TCGType type;
1236*069ea736SRichard Henderson         int i, nb_args;
1237f69d277eSRichard Henderson 
1238f69d277eSRichard Henderson         if (def->flags & TCG_OPF_NOT_PRESENT) {
1239f69d277eSRichard Henderson             continue;
1240f69d277eSRichard Henderson         }
1241f69d277eSRichard Henderson 
1242c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
1243f69d277eSRichard Henderson         if (nb_args == 0) {
1244f69d277eSRichard Henderson             continue;
1245f69d277eSRichard Henderson         }
1246f69d277eSRichard Henderson 
1247f69d277eSRichard Henderson         tdefs = tcg_target_op_def(op);
1248f69d277eSRichard Henderson         /* Missing TCGTargetOpDef entry. */
1249f69d277eSRichard Henderson         tcg_debug_assert(tdefs != NULL);
1250f69d277eSRichard Henderson 
1251*069ea736SRichard Henderson         type = (def->flags & TCG_OPF_64BIT ? TCG_TYPE_I64 : TCG_TYPE_I32);
1252c896fe29Sbellard         for (i = 0; i < nb_args; i++) {
1253f69d277eSRichard Henderson             const char *ct_str = tdefs->args_ct_str[i];
1254f69d277eSRichard Henderson             /* Incomplete TCGTargetOpDef entry. */
1255eabb7b91SAurelien Jarno             tcg_debug_assert(ct_str != NULL);
1256f69d277eSRichard Henderson 
1257c896fe29Sbellard             tcg_regset_clear(def->args_ct[i].u.regs);
1258c896fe29Sbellard             def->args_ct[i].ct = 0;
1259c896fe29Sbellard             if (ct_str[0] >= '0' && ct_str[0] <= '9') {
1260c896fe29Sbellard                 int oarg;
1261c896fe29Sbellard                 oarg = ct_str[0] - '0';
1262eabb7b91SAurelien Jarno                 tcg_debug_assert(oarg < def->nb_oargs);
1263eabb7b91SAurelien Jarno                 tcg_debug_assert(def->args_ct[oarg].ct & TCG_CT_REG);
1264c896fe29Sbellard                 /* TCG_CT_ALIAS is for the output arguments. The input
12655ff9d6a4Sbellard                    argument is tagged with TCG_CT_IALIAS. */
1266c896fe29Sbellard                 def->args_ct[i] = def->args_ct[oarg];
12675ff9d6a4Sbellard                 def->args_ct[oarg].ct = TCG_CT_ALIAS;
12685ff9d6a4Sbellard                 def->args_ct[oarg].alias_index = i;
1269c896fe29Sbellard                 def->args_ct[i].ct |= TCG_CT_IALIAS;
12705ff9d6a4Sbellard                 def->args_ct[i].alias_index = oarg;
1271c896fe29Sbellard             } else {
1272c896fe29Sbellard                 for(;;) {
1273c896fe29Sbellard                     if (*ct_str == '\0')
1274c896fe29Sbellard                         break;
1275c896fe29Sbellard                     switch(*ct_str) {
127682790a87SRichard Henderson                     case '&':
127782790a87SRichard Henderson                         def->args_ct[i].ct |= TCG_CT_NEWREG;
127882790a87SRichard Henderson                         ct_str++;
127982790a87SRichard Henderson                         break;
1280c896fe29Sbellard                     case 'i':
1281c896fe29Sbellard                         def->args_ct[i].ct |= TCG_CT_CONST;
1282c896fe29Sbellard                         ct_str++;
1283c896fe29Sbellard                         break;
1284c896fe29Sbellard                     default:
1285*069ea736SRichard Henderson                         ct_str = target_parse_constraint(&def->args_ct[i],
1286*069ea736SRichard Henderson                                                          ct_str, type);
1287f69d277eSRichard Henderson                         /* Typo in TCGTargetOpDef constraint. */
1288*069ea736SRichard Henderson                         tcg_debug_assert(ct_str != NULL);
1289c896fe29Sbellard                     }
1290c896fe29Sbellard                 }
1291c896fe29Sbellard             }
1292c896fe29Sbellard         }
1293c896fe29Sbellard 
1294c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
1295eabb7b91SAurelien Jarno         tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
1296c68aaa18SStefan Weil 
1297c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
1298c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
1299c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
1300c896fe29Sbellard     }
1301c896fe29Sbellard }
1302c896fe29Sbellard 
13030c627cdcSRichard Henderson void tcg_op_remove(TCGContext *s, TCGOp *op)
13040c627cdcSRichard Henderson {
13050c627cdcSRichard Henderson     int next = op->next;
13060c627cdcSRichard Henderson     int prev = op->prev;
13070c627cdcSRichard Henderson 
1308dcb8e758SRichard Henderson     /* We should never attempt to remove the list terminator.  */
1309dcb8e758SRichard Henderson     tcg_debug_assert(op != &s->gen_op_buf[0]);
13100c627cdcSRichard Henderson 
1311dcb8e758SRichard Henderson     s->gen_op_buf[next].prev = prev;
1312dcb8e758SRichard Henderson     s->gen_op_buf[prev].next = next;
1313dcb8e758SRichard Henderson 
1314dcb8e758SRichard Henderson     memset(op, 0, sizeof(*op));
13150c627cdcSRichard Henderson 
13160c627cdcSRichard Henderson #ifdef CONFIG_PROFILER
13170c627cdcSRichard Henderson     s->del_op_count++;
13180c627cdcSRichard Henderson #endif
13190c627cdcSRichard Henderson }
13200c627cdcSRichard Henderson 
13215a18407fSRichard Henderson TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op,
13225a18407fSRichard Henderson                             TCGOpcode opc, int nargs)
13235a18407fSRichard Henderson {
13245a18407fSRichard Henderson     int oi = s->gen_next_op_idx;
13255a18407fSRichard Henderson     int pi = s->gen_next_parm_idx;
13265a18407fSRichard Henderson     int prev = old_op->prev;
13275a18407fSRichard Henderson     int next = old_op - s->gen_op_buf;
13285a18407fSRichard Henderson     TCGOp *new_op;
13295a18407fSRichard Henderson 
13305a18407fSRichard Henderson     tcg_debug_assert(oi < OPC_BUF_SIZE);
13315a18407fSRichard Henderson     tcg_debug_assert(pi + nargs <= OPPARAM_BUF_SIZE);
13325a18407fSRichard Henderson     s->gen_next_op_idx = oi + 1;
13335a18407fSRichard Henderson     s->gen_next_parm_idx = pi + nargs;
13345a18407fSRichard Henderson 
13355a18407fSRichard Henderson     new_op = &s->gen_op_buf[oi];
13365a18407fSRichard Henderson     *new_op = (TCGOp){
13375a18407fSRichard Henderson         .opc = opc,
13385a18407fSRichard Henderson         .args = pi,
13395a18407fSRichard Henderson         .prev = prev,
13405a18407fSRichard Henderson         .next = next
13415a18407fSRichard Henderson     };
13425a18407fSRichard Henderson     s->gen_op_buf[prev].next = oi;
13435a18407fSRichard Henderson     old_op->prev = oi;
13445a18407fSRichard Henderson 
13455a18407fSRichard Henderson     return new_op;
13465a18407fSRichard Henderson }
13475a18407fSRichard Henderson 
13485a18407fSRichard Henderson TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op,
13495a18407fSRichard Henderson                            TCGOpcode opc, int nargs)
13505a18407fSRichard Henderson {
13515a18407fSRichard Henderson     int oi = s->gen_next_op_idx;
13525a18407fSRichard Henderson     int pi = s->gen_next_parm_idx;
13535a18407fSRichard Henderson     int prev = old_op - s->gen_op_buf;
13545a18407fSRichard Henderson     int next = old_op->next;
13555a18407fSRichard Henderson     TCGOp *new_op;
13565a18407fSRichard Henderson 
13575a18407fSRichard Henderson     tcg_debug_assert(oi < OPC_BUF_SIZE);
13585a18407fSRichard Henderson     tcg_debug_assert(pi + nargs <= OPPARAM_BUF_SIZE);
13595a18407fSRichard Henderson     s->gen_next_op_idx = oi + 1;
13605a18407fSRichard Henderson     s->gen_next_parm_idx = pi + nargs;
13615a18407fSRichard Henderson 
13625a18407fSRichard Henderson     new_op = &s->gen_op_buf[oi];
13635a18407fSRichard Henderson     *new_op = (TCGOp){
13645a18407fSRichard Henderson         .opc = opc,
13655a18407fSRichard Henderson         .args = pi,
13665a18407fSRichard Henderson         .prev = prev,
13675a18407fSRichard Henderson         .next = next
13685a18407fSRichard Henderson     };
13695a18407fSRichard Henderson     s->gen_op_buf[next].prev = oi;
13705a18407fSRichard Henderson     old_op->next = oi;
13715a18407fSRichard Henderson 
13725a18407fSRichard Henderson     return new_op;
13735a18407fSRichard Henderson }
13745a18407fSRichard Henderson 
1375c70fbf0aSRichard Henderson #define TS_DEAD  1
1376c70fbf0aSRichard Henderson #define TS_MEM   2
1377c70fbf0aSRichard Henderson 
13785a18407fSRichard Henderson #define IS_DEAD_ARG(n)   (arg_life & (DEAD_ARG << (n)))
13795a18407fSRichard Henderson #define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
13805a18407fSRichard Henderson 
13819c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
13829c43b68dSAurelien Jarno    should be in memory. */
1383c70fbf0aSRichard Henderson static inline void tcg_la_func_end(TCGContext *s, uint8_t *temp_state)
1384c896fe29Sbellard {
1385c70fbf0aSRichard Henderson     memset(temp_state, TS_DEAD | TS_MEM, s->nb_globals);
1386c70fbf0aSRichard Henderson     memset(temp_state + s->nb_globals, TS_DEAD, s->nb_temps - s->nb_globals);
1387c896fe29Sbellard }
1388c896fe29Sbellard 
13899c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
13909c43b68dSAurelien Jarno    and local temps should be in memory. */
1391c70fbf0aSRichard Henderson static inline void tcg_la_bb_end(TCGContext *s, uint8_t *temp_state)
1392641d5fbeSbellard {
1393c70fbf0aSRichard Henderson     int i, n;
1394641d5fbeSbellard 
1395c70fbf0aSRichard Henderson     tcg_la_func_end(s, temp_state);
1396c70fbf0aSRichard Henderson     for (i = s->nb_globals, n = s->nb_temps; i < n; i++) {
1397c70fbf0aSRichard Henderson         if (s->temps[i].temp_local) {
1398c70fbf0aSRichard Henderson             temp_state[i] |= TS_MEM;
1399c70fbf0aSRichard Henderson         }
1400641d5fbeSbellard     }
1401641d5fbeSbellard }
1402641d5fbeSbellard 
1403a1b3c48dSRichard Henderson /* Liveness analysis : update the opc_arg_life array to tell if a
1404c896fe29Sbellard    given input arguments is dead. Instructions updating dead
1405c896fe29Sbellard    temporaries are removed. */
14065a18407fSRichard Henderson static void liveness_pass_1(TCGContext *s, uint8_t *temp_state)
1407c896fe29Sbellard {
1408c70fbf0aSRichard Henderson     int nb_globals = s->nb_globals;
14095a18407fSRichard Henderson     int oi, oi_prev;
1410c896fe29Sbellard 
1411c70fbf0aSRichard Henderson     tcg_la_func_end(s, temp_state);
1412c896fe29Sbellard 
1413dcb8e758SRichard Henderson     for (oi = s->gen_op_buf[0].prev; oi != 0; oi = oi_prev) {
1414c45cb8bbSRichard Henderson         int i, nb_iargs, nb_oargs;
1415c45cb8bbSRichard Henderson         TCGOpcode opc_new, opc_new2;
1416c45cb8bbSRichard Henderson         bool have_opc_new2;
1417a1b3c48dSRichard Henderson         TCGLifeData arg_life = 0;
1418c45cb8bbSRichard Henderson         TCGArg arg;
1419c45cb8bbSRichard Henderson 
1420c45cb8bbSRichard Henderson         TCGOp * const op = &s->gen_op_buf[oi];
1421c45cb8bbSRichard Henderson         TCGArg * const args = &s->gen_opparam_buf[op->args];
1422c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
1423c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
1424c45cb8bbSRichard Henderson 
1425c45cb8bbSRichard Henderson         oi_prev = op->prev;
1426c45cb8bbSRichard Henderson 
1427c45cb8bbSRichard Henderson         switch (opc) {
1428c896fe29Sbellard         case INDEX_op_call:
1429c6e113f5Sbellard             {
1430c6e113f5Sbellard                 int call_flags;
1431c6e113f5Sbellard 
1432c45cb8bbSRichard Henderson                 nb_oargs = op->callo;
1433c45cb8bbSRichard Henderson                 nb_iargs = op->calli;
1434cf066674SRichard Henderson                 call_flags = args[nb_oargs + nb_iargs + 1];
1435c6e113f5Sbellard 
1436c45cb8bbSRichard Henderson                 /* pure functions can be removed if their result is unused */
143778505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
1438c6e113f5Sbellard                     for (i = 0; i < nb_oargs; i++) {
1439c6e113f5Sbellard                         arg = args[i];
1440c70fbf0aSRichard Henderson                         if (temp_state[arg] != TS_DEAD) {
1441c6e113f5Sbellard                             goto do_not_remove_call;
1442c6e113f5Sbellard                         }
14439c43b68dSAurelien Jarno                     }
1444c45cb8bbSRichard Henderson                     goto do_remove;
1445c6e113f5Sbellard                 } else {
1446c6e113f5Sbellard                 do_not_remove_call:
1447c896fe29Sbellard 
1448c896fe29Sbellard                     /* output args are dead */
1449c896fe29Sbellard                     for (i = 0; i < nb_oargs; i++) {
1450c896fe29Sbellard                         arg = args[i];
1451c70fbf0aSRichard Henderson                         if (temp_state[arg] & TS_DEAD) {
1452a1b3c48dSRichard Henderson                             arg_life |= DEAD_ARG << i;
14536b64b624SAurelien Jarno                         }
1454c70fbf0aSRichard Henderson                         if (temp_state[arg] & TS_MEM) {
1455a1b3c48dSRichard Henderson                             arg_life |= SYNC_ARG << i;
14569c43b68dSAurelien Jarno                         }
1457c70fbf0aSRichard Henderson                         temp_state[arg] = TS_DEAD;
1458c896fe29Sbellard                     }
1459c896fe29Sbellard 
146078505279SAurelien Jarno                     if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
146178505279SAurelien Jarno                                         TCG_CALL_NO_READ_GLOBALS))) {
14629c43b68dSAurelien Jarno                         /* globals should go back to memory */
1463c70fbf0aSRichard Henderson                         memset(temp_state, TS_DEAD | TS_MEM, nb_globals);
1464c70fbf0aSRichard Henderson                     } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
1465c70fbf0aSRichard Henderson                         /* globals should be synced to memory */
1466c70fbf0aSRichard Henderson                         for (i = 0; i < nb_globals; i++) {
1467c70fbf0aSRichard Henderson                             temp_state[i] |= TS_MEM;
1468c70fbf0aSRichard Henderson                         }
1469b9c18f56Saurel32                     }
1470c896fe29Sbellard 
1471c19f47bfSAurelien Jarno                     /* record arguments that die in this helper */
1472866cb6cbSAurelien Jarno                     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
1473866cb6cbSAurelien Jarno                         arg = args[i];
147439cf05d3Sbellard                         if (arg != TCG_CALL_DUMMY_ARG) {
1475c70fbf0aSRichard Henderson                             if (temp_state[arg] & TS_DEAD) {
1476a1b3c48dSRichard Henderson                                 arg_life |= DEAD_ARG << i;
1477c896fe29Sbellard                             }
1478c896fe29Sbellard                         }
147939cf05d3Sbellard                     }
148067cc32ebSVeres Lajos                     /* input arguments are live for preceding opcodes */
1481c70fbf0aSRichard Henderson                     for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
1482c19f47bfSAurelien Jarno                         arg = args[i];
1483c70fbf0aSRichard Henderson                         if (arg != TCG_CALL_DUMMY_ARG) {
1484c70fbf0aSRichard Henderson                             temp_state[arg] &= ~TS_DEAD;
1485c70fbf0aSRichard Henderson                         }
1486c19f47bfSAurelien Jarno                     }
1487c6e113f5Sbellard                 }
1488c6e113f5Sbellard             }
1489c896fe29Sbellard             break;
1490765b842aSRichard Henderson         case INDEX_op_insn_start:
1491c896fe29Sbellard             break;
14925ff9d6a4Sbellard         case INDEX_op_discard:
14935ff9d6a4Sbellard             /* mark the temporary as dead */
1494c70fbf0aSRichard Henderson             temp_state[args[0]] = TS_DEAD;
14955ff9d6a4Sbellard             break;
14961305c451SRichard Henderson 
14971305c451SRichard Henderson         case INDEX_op_add2_i32:
1498c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i32;
1499f1fae40cSRichard Henderson             goto do_addsub2;
15001305c451SRichard Henderson         case INDEX_op_sub2_i32:
1501c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i32;
1502f1fae40cSRichard Henderson             goto do_addsub2;
1503f1fae40cSRichard Henderson         case INDEX_op_add2_i64:
1504c45cb8bbSRichard Henderson             opc_new = INDEX_op_add_i64;
1505f1fae40cSRichard Henderson             goto do_addsub2;
1506f1fae40cSRichard Henderson         case INDEX_op_sub2_i64:
1507c45cb8bbSRichard Henderson             opc_new = INDEX_op_sub_i64;
1508f1fae40cSRichard Henderson         do_addsub2:
15091305c451SRichard Henderson             nb_iargs = 4;
15101305c451SRichard Henderson             nb_oargs = 2;
15111305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
15121305c451SRichard Henderson                the low part.  The result can be optimized to a simple
15131305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
15141305c451SRichard Henderson                cpu mode is set to 32 bit.  */
1515c70fbf0aSRichard Henderson             if (temp_state[args[1]] == TS_DEAD) {
1516c70fbf0aSRichard Henderson                 if (temp_state[args[0]] == TS_DEAD) {
15171305c451SRichard Henderson                     goto do_remove;
15181305c451SRichard Henderson                 }
1519c45cb8bbSRichard Henderson                 /* Replace the opcode and adjust the args in place,
1520c45cb8bbSRichard Henderson                    leaving 3 unused args at the end.  */
1521c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
15221305c451SRichard Henderson                 args[1] = args[2];
15231305c451SRichard Henderson                 args[2] = args[4];
15241305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
15251305c451SRichard Henderson                 nb_iargs = 2;
15261305c451SRichard Henderson                 nb_oargs = 1;
15271305c451SRichard Henderson             }
15281305c451SRichard Henderson             goto do_not_remove;
15291305c451SRichard Henderson 
15301414968aSRichard Henderson         case INDEX_op_mulu2_i32:
1531c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
1532c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i32;
1533c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i32;
153403271524SRichard Henderson             goto do_mul2;
1535f1fae40cSRichard Henderson         case INDEX_op_muls2_i32:
1536c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i32;
1537c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i32;
1538c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i32;
1539f1fae40cSRichard Henderson             goto do_mul2;
1540f1fae40cSRichard Henderson         case INDEX_op_mulu2_i64:
1541c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
1542c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_muluh_i64;
1543c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_muluh_i64;
154403271524SRichard Henderson             goto do_mul2;
1545f1fae40cSRichard Henderson         case INDEX_op_muls2_i64:
1546c45cb8bbSRichard Henderson             opc_new = INDEX_op_mul_i64;
1547c45cb8bbSRichard Henderson             opc_new2 = INDEX_op_mulsh_i64;
1548c45cb8bbSRichard Henderson             have_opc_new2 = TCG_TARGET_HAS_mulsh_i64;
154903271524SRichard Henderson             goto do_mul2;
1550f1fae40cSRichard Henderson         do_mul2:
15511414968aSRichard Henderson             nb_iargs = 2;
15521414968aSRichard Henderson             nb_oargs = 2;
1553c70fbf0aSRichard Henderson             if (temp_state[args[1]] == TS_DEAD) {
1554c70fbf0aSRichard Henderson                 if (temp_state[args[0]] == TS_DEAD) {
155503271524SRichard Henderson                     /* Both parts of the operation are dead.  */
15561414968aSRichard Henderson                     goto do_remove;
15571414968aSRichard Henderson                 }
155803271524SRichard Henderson                 /* The high part of the operation is dead; generate the low. */
1559c45cb8bbSRichard Henderson                 op->opc = opc = opc_new;
15601414968aSRichard Henderson                 args[1] = args[2];
15611414968aSRichard Henderson                 args[2] = args[3];
1562c70fbf0aSRichard Henderson             } else if (temp_state[args[0]] == TS_DEAD && have_opc_new2) {
156303271524SRichard Henderson                 /* The low part of the operation is dead; generate the high. */
1564c45cb8bbSRichard Henderson                 op->opc = opc = opc_new2;
156503271524SRichard Henderson                 args[0] = args[1];
156603271524SRichard Henderson                 args[1] = args[2];
156703271524SRichard Henderson                 args[2] = args[3];
156803271524SRichard Henderson             } else {
156903271524SRichard Henderson                 goto do_not_remove;
157003271524SRichard Henderson             }
157103271524SRichard Henderson             /* Mark the single-word operation live.  */
15721414968aSRichard Henderson             nb_oargs = 1;
15731414968aSRichard Henderson             goto do_not_remove;
15741414968aSRichard Henderson 
1575c896fe29Sbellard         default:
15761305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1577c896fe29Sbellard             nb_iargs = def->nb_iargs;
1578c896fe29Sbellard             nb_oargs = def->nb_oargs;
1579c896fe29Sbellard 
1580c896fe29Sbellard             /* Test if the operation can be removed because all
15815ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
15825ff9d6a4Sbellard                implies side effects */
15835ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
1584c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
1585c70fbf0aSRichard Henderson                     if (temp_state[args[i]] != TS_DEAD) {
1586c896fe29Sbellard                         goto do_not_remove;
1587c896fe29Sbellard                     }
15889c43b68dSAurelien Jarno                 }
15891305c451SRichard Henderson             do_remove:
15900c627cdcSRichard Henderson                 tcg_op_remove(s, op);
1591c896fe29Sbellard             } else {
1592c896fe29Sbellard             do_not_remove:
1593c896fe29Sbellard                 /* output args are dead */
1594c896fe29Sbellard                 for (i = 0; i < nb_oargs; i++) {
1595c896fe29Sbellard                     arg = args[i];
1596c70fbf0aSRichard Henderson                     if (temp_state[arg] & TS_DEAD) {
1597a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
15986b64b624SAurelien Jarno                     }
1599c70fbf0aSRichard Henderson                     if (temp_state[arg] & TS_MEM) {
1600a1b3c48dSRichard Henderson                         arg_life |= SYNC_ARG << i;
16019c43b68dSAurelien Jarno                     }
1602c70fbf0aSRichard Henderson                     temp_state[arg] = TS_DEAD;
1603c896fe29Sbellard                 }
1604c896fe29Sbellard 
1605c896fe29Sbellard                 /* if end of basic block, update */
1606c896fe29Sbellard                 if (def->flags & TCG_OPF_BB_END) {
1607c70fbf0aSRichard Henderson                     tcg_la_bb_end(s, temp_state);
16083d5c5f87SAurelien Jarno                 } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
16093d5c5f87SAurelien Jarno                     /* globals should be synced to memory */
1610c70fbf0aSRichard Henderson                     for (i = 0; i < nb_globals; i++) {
1611c70fbf0aSRichard Henderson                         temp_state[i] |= TS_MEM;
1612c70fbf0aSRichard Henderson                     }
1613c896fe29Sbellard                 }
1614c896fe29Sbellard 
1615c19f47bfSAurelien Jarno                 /* record arguments that die in this opcode */
1616866cb6cbSAurelien Jarno                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
1617866cb6cbSAurelien Jarno                     arg = args[i];
1618c70fbf0aSRichard Henderson                     if (temp_state[arg] & TS_DEAD) {
1619a1b3c48dSRichard Henderson                         arg_life |= DEAD_ARG << i;
1620c896fe29Sbellard                     }
1621c19f47bfSAurelien Jarno                 }
162267cc32ebSVeres Lajos                 /* input arguments are live for preceding opcodes */
1623c19f47bfSAurelien Jarno                 for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
1624c70fbf0aSRichard Henderson                     temp_state[args[i]] &= ~TS_DEAD;
1625c896fe29Sbellard                 }
1626c896fe29Sbellard             }
1627c896fe29Sbellard             break;
1628c896fe29Sbellard         }
1629bee158cbSRichard Henderson         op->life = arg_life;
1630c896fe29Sbellard     }
16311ff0a2c5SEvgeny Voevodin }
1632c896fe29Sbellard 
16335a18407fSRichard Henderson /* Liveness analysis: Convert indirect regs to direct temporaries.  */
16345a18407fSRichard Henderson static bool liveness_pass_2(TCGContext *s, uint8_t *temp_state)
16355a18407fSRichard Henderson {
16365a18407fSRichard Henderson     int nb_globals = s->nb_globals;
16375a18407fSRichard Henderson     int16_t *dir_temps;
16385a18407fSRichard Henderson     int i, oi, oi_next;
16395a18407fSRichard Henderson     bool changes = false;
16405a18407fSRichard Henderson 
16415a18407fSRichard Henderson     dir_temps = tcg_malloc(nb_globals * sizeof(int16_t));
16425a18407fSRichard Henderson     memset(dir_temps, 0, nb_globals * sizeof(int16_t));
16435a18407fSRichard Henderson 
16445a18407fSRichard Henderson     /* Create a temporary for each indirect global.  */
16455a18407fSRichard Henderson     for (i = 0; i < nb_globals; ++i) {
16465a18407fSRichard Henderson         TCGTemp *its = &s->temps[i];
16475a18407fSRichard Henderson         if (its->indirect_reg) {
16485a18407fSRichard Henderson             TCGTemp *dts = tcg_temp_alloc(s);
16495a18407fSRichard Henderson             dts->type = its->type;
16505a18407fSRichard Henderson             dts->base_type = its->base_type;
16515a18407fSRichard Henderson             dir_temps[i] = temp_idx(s, dts);
16525a18407fSRichard Henderson         }
16535a18407fSRichard Henderson     }
16545a18407fSRichard Henderson 
16555a18407fSRichard Henderson     memset(temp_state, TS_DEAD, nb_globals);
16565a18407fSRichard Henderson 
16575a18407fSRichard Henderson     for (oi = s->gen_op_buf[0].next; oi != 0; oi = oi_next) {
16585a18407fSRichard Henderson         TCGOp *op = &s->gen_op_buf[oi];
16595a18407fSRichard Henderson         TCGArg *args = &s->gen_opparam_buf[op->args];
16605a18407fSRichard Henderson         TCGOpcode opc = op->opc;
16615a18407fSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
16625a18407fSRichard Henderson         TCGLifeData arg_life = op->life;
16635a18407fSRichard Henderson         int nb_iargs, nb_oargs, call_flags;
16645a18407fSRichard Henderson         TCGArg arg, dir;
16655a18407fSRichard Henderson 
16665a18407fSRichard Henderson         oi_next = op->next;
16675a18407fSRichard Henderson 
16685a18407fSRichard Henderson         if (opc == INDEX_op_call) {
16695a18407fSRichard Henderson             nb_oargs = op->callo;
16705a18407fSRichard Henderson             nb_iargs = op->calli;
16715a18407fSRichard Henderson             call_flags = args[nb_oargs + nb_iargs + 1];
16725a18407fSRichard Henderson         } else {
16735a18407fSRichard Henderson             nb_iargs = def->nb_iargs;
16745a18407fSRichard Henderson             nb_oargs = def->nb_oargs;
16755a18407fSRichard Henderson 
16765a18407fSRichard Henderson             /* Set flags similar to how calls require.  */
16775a18407fSRichard Henderson             if (def->flags & TCG_OPF_BB_END) {
16785a18407fSRichard Henderson                 /* Like writing globals: save_globals */
16795a18407fSRichard Henderson                 call_flags = 0;
16805a18407fSRichard Henderson             } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
16815a18407fSRichard Henderson                 /* Like reading globals: sync_globals */
16825a18407fSRichard Henderson                 call_flags = TCG_CALL_NO_WRITE_GLOBALS;
16835a18407fSRichard Henderson             } else {
16845a18407fSRichard Henderson                 /* No effect on globals.  */
16855a18407fSRichard Henderson                 call_flags = (TCG_CALL_NO_READ_GLOBALS |
16865a18407fSRichard Henderson                               TCG_CALL_NO_WRITE_GLOBALS);
16875a18407fSRichard Henderson             }
16885a18407fSRichard Henderson         }
16895a18407fSRichard Henderson 
16905a18407fSRichard Henderson         /* Make sure that input arguments are available.  */
16915a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
16925a18407fSRichard Henderson             arg = args[i];
16935a18407fSRichard Henderson             /* Note this unsigned test catches TCG_CALL_ARG_DUMMY too.  */
16945a18407fSRichard Henderson             if (arg < nb_globals) {
16955a18407fSRichard Henderson                 dir = dir_temps[arg];
16965a18407fSRichard Henderson                 if (dir != 0 && temp_state[arg] == TS_DEAD) {
16975a18407fSRichard Henderson                     TCGTemp *its = &s->temps[arg];
16985a18407fSRichard Henderson                     TCGOpcode lopc = (its->type == TCG_TYPE_I32
16995a18407fSRichard Henderson                                       ? INDEX_op_ld_i32
17005a18407fSRichard Henderson                                       : INDEX_op_ld_i64);
17015a18407fSRichard Henderson                     TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3);
17025a18407fSRichard Henderson                     TCGArg *largs = &s->gen_opparam_buf[lop->args];
17035a18407fSRichard Henderson 
17045a18407fSRichard Henderson                     largs[0] = dir;
17055a18407fSRichard Henderson                     largs[1] = temp_idx(s, its->mem_base);
17065a18407fSRichard Henderson                     largs[2] = its->mem_offset;
17075a18407fSRichard Henderson 
17085a18407fSRichard Henderson                     /* Loaded, but synced with memory.  */
17095a18407fSRichard Henderson                     temp_state[arg] = TS_MEM;
17105a18407fSRichard Henderson                 }
17115a18407fSRichard Henderson             }
17125a18407fSRichard Henderson         }
17135a18407fSRichard Henderson 
17145a18407fSRichard Henderson         /* Perform input replacement, and mark inputs that became dead.
17155a18407fSRichard Henderson            No action is required except keeping temp_state up to date
17165a18407fSRichard Henderson            so that we reload when needed.  */
17175a18407fSRichard Henderson         for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
17185a18407fSRichard Henderson             arg = args[i];
17195a18407fSRichard Henderson             if (arg < nb_globals) {
17205a18407fSRichard Henderson                 dir = dir_temps[arg];
17215a18407fSRichard Henderson                 if (dir != 0) {
17225a18407fSRichard Henderson                     args[i] = dir;
17235a18407fSRichard Henderson                     changes = true;
17245a18407fSRichard Henderson                     if (IS_DEAD_ARG(i)) {
17255a18407fSRichard Henderson                         temp_state[arg] = TS_DEAD;
17265a18407fSRichard Henderson                     }
17275a18407fSRichard Henderson                 }
17285a18407fSRichard Henderson             }
17295a18407fSRichard Henderson         }
17305a18407fSRichard Henderson 
17315a18407fSRichard Henderson         /* Liveness analysis should ensure that the following are
17325a18407fSRichard Henderson            all correct, for call sites and basic block end points.  */
17335a18407fSRichard Henderson         if (call_flags & TCG_CALL_NO_READ_GLOBALS) {
17345a18407fSRichard Henderson             /* Nothing to do */
17355a18407fSRichard Henderson         } else if (call_flags & TCG_CALL_NO_WRITE_GLOBALS) {
17365a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
17375a18407fSRichard Henderson                 /* Liveness should see that globals are synced back,
17385a18407fSRichard Henderson                    that is, either TS_DEAD or TS_MEM.  */
17395a18407fSRichard Henderson                 tcg_debug_assert(dir_temps[i] == 0
17405a18407fSRichard Henderson                                  || temp_state[i] != 0);
17415a18407fSRichard Henderson             }
17425a18407fSRichard Henderson         } else {
17435a18407fSRichard Henderson             for (i = 0; i < nb_globals; ++i) {
17445a18407fSRichard Henderson                 /* Liveness should see that globals are saved back,
17455a18407fSRichard Henderson                    that is, TS_DEAD, waiting to be reloaded.  */
17465a18407fSRichard Henderson                 tcg_debug_assert(dir_temps[i] == 0
17475a18407fSRichard Henderson                                  || temp_state[i] == TS_DEAD);
17485a18407fSRichard Henderson             }
17495a18407fSRichard Henderson         }
17505a18407fSRichard Henderson 
17515a18407fSRichard Henderson         /* Outputs become available.  */
17525a18407fSRichard Henderson         for (i = 0; i < nb_oargs; i++) {
17535a18407fSRichard Henderson             arg = args[i];
17545a18407fSRichard Henderson             if (arg >= nb_globals) {
17555a18407fSRichard Henderson                 continue;
17565a18407fSRichard Henderson             }
17575a18407fSRichard Henderson             dir = dir_temps[arg];
17585a18407fSRichard Henderson             if (dir == 0) {
17595a18407fSRichard Henderson                 continue;
17605a18407fSRichard Henderson             }
17615a18407fSRichard Henderson             args[i] = dir;
17625a18407fSRichard Henderson             changes = true;
17635a18407fSRichard Henderson 
17645a18407fSRichard Henderson             /* The output is now live and modified.  */
17655a18407fSRichard Henderson             temp_state[arg] = 0;
17665a18407fSRichard Henderson 
17675a18407fSRichard Henderson             /* Sync outputs upon their last write.  */
17685a18407fSRichard Henderson             if (NEED_SYNC_ARG(i)) {
17695a18407fSRichard Henderson                 TCGTemp *its = &s->temps[arg];
17705a18407fSRichard Henderson                 TCGOpcode sopc = (its->type == TCG_TYPE_I32
17715a18407fSRichard Henderson                                   ? INDEX_op_st_i32
17725a18407fSRichard Henderson                                   : INDEX_op_st_i64);
17735a18407fSRichard Henderson                 TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
17745a18407fSRichard Henderson                 TCGArg *sargs = &s->gen_opparam_buf[sop->args];
17755a18407fSRichard Henderson 
17765a18407fSRichard Henderson                 sargs[0] = dir;
17775a18407fSRichard Henderson                 sargs[1] = temp_idx(s, its->mem_base);
17785a18407fSRichard Henderson                 sargs[2] = its->mem_offset;
17795a18407fSRichard Henderson 
17805a18407fSRichard Henderson                 temp_state[arg] = TS_MEM;
17815a18407fSRichard Henderson             }
17825a18407fSRichard Henderson             /* Drop outputs that are dead.  */
17835a18407fSRichard Henderson             if (IS_DEAD_ARG(i)) {
17845a18407fSRichard Henderson                 temp_state[arg] = TS_DEAD;
17855a18407fSRichard Henderson             }
17865a18407fSRichard Henderson         }
17875a18407fSRichard Henderson     }
17885a18407fSRichard Henderson 
17895a18407fSRichard Henderson     return changes;
17905a18407fSRichard Henderson }
17915a18407fSRichard Henderson 
17928d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
1793c896fe29Sbellard static void dump_regs(TCGContext *s)
1794c896fe29Sbellard {
1795c896fe29Sbellard     TCGTemp *ts;
1796c896fe29Sbellard     int i;
1797c896fe29Sbellard     char buf[64];
1798c896fe29Sbellard 
1799c896fe29Sbellard     for(i = 0; i < s->nb_temps; i++) {
1800c896fe29Sbellard         ts = &s->temps[i];
1801ac56dd48Spbrook         printf("  %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i));
1802c896fe29Sbellard         switch(ts->val_type) {
1803c896fe29Sbellard         case TEMP_VAL_REG:
1804c896fe29Sbellard             printf("%s", tcg_target_reg_names[ts->reg]);
1805c896fe29Sbellard             break;
1806c896fe29Sbellard         case TEMP_VAL_MEM:
1807b3a62939SRichard Henderson             printf("%d(%s)", (int)ts->mem_offset,
1808b3a62939SRichard Henderson                    tcg_target_reg_names[ts->mem_base->reg]);
1809c896fe29Sbellard             break;
1810c896fe29Sbellard         case TEMP_VAL_CONST:
1811c896fe29Sbellard             printf("$0x%" TCG_PRIlx, ts->val);
1812c896fe29Sbellard             break;
1813c896fe29Sbellard         case TEMP_VAL_DEAD:
1814c896fe29Sbellard             printf("D");
1815c896fe29Sbellard             break;
1816c896fe29Sbellard         default:
1817c896fe29Sbellard             printf("???");
1818c896fe29Sbellard             break;
1819c896fe29Sbellard         }
1820c896fe29Sbellard         printf("\n");
1821c896fe29Sbellard     }
1822c896fe29Sbellard 
1823c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
1824f8b2f202SRichard Henderson         if (s->reg_to_temp[i] != NULL) {
1825c896fe29Sbellard             printf("%s: %s\n",
1826c896fe29Sbellard                    tcg_target_reg_names[i],
1827f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), s->reg_to_temp[i]));
1828c896fe29Sbellard         }
1829c896fe29Sbellard     }
1830c896fe29Sbellard }
1831c896fe29Sbellard 
1832c896fe29Sbellard static void check_regs(TCGContext *s)
1833c896fe29Sbellard {
1834869938aeSRichard Henderson     int reg;
1835b6638662SRichard Henderson     int k;
1836c896fe29Sbellard     TCGTemp *ts;
1837c896fe29Sbellard     char buf[64];
1838c896fe29Sbellard 
1839c896fe29Sbellard     for (reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1840f8b2f202SRichard Henderson         ts = s->reg_to_temp[reg];
1841f8b2f202SRichard Henderson         if (ts != NULL) {
1842f8b2f202SRichard Henderson             if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) {
1843c896fe29Sbellard                 printf("Inconsistency for register %s:\n",
1844c896fe29Sbellard                        tcg_target_reg_names[reg]);
1845b03cce8eSbellard                 goto fail;
1846c896fe29Sbellard             }
1847c896fe29Sbellard         }
1848c896fe29Sbellard     }
1849c896fe29Sbellard     for (k = 0; k < s->nb_temps; k++) {
1850c896fe29Sbellard         ts = &s->temps[k];
1851f8b2f202SRichard Henderson         if (ts->val_type == TEMP_VAL_REG && !ts->fixed_reg
1852f8b2f202SRichard Henderson             && s->reg_to_temp[ts->reg] != ts) {
1853c896fe29Sbellard             printf("Inconsistency for temp %s:\n",
1854f8b2f202SRichard Henderson                    tcg_get_arg_str_ptr(s, buf, sizeof(buf), ts));
1855b03cce8eSbellard         fail:
1856c896fe29Sbellard             printf("reg state:\n");
1857c896fe29Sbellard             dump_regs(s);
1858c896fe29Sbellard             tcg_abort();
1859c896fe29Sbellard         }
1860c896fe29Sbellard     }
1861c896fe29Sbellard }
1862c896fe29Sbellard #endif
1863c896fe29Sbellard 
1864c896fe29Sbellard static void temp_allocate_frame(TCGContext *s, int temp)
1865c896fe29Sbellard {
1866c896fe29Sbellard     TCGTemp *ts;
1867c896fe29Sbellard     ts = &s->temps[temp];
18689b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64)
18699b9c37c3SRichard Henderson     /* Sparc64 stack is accessed with offset of 2047 */
1870b591dc59SBlue Swirl     s->current_frame_offset = (s->current_frame_offset +
1871b591dc59SBlue Swirl                                (tcg_target_long)sizeof(tcg_target_long) - 1) &
1872b591dc59SBlue Swirl         ~(sizeof(tcg_target_long) - 1);
1873f44c9960SBlue Swirl #endif
1874b591dc59SBlue Swirl     if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
1875b591dc59SBlue Swirl         s->frame_end) {
18765ff9d6a4Sbellard         tcg_abort();
1877b591dc59SBlue Swirl     }
1878c896fe29Sbellard     ts->mem_offset = s->current_frame_offset;
1879b3a62939SRichard Henderson     ts->mem_base = s->frame_temp;
1880c896fe29Sbellard     ts->mem_allocated = 1;
1881e2c6d1b4SRichard Henderson     s->current_frame_offset += sizeof(tcg_target_long);
1882c896fe29Sbellard }
1883c896fe29Sbellard 
1884b3915dbbSRichard Henderson static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet);
1885b3915dbbSRichard Henderson 
188659d7c14eSRichard Henderson /* Mark a temporary as free or dead.  If 'free_or_dead' is negative,
188759d7c14eSRichard Henderson    mark it free; otherwise mark it dead.  */
188859d7c14eSRichard Henderson static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
1889c896fe29Sbellard {
189059d7c14eSRichard Henderson     if (ts->fixed_reg) {
189159d7c14eSRichard Henderson         return;
189259d7c14eSRichard Henderson     }
189359d7c14eSRichard Henderson     if (ts->val_type == TEMP_VAL_REG) {
189459d7c14eSRichard Henderson         s->reg_to_temp[ts->reg] = NULL;
189559d7c14eSRichard Henderson     }
189659d7c14eSRichard Henderson     ts->val_type = (free_or_dead < 0
189759d7c14eSRichard Henderson                     || ts->temp_local
189859d7c14eSRichard Henderson                     || temp_idx(s, ts) < s->nb_globals
189959d7c14eSRichard Henderson                     ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
190059d7c14eSRichard Henderson }
1901c896fe29Sbellard 
190259d7c14eSRichard Henderson /* Mark a temporary as dead.  */
190359d7c14eSRichard Henderson static inline void temp_dead(TCGContext *s, TCGTemp *ts)
190459d7c14eSRichard Henderson {
190559d7c14eSRichard Henderson     temp_free_or_dead(s, ts, 1);
190659d7c14eSRichard Henderson }
190759d7c14eSRichard Henderson 
190859d7c14eSRichard Henderson /* Sync a temporary to memory. 'allocated_regs' is used in case a temporary
190959d7c14eSRichard Henderson    registers needs to be allocated to store a constant.  If 'free_or_dead'
191059d7c14eSRichard Henderson    is non-zero, subsequently release the temporary; if it is positive, the
191159d7c14eSRichard Henderson    temp is dead; if it is negative, the temp is free.  */
191259d7c14eSRichard Henderson static void temp_sync(TCGContext *s, TCGTemp *ts,
191359d7c14eSRichard Henderson                       TCGRegSet allocated_regs, int free_or_dead)
191459d7c14eSRichard Henderson {
191559d7c14eSRichard Henderson     if (ts->fixed_reg) {
191659d7c14eSRichard Henderson         return;
191759d7c14eSRichard Henderson     }
191859d7c14eSRichard Henderson     if (!ts->mem_coherent) {
19197f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
1920f8b2f202SRichard Henderson             temp_allocate_frame(s, temp_idx(s, ts));
192159d7c14eSRichard Henderson         }
192259d7c14eSRichard Henderson         switch (ts->val_type) {
192359d7c14eSRichard Henderson         case TEMP_VAL_CONST:
192459d7c14eSRichard Henderson             /* If we're going to free the temp immediately, then we won't
192559d7c14eSRichard Henderson                require it later in a register, so attempt to store the
192659d7c14eSRichard Henderson                constant to memory directly.  */
192759d7c14eSRichard Henderson             if (free_or_dead
192859d7c14eSRichard Henderson                 && tcg_out_sti(s, ts->type, ts->val,
192959d7c14eSRichard Henderson                                ts->mem_base->reg, ts->mem_offset)) {
193059d7c14eSRichard Henderson                 break;
193159d7c14eSRichard Henderson             }
193259d7c14eSRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
193359d7c14eSRichard Henderson                       allocated_regs);
193459d7c14eSRichard Henderson             /* fallthrough */
193559d7c14eSRichard Henderson 
193659d7c14eSRichard Henderson         case TEMP_VAL_REG:
193759d7c14eSRichard Henderson             tcg_out_st(s, ts->type, ts->reg,
193859d7c14eSRichard Henderson                        ts->mem_base->reg, ts->mem_offset);
193959d7c14eSRichard Henderson             break;
194059d7c14eSRichard Henderson 
194159d7c14eSRichard Henderson         case TEMP_VAL_MEM:
194259d7c14eSRichard Henderson             break;
194359d7c14eSRichard Henderson 
194459d7c14eSRichard Henderson         case TEMP_VAL_DEAD:
194559d7c14eSRichard Henderson         default:
194659d7c14eSRichard Henderson             tcg_abort();
1947c896fe29Sbellard         }
19487f6ceedfSAurelien Jarno         ts->mem_coherent = 1;
19497f6ceedfSAurelien Jarno     }
195059d7c14eSRichard Henderson     if (free_or_dead) {
195159d7c14eSRichard Henderson         temp_free_or_dead(s, ts, free_or_dead);
195259d7c14eSRichard Henderson     }
195359d7c14eSRichard Henderson }
19547f6ceedfSAurelien Jarno 
19557f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
1956b3915dbbSRichard Henderson static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
19577f6ceedfSAurelien Jarno {
1958f8b2f202SRichard Henderson     TCGTemp *ts = s->reg_to_temp[reg];
1959f8b2f202SRichard Henderson     if (ts != NULL) {
196059d7c14eSRichard Henderson         temp_sync(s, ts, allocated_regs, -1);
1961c896fe29Sbellard     }
1962c896fe29Sbellard }
1963c896fe29Sbellard 
1964c896fe29Sbellard /* Allocate a register belonging to reg1 & ~reg2 */
1965b3915dbbSRichard Henderson static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet desired_regs,
196691478cefSRichard Henderson                             TCGRegSet allocated_regs, bool rev)
1967c896fe29Sbellard {
196891478cefSRichard Henderson     int i, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
196991478cefSRichard Henderson     const int *order;
1970b6638662SRichard Henderson     TCGReg reg;
1971c896fe29Sbellard     TCGRegSet reg_ct;
1972c896fe29Sbellard 
1973b3915dbbSRichard Henderson     tcg_regset_andnot(reg_ct, desired_regs, allocated_regs);
197491478cefSRichard Henderson     order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
1975c896fe29Sbellard 
1976c896fe29Sbellard     /* first try free registers */
197791478cefSRichard Henderson     for(i = 0; i < n; i++) {
197891478cefSRichard Henderson         reg = order[i];
1979f8b2f202SRichard Henderson         if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == NULL)
1980c896fe29Sbellard             return reg;
1981c896fe29Sbellard     }
1982c896fe29Sbellard 
1983c896fe29Sbellard     /* XXX: do better spill choice */
198491478cefSRichard Henderson     for(i = 0; i < n; i++) {
198591478cefSRichard Henderson         reg = order[i];
1986c896fe29Sbellard         if (tcg_regset_test_reg(reg_ct, reg)) {
1987b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
1988c896fe29Sbellard             return reg;
1989c896fe29Sbellard         }
1990c896fe29Sbellard     }
1991c896fe29Sbellard 
1992c896fe29Sbellard     tcg_abort();
1993c896fe29Sbellard }
1994c896fe29Sbellard 
199540ae5c62SRichard Henderson /* Make sure the temporary is in a register.  If needed, allocate the register
199640ae5c62SRichard Henderson    from DESIRED while avoiding ALLOCATED.  */
199740ae5c62SRichard Henderson static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
199840ae5c62SRichard Henderson                       TCGRegSet allocated_regs)
199940ae5c62SRichard Henderson {
200040ae5c62SRichard Henderson     TCGReg reg;
200140ae5c62SRichard Henderson 
200240ae5c62SRichard Henderson     switch (ts->val_type) {
200340ae5c62SRichard Henderson     case TEMP_VAL_REG:
200440ae5c62SRichard Henderson         return;
200540ae5c62SRichard Henderson     case TEMP_VAL_CONST:
200691478cefSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs, ts->indirect_base);
200740ae5c62SRichard Henderson         tcg_out_movi(s, ts->type, reg, ts->val);
200840ae5c62SRichard Henderson         ts->mem_coherent = 0;
200940ae5c62SRichard Henderson         break;
201040ae5c62SRichard Henderson     case TEMP_VAL_MEM:
201191478cefSRichard Henderson         reg = tcg_reg_alloc(s, desired_regs, allocated_regs, ts->indirect_base);
201240ae5c62SRichard Henderson         tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
201340ae5c62SRichard Henderson         ts->mem_coherent = 1;
201440ae5c62SRichard Henderson         break;
201540ae5c62SRichard Henderson     case TEMP_VAL_DEAD:
201640ae5c62SRichard Henderson     default:
201740ae5c62SRichard Henderson         tcg_abort();
201840ae5c62SRichard Henderson     }
201940ae5c62SRichard Henderson     ts->reg = reg;
202040ae5c62SRichard Henderson     ts->val_type = TEMP_VAL_REG;
202140ae5c62SRichard Henderson     s->reg_to_temp[reg] = ts;
202240ae5c62SRichard Henderson }
202340ae5c62SRichard Henderson 
202459d7c14eSRichard Henderson /* Save a temporary to memory. 'allocated_regs' is used in case a
2025e8996ee0Sbellard    temporary registers needs to be allocated to store a constant.  */
202659d7c14eSRichard Henderson static void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
20271ad80729SAurelien Jarno {
20282c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
2029eabb7b91SAurelien Jarno        in memory. Keep an tcg_debug_assert for safety. */
2030f8bf00f1SRichard Henderson     tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg);
20311ad80729SAurelien Jarno }
20321ad80729SAurelien Jarno 
20339814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
2034641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
2035641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
2036641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
2037641d5fbeSbellard {
2038641d5fbeSbellard     int i;
2039641d5fbeSbellard 
2040641d5fbeSbellard     for (i = 0; i < s->nb_globals; i++) {
2041b13eb728SRichard Henderson         temp_save(s, &s->temps[i], allocated_regs);
2042641d5fbeSbellard     }
2043e5097dc8Sbellard }
2044e5097dc8Sbellard 
20453d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
20463d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
20473d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
20483d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
20493d5c5f87SAurelien Jarno {
20503d5c5f87SAurelien Jarno     int i;
20513d5c5f87SAurelien Jarno 
20523d5c5f87SAurelien Jarno     for (i = 0; i < s->nb_globals; i++) {
205312b9b11aSRichard Henderson         TCGTemp *ts = &s->temps[i];
205412b9b11aSRichard Henderson         tcg_debug_assert(ts->val_type != TEMP_VAL_REG
205512b9b11aSRichard Henderson                          || ts->fixed_reg
205612b9b11aSRichard Henderson                          || ts->mem_coherent);
20573d5c5f87SAurelien Jarno     }
20583d5c5f87SAurelien Jarno }
20593d5c5f87SAurelien Jarno 
2060e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
2061e8996ee0Sbellard    all globals are stored at their canonical location. */
2062e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
2063e5097dc8Sbellard {
2064e5097dc8Sbellard     int i;
2065e5097dc8Sbellard 
2066c896fe29Sbellard     for (i = s->nb_globals; i < s->nb_temps; i++) {
2067b13eb728SRichard Henderson         TCGTemp *ts = &s->temps[i];
2068641d5fbeSbellard         if (ts->temp_local) {
2069b13eb728SRichard Henderson             temp_save(s, ts, allocated_regs);
2070641d5fbeSbellard         } else {
20712c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
2072eabb7b91SAurelien Jarno                Keep an tcg_debug_assert for safety. */
2073eabb7b91SAurelien Jarno             tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
2074c896fe29Sbellard         }
2075641d5fbeSbellard     }
2076e8996ee0Sbellard 
2077e8996ee0Sbellard     save_globals(s, allocated_regs);
2078c896fe29Sbellard }
2079c896fe29Sbellard 
20800fe4fca4SPaolo Bonzini static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
20810fe4fca4SPaolo Bonzini                                   tcg_target_ulong val, TCGLifeData arg_life)
2082e8996ee0Sbellard {
2083e8996ee0Sbellard     if (ots->fixed_reg) {
208459d7c14eSRichard Henderson         /* For fixed registers, we do not do any constant propagation.  */
2085e8996ee0Sbellard         tcg_out_movi(s, ots->type, ots->reg, val);
208659d7c14eSRichard Henderson         return;
208759d7c14eSRichard Henderson     }
208859d7c14eSRichard Henderson 
208959d7c14eSRichard Henderson     /* The movi is not explicitly generated here.  */
2090f8b2f202SRichard Henderson     if (ots->val_type == TEMP_VAL_REG) {
2091f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = NULL;
2092f8b2f202SRichard Henderson     }
2093e8996ee0Sbellard     ots->val_type = TEMP_VAL_CONST;
2094e8996ee0Sbellard     ots->val = val;
209559d7c14eSRichard Henderson     ots->mem_coherent = 0;
2096ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
209759d7c14eSRichard Henderson         temp_sync(s, ots, s->reserved_regs, IS_DEAD_ARG(0));
209859d7c14eSRichard Henderson     } else if (IS_DEAD_ARG(0)) {
2099f8bf00f1SRichard Henderson         temp_dead(s, ots);
21004c4e1ab2SAurelien Jarno     }
2101e8996ee0Sbellard }
2102e8996ee0Sbellard 
21030fe4fca4SPaolo Bonzini static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args,
21040fe4fca4SPaolo Bonzini                                TCGLifeData arg_life)
21050fe4fca4SPaolo Bonzini {
21060fe4fca4SPaolo Bonzini     TCGTemp *ots = &s->temps[args[0]];
21070fe4fca4SPaolo Bonzini     tcg_target_ulong val = args[1];
21080fe4fca4SPaolo Bonzini 
21090fe4fca4SPaolo Bonzini     tcg_reg_alloc_do_movi(s, ots, val, arg_life);
21100fe4fca4SPaolo Bonzini }
21110fe4fca4SPaolo Bonzini 
2112c896fe29Sbellard static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
2113a1b3c48dSRichard Henderson                               const TCGArg *args, TCGLifeData arg_life)
2114c896fe29Sbellard {
2115c29c1d7eSAurelien Jarno     TCGRegSet allocated_regs;
2116c896fe29Sbellard     TCGTemp *ts, *ots;
2117450445d5SRichard Henderson     TCGType otype, itype;
2118c896fe29Sbellard 
2119c29c1d7eSAurelien Jarno     tcg_regset_set(allocated_regs, s->reserved_regs);
2120c896fe29Sbellard     ots = &s->temps[args[0]];
2121c896fe29Sbellard     ts = &s->temps[args[1]];
2122450445d5SRichard Henderson 
2123450445d5SRichard Henderson     /* Note that otype != itype for no-op truncation.  */
2124450445d5SRichard Henderson     otype = ots->type;
2125450445d5SRichard Henderson     itype = ts->type;
2126c896fe29Sbellard 
21270fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_CONST) {
21280fe4fca4SPaolo Bonzini         /* propagate constant or generate sti */
21290fe4fca4SPaolo Bonzini         tcg_target_ulong val = ts->val;
21300fe4fca4SPaolo Bonzini         if (IS_DEAD_ARG(1)) {
21310fe4fca4SPaolo Bonzini             temp_dead(s, ts);
21320fe4fca4SPaolo Bonzini         }
21330fe4fca4SPaolo Bonzini         tcg_reg_alloc_do_movi(s, ots, val, arg_life);
21340fe4fca4SPaolo Bonzini         return;
21350fe4fca4SPaolo Bonzini     }
21360fe4fca4SPaolo Bonzini 
21370fe4fca4SPaolo Bonzini     /* If the source value is in memory we're going to be forced
21380fe4fca4SPaolo Bonzini        to have it in a register in order to perform the copy.  Copy
21390fe4fca4SPaolo Bonzini        the SOURCE value into its own register first, that way we
21400fe4fca4SPaolo Bonzini        don't have to reload SOURCE the next time it is used. */
21410fe4fca4SPaolo Bonzini     if (ts->val_type == TEMP_VAL_MEM) {
214240ae5c62SRichard Henderson         temp_load(s, ts, tcg_target_available_regs[itype], allocated_regs);
2143c29c1d7eSAurelien Jarno     }
2144c29c1d7eSAurelien Jarno 
21450fe4fca4SPaolo Bonzini     tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
2146c29c1d7eSAurelien Jarno     if (IS_DEAD_ARG(0) && !ots->fixed_reg) {
2147c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
2148c29c1d7eSAurelien Jarno            liveness analysis disabled). */
2149eabb7b91SAurelien Jarno         tcg_debug_assert(NEED_SYNC_ARG(0));
2150c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
2151c29c1d7eSAurelien Jarno             temp_allocate_frame(s, args[0]);
2152c29c1d7eSAurelien Jarno         }
2153b3a62939SRichard Henderson         tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset);
2154c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
2155f8bf00f1SRichard Henderson             temp_dead(s, ts);
2156c29c1d7eSAurelien Jarno         }
2157f8bf00f1SRichard Henderson         temp_dead(s, ots);
2158e8996ee0Sbellard     } else {
2159c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1) && !ts->fixed_reg && !ots->fixed_reg) {
2160c29c1d7eSAurelien Jarno             /* the mov can be suppressed */
2161c29c1d7eSAurelien Jarno             if (ots->val_type == TEMP_VAL_REG) {
2162f8b2f202SRichard Henderson                 s->reg_to_temp[ots->reg] = NULL;
2163c896fe29Sbellard             }
2164c29c1d7eSAurelien Jarno             ots->reg = ts->reg;
2165f8bf00f1SRichard Henderson             temp_dead(s, ts);
2166c29c1d7eSAurelien Jarno         } else {
2167c29c1d7eSAurelien Jarno             if (ots->val_type != TEMP_VAL_REG) {
2168c29c1d7eSAurelien Jarno                 /* When allocating a new register, make sure to not spill the
2169c29c1d7eSAurelien Jarno                    input one. */
2170c29c1d7eSAurelien Jarno                 tcg_regset_set_reg(allocated_regs, ts->reg);
2171450445d5SRichard Henderson                 ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
217291478cefSRichard Henderson                                          allocated_regs, ots->indirect_base);
2173c29c1d7eSAurelien Jarno             }
2174450445d5SRichard Henderson             tcg_out_mov(s, otype, ots->reg, ts->reg);
2175c29c1d7eSAurelien Jarno         }
2176c896fe29Sbellard         ots->val_type = TEMP_VAL_REG;
2177c896fe29Sbellard         ots->mem_coherent = 0;
2178f8b2f202SRichard Henderson         s->reg_to_temp[ots->reg] = ots;
2179ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(0)) {
218059d7c14eSRichard Henderson             temp_sync(s, ots, allocated_regs, 0);
2181c29c1d7eSAurelien Jarno         }
2182ec7a869dSAurelien Jarno     }
2183c896fe29Sbellard }
2184c896fe29Sbellard 
2185c896fe29Sbellard static void tcg_reg_alloc_op(TCGContext *s,
2186a9751609SRichard Henderson                              const TCGOpDef *def, TCGOpcode opc,
2187a1b3c48dSRichard Henderson                              const TCGArg *args, TCGLifeData arg_life)
2188c896fe29Sbellard {
218982790a87SRichard Henderson     TCGRegSet i_allocated_regs;
219082790a87SRichard Henderson     TCGRegSet o_allocated_regs;
2191b6638662SRichard Henderson     int i, k, nb_iargs, nb_oargs;
2192b6638662SRichard Henderson     TCGReg reg;
2193c896fe29Sbellard     TCGArg arg;
2194c896fe29Sbellard     const TCGArgConstraint *arg_ct;
2195c896fe29Sbellard     TCGTemp *ts;
2196c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
2197c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
2198c896fe29Sbellard 
2199c896fe29Sbellard     nb_oargs = def->nb_oargs;
2200c896fe29Sbellard     nb_iargs = def->nb_iargs;
2201c896fe29Sbellard 
2202c896fe29Sbellard     /* copy constants */
2203c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
2204c896fe29Sbellard            args + nb_oargs + nb_iargs,
2205c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
2206c896fe29Sbellard 
220782790a87SRichard Henderson     tcg_regset_set(i_allocated_regs, s->reserved_regs);
220882790a87SRichard Henderson     tcg_regset_set(o_allocated_regs, s->reserved_regs);
220982790a87SRichard Henderson 
2210c896fe29Sbellard     /* satisfy input constraints */
2211c896fe29Sbellard     for(k = 0; k < nb_iargs; k++) {
2212c896fe29Sbellard         i = def->sorted_args[nb_oargs + k];
2213c896fe29Sbellard         arg = args[i];
2214c896fe29Sbellard         arg_ct = &def->args_ct[i];
2215c896fe29Sbellard         ts = &s->temps[arg];
221640ae5c62SRichard Henderson 
221740ae5c62SRichard Henderson         if (ts->val_type == TEMP_VAL_CONST
221840ae5c62SRichard Henderson             && tcg_target_const_match(ts->val, ts->type, arg_ct)) {
2219c896fe29Sbellard             /* constant is OK for instruction */
2220c896fe29Sbellard             const_args[i] = 1;
2221c896fe29Sbellard             new_args[i] = ts->val;
2222c896fe29Sbellard             goto iarg_end;
2223c896fe29Sbellard         }
222440ae5c62SRichard Henderson 
222582790a87SRichard Henderson         temp_load(s, ts, arg_ct->u.regs, i_allocated_regs);
222640ae5c62SRichard Henderson 
22275ff9d6a4Sbellard         if (arg_ct->ct & TCG_CT_IALIAS) {
22285ff9d6a4Sbellard             if (ts->fixed_reg) {
22295ff9d6a4Sbellard                 /* if fixed register, we must allocate a new register
22305ff9d6a4Sbellard                    if the alias is not the same register */
22315ff9d6a4Sbellard                 if (arg != args[arg_ct->alias_index])
22325ff9d6a4Sbellard                     goto allocate_in_reg;
22335ff9d6a4Sbellard             } else {
2234c896fe29Sbellard                 /* if the input is aliased to an output and if it is
2235c896fe29Sbellard                    not dead after the instruction, we must allocate
2236c896fe29Sbellard                    a new register and move it */
2237866cb6cbSAurelien Jarno                 if (!IS_DEAD_ARG(i)) {
2238c896fe29Sbellard                     goto allocate_in_reg;
2239c896fe29Sbellard                 }
22407e1df267SAurelien Jarno                 /* check if the current register has already been allocated
22417e1df267SAurelien Jarno                    for another input aliased to an output */
22427e1df267SAurelien Jarno                 int k2, i2;
22437e1df267SAurelien Jarno                 for (k2 = 0 ; k2 < k ; k2++) {
22447e1df267SAurelien Jarno                     i2 = def->sorted_args[nb_oargs + k2];
22457e1df267SAurelien Jarno                     if ((def->args_ct[i2].ct & TCG_CT_IALIAS) &&
22467e1df267SAurelien Jarno                         (new_args[i2] == ts->reg)) {
22477e1df267SAurelien Jarno                         goto allocate_in_reg;
22487e1df267SAurelien Jarno                     }
22497e1df267SAurelien Jarno                 }
22505ff9d6a4Sbellard             }
2251866cb6cbSAurelien Jarno         }
2252c896fe29Sbellard         reg = ts->reg;
2253c896fe29Sbellard         if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
2254c896fe29Sbellard             /* nothing to do : the constraint is satisfied */
2255c896fe29Sbellard         } else {
2256c896fe29Sbellard         allocate_in_reg:
2257c896fe29Sbellard             /* allocate a new register matching the constraint
2258c896fe29Sbellard                and move the temporary register into it */
225982790a87SRichard Henderson             reg = tcg_reg_alloc(s, arg_ct->u.regs, i_allocated_regs,
226091478cefSRichard Henderson                                 ts->indirect_base);
22613b6dac34SRichard Henderson             tcg_out_mov(s, ts->type, reg, ts->reg);
2262c896fe29Sbellard         }
2263c896fe29Sbellard         new_args[i] = reg;
2264c896fe29Sbellard         const_args[i] = 0;
226582790a87SRichard Henderson         tcg_regset_set_reg(i_allocated_regs, reg);
2266c896fe29Sbellard     iarg_end: ;
2267c896fe29Sbellard     }
2268c896fe29Sbellard 
2269c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
2270866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
2271866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
2272f8bf00f1SRichard Henderson             temp_dead(s, &s->temps[args[i]]);
2273c896fe29Sbellard         }
2274c896fe29Sbellard     }
2275c896fe29Sbellard 
2276a52ad07eSAurelien Jarno     if (def->flags & TCG_OPF_BB_END) {
227782790a87SRichard Henderson         tcg_reg_alloc_bb_end(s, i_allocated_regs);
2278a52ad07eSAurelien Jarno     } else {
2279c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
2280b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
2281c8074023SRichard Henderson             for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
2282c8074023SRichard Henderson                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
228382790a87SRichard Henderson                     tcg_reg_free(s, i, i_allocated_regs);
2284c896fe29Sbellard                 }
2285c896fe29Sbellard             }
22863d5c5f87SAurelien Jarno         }
22873d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
22883d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
22893d5c5f87SAurelien Jarno                an exception. */
229082790a87SRichard Henderson             sync_globals(s, i_allocated_regs);
2291c896fe29Sbellard         }
2292c896fe29Sbellard 
2293c896fe29Sbellard         /* satisfy the output constraints */
2294c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
2295c896fe29Sbellard             i = def->sorted_args[k];
2296c896fe29Sbellard             arg = args[i];
2297c896fe29Sbellard             arg_ct = &def->args_ct[i];
2298c896fe29Sbellard             ts = &s->temps[arg];
2299c896fe29Sbellard             if (arg_ct->ct & TCG_CT_ALIAS) {
23005ff9d6a4Sbellard                 reg = new_args[arg_ct->alias_index];
230182790a87SRichard Henderson             } else if (arg_ct->ct & TCG_CT_NEWREG) {
230282790a87SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->u.regs,
230382790a87SRichard Henderson                                     i_allocated_regs | o_allocated_regs,
230482790a87SRichard Henderson                                     ts->indirect_base);
2305c896fe29Sbellard             } else {
2306c896fe29Sbellard                 /* if fixed register, we try to use it */
2307c896fe29Sbellard                 reg = ts->reg;
2308c896fe29Sbellard                 if (ts->fixed_reg &&
2309c896fe29Sbellard                     tcg_regset_test_reg(arg_ct->u.regs, reg)) {
2310c896fe29Sbellard                     goto oarg_end;
2311c896fe29Sbellard                 }
231282790a87SRichard Henderson                 reg = tcg_reg_alloc(s, arg_ct->u.regs, o_allocated_regs,
231391478cefSRichard Henderson                                     ts->indirect_base);
2314c896fe29Sbellard             }
231582790a87SRichard Henderson             tcg_regset_set_reg(o_allocated_regs, reg);
2316c896fe29Sbellard             /* if a fixed register is used, then a move will be done afterwards */
2317c896fe29Sbellard             if (!ts->fixed_reg) {
2318639368ddSAurelien Jarno                 if (ts->val_type == TEMP_VAL_REG) {
2319f8b2f202SRichard Henderson                     s->reg_to_temp[ts->reg] = NULL;
2320639368ddSAurelien Jarno                 }
2321c896fe29Sbellard                 ts->val_type = TEMP_VAL_REG;
2322c896fe29Sbellard                 ts->reg = reg;
2323c896fe29Sbellard                 /* temp value is modified, so the value kept in memory is
2324c896fe29Sbellard                    potentially not the same */
2325c896fe29Sbellard                 ts->mem_coherent = 0;
2326f8b2f202SRichard Henderson                 s->reg_to_temp[reg] = ts;
2327c896fe29Sbellard             }
2328c896fe29Sbellard         oarg_end:
2329c896fe29Sbellard             new_args[i] = reg;
2330c896fe29Sbellard         }
2331e8996ee0Sbellard     }
2332c896fe29Sbellard 
2333c896fe29Sbellard     /* emit instruction */
2334c896fe29Sbellard     tcg_out_op(s, opc, new_args, const_args);
2335c896fe29Sbellard 
2336c896fe29Sbellard     /* move the outputs in the correct register if needed */
2337c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
2338c896fe29Sbellard         ts = &s->temps[args[i]];
2339c896fe29Sbellard         reg = new_args[i];
2340c896fe29Sbellard         if (ts->fixed_reg && ts->reg != reg) {
23413b6dac34SRichard Henderson             tcg_out_mov(s, ts->type, ts->reg, reg);
2342c896fe29Sbellard         }
2343ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
234482790a87SRichard Henderson             temp_sync(s, ts, o_allocated_regs, IS_DEAD_ARG(i));
234559d7c14eSRichard Henderson         } else if (IS_DEAD_ARG(i)) {
2346f8bf00f1SRichard Henderson             temp_dead(s, ts);
2347ec7a869dSAurelien Jarno         }
2348c896fe29Sbellard     }
2349c896fe29Sbellard }
2350c896fe29Sbellard 
2351b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP
2352b03cce8eSbellard #define STACK_DIR(x) (-(x))
2353b03cce8eSbellard #else
2354b03cce8eSbellard #define STACK_DIR(x) (x)
2355b03cce8eSbellard #endif
2356b03cce8eSbellard 
2357c45cb8bbSRichard Henderson static void tcg_reg_alloc_call(TCGContext *s, int nb_oargs, int nb_iargs,
2358a1b3c48dSRichard Henderson                                const TCGArg * const args, TCGLifeData arg_life)
2359c896fe29Sbellard {
2360b6638662SRichard Henderson     int flags, nb_regs, i;
2361b6638662SRichard Henderson     TCGReg reg;
2362cf066674SRichard Henderson     TCGArg arg;
2363c896fe29Sbellard     TCGTemp *ts;
2364d3452f1fSRichard Henderson     intptr_t stack_offset;
2365d3452f1fSRichard Henderson     size_t call_stack_size;
2366cf066674SRichard Henderson     tcg_insn_unit *func_addr;
2367cf066674SRichard Henderson     int allocate_args;
2368c896fe29Sbellard     TCGRegSet allocated_regs;
2369c896fe29Sbellard 
2370cf066674SRichard Henderson     func_addr = (tcg_insn_unit *)(intptr_t)args[nb_oargs + nb_iargs];
2371cf066674SRichard Henderson     flags = args[nb_oargs + nb_iargs + 1];
2372c896fe29Sbellard 
23736e17d0c5SStefan Weil     nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
2374c45cb8bbSRichard Henderson     if (nb_regs > nb_iargs) {
2375c45cb8bbSRichard Henderson         nb_regs = nb_iargs;
2376cf066674SRichard Henderson     }
2377c896fe29Sbellard 
2378c896fe29Sbellard     /* assign stack slots first */
2379c45cb8bbSRichard Henderson     call_stack_size = (nb_iargs - nb_regs) * sizeof(tcg_target_long);
2380c896fe29Sbellard     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
2381c896fe29Sbellard         ~(TCG_TARGET_STACK_ALIGN - 1);
2382b03cce8eSbellard     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
2383b03cce8eSbellard     if (allocate_args) {
2384345649c0SBlue Swirl         /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
2385345649c0SBlue Swirl            preallocate call stack */
2386345649c0SBlue Swirl         tcg_abort();
2387b03cce8eSbellard     }
238839cf05d3Sbellard 
238939cf05d3Sbellard     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
2390c45cb8bbSRichard Henderson     for(i = nb_regs; i < nb_iargs; i++) {
2391c896fe29Sbellard         arg = args[nb_oargs + i];
239239cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP
239339cf05d3Sbellard         stack_offset -= sizeof(tcg_target_long);
239439cf05d3Sbellard #endif
239539cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
2396c896fe29Sbellard             ts = &s->temps[arg];
239740ae5c62SRichard Henderson             temp_load(s, ts, tcg_target_available_regs[ts->type],
239840ae5c62SRichard Henderson                       s->reserved_regs);
2399e4d5434cSblueswir1             tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
240039cf05d3Sbellard         }
240139cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP
240239cf05d3Sbellard         stack_offset += sizeof(tcg_target_long);
240339cf05d3Sbellard #endif
2404c896fe29Sbellard     }
2405c896fe29Sbellard 
2406c896fe29Sbellard     /* assign input registers */
2407c896fe29Sbellard     tcg_regset_set(allocated_regs, s->reserved_regs);
2408c896fe29Sbellard     for(i = 0; i < nb_regs; i++) {
2409c896fe29Sbellard         arg = args[nb_oargs + i];
241039cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
2411c896fe29Sbellard             ts = &s->temps[arg];
2412c896fe29Sbellard             reg = tcg_target_call_iarg_regs[i];
2413b3915dbbSRichard Henderson             tcg_reg_free(s, reg, allocated_regs);
241440ae5c62SRichard Henderson 
2415c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
2416c896fe29Sbellard                 if (ts->reg != reg) {
24173b6dac34SRichard Henderson                     tcg_out_mov(s, ts->type, reg, ts->reg);
2418c896fe29Sbellard                 }
2419c896fe29Sbellard             } else {
242040ae5c62SRichard Henderson                 TCGRegSet arg_set;
242140ae5c62SRichard Henderson 
242240ae5c62SRichard Henderson                 tcg_regset_clear(arg_set);
242340ae5c62SRichard Henderson                 tcg_regset_set_reg(arg_set, reg);
242440ae5c62SRichard Henderson                 temp_load(s, ts, arg_set, allocated_regs);
2425c896fe29Sbellard             }
242640ae5c62SRichard Henderson 
2427c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
2428c896fe29Sbellard         }
242939cf05d3Sbellard     }
2430c896fe29Sbellard 
2431c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
2432866cb6cbSAurelien Jarno     for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2433866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
2434f8bf00f1SRichard Henderson             temp_dead(s, &s->temps[args[i]]);
2435c896fe29Sbellard         }
2436c896fe29Sbellard     }
2437c896fe29Sbellard 
2438c896fe29Sbellard     /* clobber call registers */
2439c8074023SRichard Henderson     for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
2440c8074023SRichard Henderson         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
2441b3915dbbSRichard Henderson             tcg_reg_free(s, i, allocated_regs);
2442c896fe29Sbellard         }
2443c896fe29Sbellard     }
2444c896fe29Sbellard 
244578505279SAurelien Jarno     /* Save globals if they might be written by the helper, sync them if
244678505279SAurelien Jarno        they might be read. */
244778505279SAurelien Jarno     if (flags & TCG_CALL_NO_READ_GLOBALS) {
244878505279SAurelien Jarno         /* Nothing to do */
244978505279SAurelien Jarno     } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) {
245078505279SAurelien Jarno         sync_globals(s, allocated_regs);
245178505279SAurelien Jarno     } else {
2452e8996ee0Sbellard         save_globals(s, allocated_regs);
2453b9c18f56Saurel32     }
2454c896fe29Sbellard 
2455cf066674SRichard Henderson     tcg_out_call(s, func_addr);
2456c896fe29Sbellard 
2457c896fe29Sbellard     /* assign output registers and emit moves if needed */
2458c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
2459c896fe29Sbellard         arg = args[i];
2460c896fe29Sbellard         ts = &s->temps[arg];
2461c896fe29Sbellard         reg = tcg_target_call_oarg_regs[i];
2462eabb7b91SAurelien Jarno         tcg_debug_assert(s->reg_to_temp[reg] == NULL);
246334b1a49cSRichard Henderson 
2464c896fe29Sbellard         if (ts->fixed_reg) {
2465c896fe29Sbellard             if (ts->reg != reg) {
24663b6dac34SRichard Henderson                 tcg_out_mov(s, ts->type, ts->reg, reg);
2467c896fe29Sbellard             }
2468c896fe29Sbellard         } else {
2469639368ddSAurelien Jarno             if (ts->val_type == TEMP_VAL_REG) {
2470f8b2f202SRichard Henderson                 s->reg_to_temp[ts->reg] = NULL;
2471639368ddSAurelien Jarno             }
2472c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
2473c896fe29Sbellard             ts->reg = reg;
2474c896fe29Sbellard             ts->mem_coherent = 0;
2475f8b2f202SRichard Henderson             s->reg_to_temp[reg] = ts;
2476ec7a869dSAurelien Jarno             if (NEED_SYNC_ARG(i)) {
247759d7c14eSRichard Henderson                 temp_sync(s, ts, allocated_regs, IS_DEAD_ARG(i));
247859d7c14eSRichard Henderson             } else if (IS_DEAD_ARG(i)) {
2479f8bf00f1SRichard Henderson                 temp_dead(s, ts);
2480c896fe29Sbellard             }
2481c896fe29Sbellard         }
24828c11ad25SAurelien Jarno     }
2483c896fe29Sbellard }
2484c896fe29Sbellard 
2485c896fe29Sbellard #ifdef CONFIG_PROFILER
2486c896fe29Sbellard 
248754604f74Saurel32 static int64_t tcg_table_op_count[NB_OPS];
2488c896fe29Sbellard 
2489246ae24dSMax Filippov void tcg_dump_op_count(FILE *f, fprintf_function cpu_fprintf)
2490c896fe29Sbellard {
2491c896fe29Sbellard     int i;
2492d70724ceSzhanghailiang 
249315fc7daaSRichard Henderson     for (i = 0; i < NB_OPS; i++) {
2494246ae24dSMax Filippov         cpu_fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name,
2495246ae24dSMax Filippov                     tcg_table_op_count[i]);
2496c896fe29Sbellard     }
2497c896fe29Sbellard }
2498246ae24dSMax Filippov #else
2499246ae24dSMax Filippov void tcg_dump_op_count(FILE *f, fprintf_function cpu_fprintf)
2500246ae24dSMax Filippov {
2501246ae24dSMax Filippov     cpu_fprintf(f, "[TCG profiler not compiled]\n");
2502246ae24dSMax Filippov }
2503c896fe29Sbellard #endif
2504c896fe29Sbellard 
2505c896fe29Sbellard 
25065bd2ec3dSAlex Bennée int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
2507c896fe29Sbellard {
2508fca8a500SRichard Henderson     int i, oi, oi_next, num_insns;
2509c896fe29Sbellard 
251004fe6400SRichard Henderson #ifdef CONFIG_PROFILER
251104fe6400SRichard Henderson     {
251204fe6400SRichard Henderson         int n;
251304fe6400SRichard Henderson 
2514dcb8e758SRichard Henderson         n = s->gen_op_buf[0].prev + 1;
251504fe6400SRichard Henderson         s->op_count += n;
251604fe6400SRichard Henderson         if (n > s->op_count_max) {
251704fe6400SRichard Henderson             s->op_count_max = n;
251804fe6400SRichard Henderson         }
251904fe6400SRichard Henderson 
252004fe6400SRichard Henderson         n = s->nb_temps;
252104fe6400SRichard Henderson         s->temp_count += n;
252204fe6400SRichard Henderson         if (n > s->temp_count_max) {
252304fe6400SRichard Henderson             s->temp_count_max = n;
252404fe6400SRichard Henderson         }
252504fe6400SRichard Henderson     }
252604fe6400SRichard Henderson #endif
252704fe6400SRichard Henderson 
2528c896fe29Sbellard #ifdef DEBUG_DISAS
2529d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
2530d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
25311ee73216SRichard Henderson         qemu_log_lock();
253293fcfe39Saliguori         qemu_log("OP:\n");
2533eeacee4dSBlue Swirl         tcg_dump_ops(s);
253493fcfe39Saliguori         qemu_log("\n");
25351ee73216SRichard Henderson         qemu_log_unlock();
2536c896fe29Sbellard     }
2537c896fe29Sbellard #endif
2538c896fe29Sbellard 
2539c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
2540c5cc28ffSAurelien Jarno     s->opt_time -= profile_getclock();
2541c5cc28ffSAurelien Jarno #endif
2542c5cc28ffSAurelien Jarno 
25438f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
2544c45cb8bbSRichard Henderson     tcg_optimize(s);
25458f2e8c07SKirill Batuzov #endif
25468f2e8c07SKirill Batuzov 
2547a23a9ec6Sbellard #ifdef CONFIG_PROFILER
2548c5cc28ffSAurelien Jarno     s->opt_time += profile_getclock();
2549a23a9ec6Sbellard     s->la_time -= profile_getclock();
2550a23a9ec6Sbellard #endif
2551c5cc28ffSAurelien Jarno 
25525a18407fSRichard Henderson     {
25535a18407fSRichard Henderson         uint8_t *temp_state = tcg_malloc(s->nb_temps + s->nb_indirects);
25545a18407fSRichard Henderson 
25555a18407fSRichard Henderson         liveness_pass_1(s, temp_state);
25565a18407fSRichard Henderson 
25575a18407fSRichard Henderson         if (s->nb_indirects > 0) {
25585a18407fSRichard Henderson #ifdef DEBUG_DISAS
25595a18407fSRichard Henderson             if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND)
25605a18407fSRichard Henderson                          && qemu_log_in_addr_range(tb->pc))) {
25611ee73216SRichard Henderson                 qemu_log_lock();
25625a18407fSRichard Henderson                 qemu_log("OP before indirect lowering:\n");
25635a18407fSRichard Henderson                 tcg_dump_ops(s);
25645a18407fSRichard Henderson                 qemu_log("\n");
25651ee73216SRichard Henderson                 qemu_log_unlock();
25665a18407fSRichard Henderson             }
25675a18407fSRichard Henderson #endif
25685a18407fSRichard Henderson             /* Replace indirect temps with direct temps.  */
25695a18407fSRichard Henderson             if (liveness_pass_2(s, temp_state)) {
25705a18407fSRichard Henderson                 /* If changes were made, re-run liveness.  */
25715a18407fSRichard Henderson                 liveness_pass_1(s, temp_state);
25725a18407fSRichard Henderson             }
25735a18407fSRichard Henderson         }
25745a18407fSRichard Henderson     }
2575c5cc28ffSAurelien Jarno 
2576a23a9ec6Sbellard #ifdef CONFIG_PROFILER
2577a23a9ec6Sbellard     s->la_time += profile_getclock();
2578a23a9ec6Sbellard #endif
2579c896fe29Sbellard 
2580c896fe29Sbellard #ifdef DEBUG_DISAS
2581d977e1c2SAlex Bennée     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
2582d977e1c2SAlex Bennée                  && qemu_log_in_addr_range(tb->pc))) {
25831ee73216SRichard Henderson         qemu_log_lock();
2584c5cc28ffSAurelien Jarno         qemu_log("OP after optimization and liveness analysis:\n");
2585eeacee4dSBlue Swirl         tcg_dump_ops(s);
258693fcfe39Saliguori         qemu_log("\n");
25871ee73216SRichard Henderson         qemu_log_unlock();
2588c896fe29Sbellard     }
2589c896fe29Sbellard #endif
2590c896fe29Sbellard 
2591c896fe29Sbellard     tcg_reg_alloc_start(s);
2592c896fe29Sbellard 
25935bd2ec3dSAlex Bennée     s->code_buf = tb->tc_ptr;
25945bd2ec3dSAlex Bennée     s->code_ptr = tb->tc_ptr;
2595c896fe29Sbellard 
25969ecefc84SRichard Henderson     tcg_out_tb_init(s);
25979ecefc84SRichard Henderson 
2598fca8a500SRichard Henderson     num_insns = -1;
2599dcb8e758SRichard Henderson     for (oi = s->gen_op_buf[0].next; oi != 0; oi = oi_next) {
2600c45cb8bbSRichard Henderson         TCGOp * const op = &s->gen_op_buf[oi];
2601c45cb8bbSRichard Henderson         TCGArg * const args = &s->gen_opparam_buf[op->args];
2602c45cb8bbSRichard Henderson         TCGOpcode opc = op->opc;
2603c45cb8bbSRichard Henderson         const TCGOpDef *def = &tcg_op_defs[opc];
2604bee158cbSRichard Henderson         TCGLifeData arg_life = op->life;
2605b3db8758Sblueswir1 
2606c45cb8bbSRichard Henderson         oi_next = op->next;
2607c896fe29Sbellard #ifdef CONFIG_PROFILER
260854604f74Saurel32         tcg_table_op_count[opc]++;
2609c896fe29Sbellard #endif
2610c45cb8bbSRichard Henderson 
2611c896fe29Sbellard         switch (opc) {
2612c896fe29Sbellard         case INDEX_op_mov_i32:
2613c896fe29Sbellard         case INDEX_op_mov_i64:
2614a1b3c48dSRichard Henderson             tcg_reg_alloc_mov(s, def, args, arg_life);
2615c896fe29Sbellard             break;
2616e8996ee0Sbellard         case INDEX_op_movi_i32:
2617e8996ee0Sbellard         case INDEX_op_movi_i64:
2618a1b3c48dSRichard Henderson             tcg_reg_alloc_movi(s, args, arg_life);
2619e8996ee0Sbellard             break;
2620765b842aSRichard Henderson         case INDEX_op_insn_start:
2621fca8a500SRichard Henderson             if (num_insns >= 0) {
2622fca8a500SRichard Henderson                 s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
2623fca8a500SRichard Henderson             }
2624fca8a500SRichard Henderson             num_insns++;
2625bad729e2SRichard Henderson             for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
2626bad729e2SRichard Henderson                 target_ulong a;
2627bad729e2SRichard Henderson #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
2628bad729e2SRichard Henderson                 a = ((target_ulong)args[i * 2 + 1] << 32) | args[i * 2];
2629bad729e2SRichard Henderson #else
2630bad729e2SRichard Henderson                 a = args[i];
2631bad729e2SRichard Henderson #endif
2632fca8a500SRichard Henderson                 s->gen_insn_data[num_insns][i] = a;
2633bad729e2SRichard Henderson             }
2634c896fe29Sbellard             break;
26355ff9d6a4Sbellard         case INDEX_op_discard:
2636f8bf00f1SRichard Henderson             temp_dead(s, &s->temps[args[0]]);
26375ff9d6a4Sbellard             break;
2638c896fe29Sbellard         case INDEX_op_set_label:
2639e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
2640bec16311SRichard Henderson             tcg_out_label(s, arg_label(args[0]), s->code_ptr);
2641c896fe29Sbellard             break;
2642c896fe29Sbellard         case INDEX_op_call:
2643a1b3c48dSRichard Henderson             tcg_reg_alloc_call(s, op->callo, op->calli, args, arg_life);
2644c45cb8bbSRichard Henderson             break;
2645c896fe29Sbellard         default:
264625c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
264725c4d9ccSRichard Henderson             if (def->flags & TCG_OPF_NOT_PRESENT) {
264825c4d9ccSRichard Henderson                 tcg_abort();
264925c4d9ccSRichard Henderson             }
2650c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
2651c896fe29Sbellard                faster to have specialized register allocator functions for
2652c896fe29Sbellard                some common argument patterns */
2653a1b3c48dSRichard Henderson             tcg_reg_alloc_op(s, def, opc, args, arg_life);
2654c896fe29Sbellard             break;
2655c896fe29Sbellard         }
26568d8fdbaeSAurelien Jarno #ifdef CONFIG_DEBUG_TCG
2657c896fe29Sbellard         check_regs(s);
2658c896fe29Sbellard #endif
2659b125f9dcSRichard Henderson         /* Test for (pending) buffer overflow.  The assumption is that any
2660b125f9dcSRichard Henderson            one operation beginning below the high water mark cannot overrun
2661b125f9dcSRichard Henderson            the buffer completely.  Thus we can test for overflow after
2662b125f9dcSRichard Henderson            generating code without having to check during generation.  */
2663644da9b3SJohn Clarke         if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
2664b125f9dcSRichard Henderson             return -1;
2665b125f9dcSRichard Henderson         }
2666c896fe29Sbellard     }
2667fca8a500SRichard Henderson     tcg_debug_assert(num_insns >= 0);
2668fca8a500SRichard Henderson     s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);
2669c45cb8bbSRichard Henderson 
2670b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
267123dceda6SRichard Henderson     if (!tcg_out_tb_finalize(s)) {
267223dceda6SRichard Henderson         return -1;
267323dceda6SRichard Henderson     }
2674c896fe29Sbellard 
2675c896fe29Sbellard     /* flush instruction cache */
26761813e175SRichard Henderson     flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr);
26772aeabc08SStefan Weil 
26781813e175SRichard Henderson     return tcg_current_code_size(s);
2679c896fe29Sbellard }
2680c896fe29Sbellard 
2681a23a9ec6Sbellard #ifdef CONFIG_PROFILER
2682405cf9ffSStefan Weil void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
2683a23a9ec6Sbellard {
2684a23a9ec6Sbellard     TCGContext *s = &tcg_ctx;
2685fca8a500SRichard Henderson     int64_t tb_count = s->tb_count;
2686fca8a500SRichard Henderson     int64_t tb_div_count = tb_count ? tb_count : 1;
2687fca8a500SRichard Henderson     int64_t tot = s->interm_time + s->code_time;
2688a23a9ec6Sbellard 
2689a23a9ec6Sbellard     cpu_fprintf(f, "JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
2690a23a9ec6Sbellard                 tot, tot / 2.4e9);
2691a23a9ec6Sbellard     cpu_fprintf(f, "translated TBs      %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n",
2692fca8a500SRichard Henderson                 tb_count, s->tb_count1 - tb_count,
2693fca8a500SRichard Henderson                 (double)(s->tb_count1 - s->tb_count)
2694fca8a500SRichard Henderson                 / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
2695a23a9ec6Sbellard     cpu_fprintf(f, "avg ops/TB          %0.1f max=%d\n",
2696fca8a500SRichard Henderson                 (double)s->op_count / tb_div_count, s->op_count_max);
2697a23a9ec6Sbellard     cpu_fprintf(f, "deleted ops/TB      %0.2f\n",
2698fca8a500SRichard Henderson                 (double)s->del_op_count / tb_div_count);
2699a23a9ec6Sbellard     cpu_fprintf(f, "avg temps/TB        %0.2f max=%d\n",
2700fca8a500SRichard Henderson                 (double)s->temp_count / tb_div_count, s->temp_count_max);
2701fca8a500SRichard Henderson     cpu_fprintf(f, "avg host code/TB    %0.1f\n",
2702fca8a500SRichard Henderson                 (double)s->code_out_len / tb_div_count);
2703fca8a500SRichard Henderson     cpu_fprintf(f, "avg search data/TB  %0.1f\n",
2704fca8a500SRichard Henderson                 (double)s->search_out_len / tb_div_count);
2705a23a9ec6Sbellard 
2706a23a9ec6Sbellard     cpu_fprintf(f, "cycles/op           %0.1f\n",
2707a23a9ec6Sbellard                 s->op_count ? (double)tot / s->op_count : 0);
2708a23a9ec6Sbellard     cpu_fprintf(f, "cycles/in byte      %0.1f\n",
2709a23a9ec6Sbellard                 s->code_in_len ? (double)tot / s->code_in_len : 0);
2710a23a9ec6Sbellard     cpu_fprintf(f, "cycles/out byte     %0.1f\n",
2711a23a9ec6Sbellard                 s->code_out_len ? (double)tot / s->code_out_len : 0);
2712fca8a500SRichard Henderson     cpu_fprintf(f, "cycles/search byte     %0.1f\n",
2713fca8a500SRichard Henderson                 s->search_out_len ? (double)tot / s->search_out_len : 0);
2714fca8a500SRichard Henderson     if (tot == 0) {
2715a23a9ec6Sbellard         tot = 1;
2716fca8a500SRichard Henderson     }
2717a23a9ec6Sbellard     cpu_fprintf(f, "  gen_interm time   %0.1f%%\n",
2718a23a9ec6Sbellard                 (double)s->interm_time / tot * 100.0);
2719a23a9ec6Sbellard     cpu_fprintf(f, "  gen_code time     %0.1f%%\n",
2720a23a9ec6Sbellard                 (double)s->code_time / tot * 100.0);
2721c5cc28ffSAurelien Jarno     cpu_fprintf(f, "optim./code time    %0.1f%%\n",
2722c5cc28ffSAurelien Jarno                 (double)s->opt_time / (s->code_time ? s->code_time : 1)
2723c5cc28ffSAurelien Jarno                 * 100.0);
2724a23a9ec6Sbellard     cpu_fprintf(f, "liveness/code time  %0.1f%%\n",
2725a23a9ec6Sbellard                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
2726a23a9ec6Sbellard     cpu_fprintf(f, "cpu_restore count   %" PRId64 "\n",
2727a23a9ec6Sbellard                 s->restore_count);
2728a23a9ec6Sbellard     cpu_fprintf(f, "  avg cycles        %0.1f\n",
2729a23a9ec6Sbellard                 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
2730a23a9ec6Sbellard }
2731a23a9ec6Sbellard #else
2732405cf9ffSStefan Weil void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
2733a23a9ec6Sbellard {
273424bf7b3aSbellard     cpu_fprintf(f, "[TCG profiler not compiled]\n");
2735a23a9ec6Sbellard }
2736a23a9ec6Sbellard #endif
2737813da627SRichard Henderson 
2738813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
27395872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
27405872bbf2SRichard Henderson 
27415872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
27425872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
27435872bbf2SRichard Henderson 
27445872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
27455872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
27465872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
27475872bbf2SRichard Henderson 
27485872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
27495872bbf2SRichard Henderson */
2750813da627SRichard Henderson 
2751813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
2752813da627SRichard Henderson typedef enum {
2753813da627SRichard Henderson     JIT_NOACTION = 0,
2754813da627SRichard Henderson     JIT_REGISTER_FN,
2755813da627SRichard Henderson     JIT_UNREGISTER_FN
2756813da627SRichard Henderson } jit_actions_t;
2757813da627SRichard Henderson 
2758813da627SRichard Henderson struct jit_code_entry {
2759813da627SRichard Henderson     struct jit_code_entry *next_entry;
2760813da627SRichard Henderson     struct jit_code_entry *prev_entry;
2761813da627SRichard Henderson     const void *symfile_addr;
2762813da627SRichard Henderson     uint64_t symfile_size;
2763813da627SRichard Henderson };
2764813da627SRichard Henderson 
2765813da627SRichard Henderson struct jit_descriptor {
2766813da627SRichard Henderson     uint32_t version;
2767813da627SRichard Henderson     uint32_t action_flag;
2768813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
2769813da627SRichard Henderson     struct jit_code_entry *first_entry;
2770813da627SRichard Henderson };
2771813da627SRichard Henderson 
2772813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
2773813da627SRichard Henderson void __jit_debug_register_code(void)
2774813da627SRichard Henderson {
2775813da627SRichard Henderson     asm("");
2776813da627SRichard Henderson }
2777813da627SRichard Henderson 
2778813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
2779813da627SRichard Henderson    the version before we can set it.  */
2780813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
2781813da627SRichard Henderson 
2782813da627SRichard Henderson /* End GDB interface.  */
2783813da627SRichard Henderson 
2784813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
2785813da627SRichard Henderson {
2786813da627SRichard Henderson     const char *p = strtab + 1;
2787813da627SRichard Henderson 
2788813da627SRichard Henderson     while (1) {
2789813da627SRichard Henderson         if (strcmp(p, str) == 0) {
2790813da627SRichard Henderson             return p - strtab;
2791813da627SRichard Henderson         }
2792813da627SRichard Henderson         p += strlen(p) + 1;
2793813da627SRichard Henderson     }
2794813da627SRichard Henderson }
2795813da627SRichard Henderson 
27965872bbf2SRichard Henderson static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
27972c90784aSRichard Henderson                                  const void *debug_frame,
27982c90784aSRichard Henderson                                  size_t debug_frame_size)
2799813da627SRichard Henderson {
28005872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
28015872bbf2SRichard Henderson         uint32_t  len;
28025872bbf2SRichard Henderson         uint16_t  version;
28035872bbf2SRichard Henderson         uint32_t  abbrev;
28045872bbf2SRichard Henderson         uint8_t   ptr_size;
28055872bbf2SRichard Henderson         uint8_t   cu_die;
28065872bbf2SRichard Henderson         uint16_t  cu_lang;
28075872bbf2SRichard Henderson         uintptr_t cu_low_pc;
28085872bbf2SRichard Henderson         uintptr_t cu_high_pc;
28095872bbf2SRichard Henderson         uint8_t   fn_die;
28105872bbf2SRichard Henderson         char      fn_name[16];
28115872bbf2SRichard Henderson         uintptr_t fn_low_pc;
28125872bbf2SRichard Henderson         uintptr_t fn_high_pc;
28135872bbf2SRichard Henderson         uint8_t   cu_eoc;
28145872bbf2SRichard Henderson     };
2815813da627SRichard Henderson 
2816813da627SRichard Henderson     struct ElfImage {
2817813da627SRichard Henderson         ElfW(Ehdr) ehdr;
2818813da627SRichard Henderson         ElfW(Phdr) phdr;
28195872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
28205872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
28215872bbf2SRichard Henderson         struct DebugInfo di;
28225872bbf2SRichard Henderson         uint8_t    da[24];
28235872bbf2SRichard Henderson         char       str[80];
28245872bbf2SRichard Henderson     };
28255872bbf2SRichard Henderson 
28265872bbf2SRichard Henderson     struct ElfImage *img;
28275872bbf2SRichard Henderson 
28285872bbf2SRichard Henderson     static const struct ElfImage img_template = {
28295872bbf2SRichard Henderson         .ehdr = {
28305872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
28315872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
28325872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
28335872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
28345872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
28355872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
28365872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
28375872bbf2SRichard Henderson             .e_type = ET_EXEC,
28385872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
28395872bbf2SRichard Henderson             .e_version = EV_CURRENT,
28405872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
28415872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
28425872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
28435872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
28445872bbf2SRichard Henderson             .e_phnum = 1,
28455872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
28465872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
28475872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
2848abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
2849abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
2850abbb3eaeSRichard Henderson #endif
2851abbb3eaeSRichard Henderson #ifdef ELF_OSABI
2852abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
2853abbb3eaeSRichard Henderson #endif
28545872bbf2SRichard Henderson         },
28555872bbf2SRichard Henderson         .phdr = {
28565872bbf2SRichard Henderson             .p_type = PT_LOAD,
28575872bbf2SRichard Henderson             .p_flags = PF_X,
28585872bbf2SRichard Henderson         },
28595872bbf2SRichard Henderson         .shdr = {
28605872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
28615872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
28625872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
28635872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
28645872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
28655872bbf2SRichard Henderson             [1] = { /* .text */
28665872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
28675872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
28685872bbf2SRichard Henderson             },
28695872bbf2SRichard Henderson             [2] = { /* .debug_info */
28705872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
28715872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
28725872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
28735872bbf2SRichard Henderson             },
28745872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
28755872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
28765872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
28775872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
28785872bbf2SRichard Henderson             },
28795872bbf2SRichard Henderson             [4] = { /* .debug_frame */
28805872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
28815872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
28825872bbf2SRichard Henderson             },
28835872bbf2SRichard Henderson             [5] = { /* .symtab */
28845872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
28855872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
28865872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
28875872bbf2SRichard Henderson                 .sh_info = 1,
28885872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
28895872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
28905872bbf2SRichard Henderson             },
28915872bbf2SRichard Henderson             [6] = { /* .strtab */
28925872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
28935872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
28945872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
28955872bbf2SRichard Henderson             }
28965872bbf2SRichard Henderson         },
28975872bbf2SRichard Henderson         .sym = {
28985872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
28995872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
29005872bbf2SRichard Henderson                 .st_shndx = 1,
29015872bbf2SRichard Henderson             }
29025872bbf2SRichard Henderson         },
29035872bbf2SRichard Henderson         .di = {
29045872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
29055872bbf2SRichard Henderson             .version = 2,
29065872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
29075872bbf2SRichard Henderson             .cu_die = 1,
29085872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
29095872bbf2SRichard Henderson             .fn_die = 2,
29105872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
29115872bbf2SRichard Henderson         },
29125872bbf2SRichard Henderson         .da = {
29135872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
29145872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
29155872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
29165872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
29175872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
29185872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
29195872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
29205872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
29215872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
29225872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
29235872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
29245872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
29255872bbf2SRichard Henderson             0           /* no more abbrev */
29265872bbf2SRichard Henderson         },
29275872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
29285872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
2929813da627SRichard Henderson     };
2930813da627SRichard Henderson 
2931813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
2932813da627SRichard Henderson     static struct jit_code_entry one_entry;
2933813da627SRichard Henderson 
29345872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
2935813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
29362c90784aSRichard Henderson     DebugFrameHeader *dfh;
2937813da627SRichard Henderson 
29385872bbf2SRichard Henderson     img = g_malloc(img_size);
29395872bbf2SRichard Henderson     *img = img_template;
2940813da627SRichard Henderson 
29415872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
29425872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
29435872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
2944813da627SRichard Henderson 
29455872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
29465872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
29475872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
2948813da627SRichard Henderson 
29495872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
29505872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
29515872bbf2SRichard Henderson 
29525872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
29535872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
29545872bbf2SRichard Henderson 
29555872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
29565872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
29575872bbf2SRichard Henderson 
29585872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
29595872bbf2SRichard Henderson     img->sym[1].st_value = buf;
29605872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
29615872bbf2SRichard Henderson 
29625872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
296345aba097SRichard Henderson     img->di.cu_high_pc = buf + buf_size;
29645872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
296545aba097SRichard Henderson     img->di.fn_high_pc = buf + buf_size;
2966813da627SRichard Henderson 
29672c90784aSRichard Henderson     dfh = (DebugFrameHeader *)(img + 1);
29682c90784aSRichard Henderson     memcpy(dfh, debug_frame, debug_frame_size);
29692c90784aSRichard Henderson     dfh->fde.func_start = buf;
29702c90784aSRichard Henderson     dfh->fde.func_len = buf_size;
29712c90784aSRichard Henderson 
2972813da627SRichard Henderson #ifdef DEBUG_JIT
2973813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
2974813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
2975813da627SRichard Henderson     {
2976813da627SRichard Henderson         FILE *f = fopen("/tmp/qemu.jit", "w+b");
2977813da627SRichard Henderson         if (f) {
29785872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
2979813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
2980813da627SRichard Henderson             }
2981813da627SRichard Henderson             fclose(f);
2982813da627SRichard Henderson         }
2983813da627SRichard Henderson     }
2984813da627SRichard Henderson #endif
2985813da627SRichard Henderson 
2986813da627SRichard Henderson     one_entry.symfile_addr = img;
2987813da627SRichard Henderson     one_entry.symfile_size = img_size;
2988813da627SRichard Henderson 
2989813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
2990813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
2991813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
2992813da627SRichard Henderson     __jit_debug_register_code();
2993813da627SRichard Henderson }
2994813da627SRichard Henderson #else
29955872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
29965872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
2997813da627SRichard Henderson 
2998813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size,
29992c90784aSRichard Henderson                                  const void *debug_frame,
30002c90784aSRichard Henderson                                  size_t debug_frame_size)
3001813da627SRichard Henderson {
3002813da627SRichard Henderson }
3003813da627SRichard Henderson 
3004813da627SRichard Henderson void tcg_register_jit(void *buf, size_t buf_size)
3005813da627SRichard Henderson {
3006813da627SRichard Henderson }
3007813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
3008