xref: /openbmc/qemu/tcg/tcg.c (revision 92414b31)
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) */
26c896fe29Sbellard #define USE_LIVENESS_ANALYSIS
278f2e8c07SKirill Batuzov #define USE_TCG_OPTIMIZATIONS
28c896fe29Sbellard 
29cca82982Saurel32 #include "config.h"
30cca82982Saurel32 
31813da627SRichard Henderson /* Define to jump the ELF file used to communicate with GDB.  */
32813da627SRichard Henderson #undef DEBUG_JIT
33813da627SRichard Henderson 
34a6c6f76cSBlue Swirl #if !defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG)
35cca82982Saurel32 /* define it to suppress various consistency checks (faster) */
36cca82982Saurel32 #define NDEBUG
37cca82982Saurel32 #endif
38cca82982Saurel32 
39ca10f867Saurel32 #include "qemu-common.h"
40902b3d5cSmalc #include "cache-utils.h"
41379f6698SPaul Brook #include "host-utils.h"
422d8ebcf9SRichard Henderson #include "qemu-timer.h"
43c896fe29Sbellard 
44c896fe29Sbellard /* Note: the long term plan is to reduce the dependancies on the QEMU
45c896fe29Sbellard    CPU definitions. Currently they are used for qemu_ld/st
46c896fe29Sbellard    instructions */
47c896fe29Sbellard #define NO_CPU_IO_DEFS
48c896fe29Sbellard #include "cpu.h"
49c896fe29Sbellard 
50c896fe29Sbellard #include "tcg-op.h"
51813da627SRichard Henderson 
52813da627SRichard Henderson #if TCG_TARGET_REG_BITS == 64
53813da627SRichard Henderson # define ELF_CLASS  ELFCLASS64
54813da627SRichard Henderson #else
55813da627SRichard Henderson # define ELF_CLASS  ELFCLASS32
56813da627SRichard Henderson #endif
57813da627SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
58813da627SRichard Henderson # define ELF_DATA   ELFDATA2MSB
59813da627SRichard Henderson #else
60813da627SRichard Henderson # define ELF_DATA   ELFDATA2LSB
61813da627SRichard Henderson #endif
62813da627SRichard Henderson 
63c896fe29Sbellard #include "elf.h"
64c896fe29Sbellard 
65c0ad3001SStefan Weil /* Forward declarations for functions declared in tcg-target.c and used here. */
66e4d58b41SRichard Henderson static void tcg_target_init(TCGContext *s);
67e4d58b41SRichard Henderson static void tcg_target_qemu_prologue(TCGContext *s);
68c896fe29Sbellard static void patch_reloc(uint8_t *code_ptr, int type,
69f54b3f92Saurel32                         tcg_target_long value, tcg_target_long addend);
70c896fe29Sbellard 
71813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size,
72813da627SRichard Henderson                                  void *debug_frame, size_t debug_frame_size)
73813da627SRichard Henderson     __attribute__((unused));
74813da627SRichard Henderson 
75c0ad3001SStefan Weil /* Forward declarations for functions declared and used in tcg-target.c. */
76c0ad3001SStefan Weil static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str);
772a534affSRichard Henderson static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
78c0ad3001SStefan Weil                        tcg_target_long arg2);
792a534affSRichard Henderson static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
80c0ad3001SStefan Weil static void tcg_out_movi(TCGContext *s, TCGType type,
812a534affSRichard Henderson                          TCGReg ret, tcg_target_long arg);
82c0ad3001SStefan Weil static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
83c0ad3001SStefan Weil                        const int *const_args);
842a534affSRichard Henderson static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
85c0ad3001SStefan Weil                        tcg_target_long arg2);
86c0ad3001SStefan Weil static int tcg_target_const_match(tcg_target_long val,
87c0ad3001SStefan Weil                                   const TCGArgConstraint *arg_ct);
88c0ad3001SStefan Weil 
898399ad59SRichard Henderson TCGOpDef tcg_op_defs[] = {
900e2029a0SAurelien Jarno #define DEF(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags },
91c896fe29Sbellard #include "tcg-opc.h"
92c896fe29Sbellard #undef DEF
93c896fe29Sbellard };
942a24374aSStefan Weil const size_t tcg_op_defs_max = ARRAY_SIZE(tcg_op_defs);
95c896fe29Sbellard 
96b1d8e52eSblueswir1 static TCGRegSet tcg_target_available_regs[2];
97b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
98c896fe29Sbellard 
99c896fe29Sbellard /* XXX: move that inside the context */
100c896fe29Sbellard uint16_t *gen_opc_ptr;
101c896fe29Sbellard TCGArg *gen_opparam_ptr;
102c896fe29Sbellard 
103c896fe29Sbellard static inline void tcg_out8(TCGContext *s, uint8_t v)
104c896fe29Sbellard {
105c896fe29Sbellard     *s->code_ptr++ = v;
106c896fe29Sbellard }
107c896fe29Sbellard 
108c896fe29Sbellard static inline void tcg_out16(TCGContext *s, uint16_t v)
109c896fe29Sbellard {
110c896fe29Sbellard     *(uint16_t *)s->code_ptr = v;
111c896fe29Sbellard     s->code_ptr += 2;
112c896fe29Sbellard }
113c896fe29Sbellard 
114c896fe29Sbellard static inline void tcg_out32(TCGContext *s, uint32_t v)
115c896fe29Sbellard {
116c896fe29Sbellard     *(uint32_t *)s->code_ptr = v;
117c896fe29Sbellard     s->code_ptr += 4;
118c896fe29Sbellard }
119c896fe29Sbellard 
120c896fe29Sbellard /* label relocation processing */
121c896fe29Sbellard 
122a5ad5916SStefan Weil static void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type,
123c896fe29Sbellard                           int label_index, long addend)
124c896fe29Sbellard {
125c896fe29Sbellard     TCGLabel *l;
126c896fe29Sbellard     TCGRelocation *r;
127c896fe29Sbellard 
128c896fe29Sbellard     l = &s->labels[label_index];
129c896fe29Sbellard     if (l->has_value) {
130623e265cSpbrook         /* FIXME: This may break relocations on RISC targets that
131623e265cSpbrook            modify instruction fields in place.  The caller may not have
132623e265cSpbrook            written the initial value.  */
133f54b3f92Saurel32         patch_reloc(code_ptr, type, l->u.value, addend);
134c896fe29Sbellard     } else {
135c896fe29Sbellard         /* add a new relocation entry */
136c896fe29Sbellard         r = tcg_malloc(sizeof(TCGRelocation));
137c896fe29Sbellard         r->type = type;
138c896fe29Sbellard         r->ptr = code_ptr;
139c896fe29Sbellard         r->addend = addend;
140c896fe29Sbellard         r->next = l->u.first_reloc;
141c896fe29Sbellard         l->u.first_reloc = r;
142c896fe29Sbellard     }
143c896fe29Sbellard }
144c896fe29Sbellard 
1459d6fca70SStefan Weil static void tcg_out_label(TCGContext *s, int label_index, void *ptr)
146c896fe29Sbellard {
147c896fe29Sbellard     TCGLabel *l;
148c896fe29Sbellard     TCGRelocation *r;
1499d6fca70SStefan Weil     tcg_target_long value = (tcg_target_long)ptr;
150c896fe29Sbellard 
151c896fe29Sbellard     l = &s->labels[label_index];
152c896fe29Sbellard     if (l->has_value)
153c896fe29Sbellard         tcg_abort();
154c896fe29Sbellard     r = l->u.first_reloc;
155c896fe29Sbellard     while (r != NULL) {
156f54b3f92Saurel32         patch_reloc(r->ptr, r->type, value, r->addend);
157c896fe29Sbellard         r = r->next;
158c896fe29Sbellard     }
159c896fe29Sbellard     l->has_value = 1;
160c896fe29Sbellard     l->u.value = value;
161c896fe29Sbellard }
162c896fe29Sbellard 
163c896fe29Sbellard int gen_new_label(void)
164c896fe29Sbellard {
165c896fe29Sbellard     TCGContext *s = &tcg_ctx;
166c896fe29Sbellard     int idx;
167c896fe29Sbellard     TCGLabel *l;
168c896fe29Sbellard 
169c896fe29Sbellard     if (s->nb_labels >= TCG_MAX_LABELS)
170c896fe29Sbellard         tcg_abort();
171c896fe29Sbellard     idx = s->nb_labels++;
172c896fe29Sbellard     l = &s->labels[idx];
173c896fe29Sbellard     l->has_value = 0;
174c896fe29Sbellard     l->u.first_reloc = NULL;
175c896fe29Sbellard     return idx;
176c896fe29Sbellard }
177c896fe29Sbellard 
178c896fe29Sbellard #include "tcg-target.c"
179c896fe29Sbellard 
180c896fe29Sbellard /* pool based memory allocation */
181c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
182c896fe29Sbellard {
183c896fe29Sbellard     TCGPool *p;
184c896fe29Sbellard     int pool_size;
185c896fe29Sbellard 
186c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
187c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
1887267c094SAnthony Liguori         p = g_malloc(sizeof(TCGPool) + size);
189c896fe29Sbellard         p->size = size;
1904055299eSKirill Batuzov         p->next = s->pool_first_large;
1914055299eSKirill Batuzov         s->pool_first_large = p;
1924055299eSKirill Batuzov         return p->data;
193c896fe29Sbellard     } else {
194c896fe29Sbellard         p = s->pool_current;
195c896fe29Sbellard         if (!p) {
196c896fe29Sbellard             p = s->pool_first;
197c896fe29Sbellard             if (!p)
198c896fe29Sbellard                 goto new_pool;
199c896fe29Sbellard         } else {
200c896fe29Sbellard             if (!p->next) {
201c896fe29Sbellard             new_pool:
202c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
2037267c094SAnthony Liguori                 p = g_malloc(sizeof(TCGPool) + pool_size);
204c896fe29Sbellard                 p->size = pool_size;
205c896fe29Sbellard                 p->next = NULL;
206c896fe29Sbellard                 if (s->pool_current)
207c896fe29Sbellard                     s->pool_current->next = p;
208c896fe29Sbellard                 else
209c896fe29Sbellard                     s->pool_first = p;
210c896fe29Sbellard             } else {
211c896fe29Sbellard                 p = p->next;
212c896fe29Sbellard             }
213c896fe29Sbellard         }
214c896fe29Sbellard     }
215c896fe29Sbellard     s->pool_current = p;
216c896fe29Sbellard     s->pool_cur = p->data + size;
217c896fe29Sbellard     s->pool_end = p->data + p->size;
218c896fe29Sbellard     return p->data;
219c896fe29Sbellard }
220c896fe29Sbellard 
221c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
222c896fe29Sbellard {
2234055299eSKirill Batuzov     TCGPool *p, *t;
2244055299eSKirill Batuzov     for (p = s->pool_first_large; p; p = t) {
2254055299eSKirill Batuzov         t = p->next;
2264055299eSKirill Batuzov         g_free(p);
2274055299eSKirill Batuzov     }
2284055299eSKirill Batuzov     s->pool_first_large = NULL;
229c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
230c896fe29Sbellard     s->pool_current = NULL;
231c896fe29Sbellard }
232c896fe29Sbellard 
233c896fe29Sbellard void tcg_context_init(TCGContext *s)
234c896fe29Sbellard {
235c896fe29Sbellard     int op, total_args, n;
236c896fe29Sbellard     TCGOpDef *def;
237c896fe29Sbellard     TCGArgConstraint *args_ct;
238c896fe29Sbellard     int *sorted_args;
239c896fe29Sbellard 
240c896fe29Sbellard     memset(s, 0, sizeof(*s));
241c896fe29Sbellard     s->nb_globals = 0;
242c896fe29Sbellard 
243c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
244c896fe29Sbellard        space */
245c896fe29Sbellard     total_args = 0;
246c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
247c896fe29Sbellard         def = &tcg_op_defs[op];
248c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
249c896fe29Sbellard         total_args += n;
250c896fe29Sbellard     }
251c896fe29Sbellard 
2527267c094SAnthony Liguori     args_ct = g_malloc(sizeof(TCGArgConstraint) * total_args);
2537267c094SAnthony Liguori     sorted_args = g_malloc(sizeof(int) * total_args);
254c896fe29Sbellard 
255c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
256c896fe29Sbellard         def = &tcg_op_defs[op];
257c896fe29Sbellard         def->args_ct = args_ct;
258c896fe29Sbellard         def->sorted_args = sorted_args;
259c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
260c896fe29Sbellard         sorted_args += n;
261c896fe29Sbellard         args_ct += n;
262c896fe29Sbellard     }
263c896fe29Sbellard 
264c896fe29Sbellard     tcg_target_init(s);
2659002ec79SRichard Henderson }
266b03cce8eSbellard 
2679002ec79SRichard Henderson void tcg_prologue_init(TCGContext *s)
2689002ec79SRichard Henderson {
269b03cce8eSbellard     /* init global prologue and epilogue */
270b03cce8eSbellard     s->code_buf = code_gen_prologue;
271b03cce8eSbellard     s->code_ptr = s->code_buf;
272b03cce8eSbellard     tcg_target_qemu_prologue(s);
2732aeabc08SStefan Weil     flush_icache_range((tcg_target_ulong)s->code_buf,
2742aeabc08SStefan Weil                        (tcg_target_ulong)s->code_ptr);
275c896fe29Sbellard }
276c896fe29Sbellard 
277c896fe29Sbellard void tcg_set_frame(TCGContext *s, int reg,
278c896fe29Sbellard                    tcg_target_long start, tcg_target_long size)
279c896fe29Sbellard {
280c896fe29Sbellard     s->frame_start = start;
281c896fe29Sbellard     s->frame_end = start + size;
282c896fe29Sbellard     s->frame_reg = reg;
283c896fe29Sbellard }
284c896fe29Sbellard 
285c896fe29Sbellard void tcg_func_start(TCGContext *s)
286c896fe29Sbellard {
287e8996ee0Sbellard     int i;
288c896fe29Sbellard     tcg_pool_reset(s);
289c896fe29Sbellard     s->nb_temps = s->nb_globals;
290641d5fbeSbellard     for(i = 0; i < (TCG_TYPE_COUNT * 2); i++)
291e8996ee0Sbellard         s->first_free_temp[i] = -1;
292c896fe29Sbellard     s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS);
293c896fe29Sbellard     s->nb_labels = 0;
294c896fe29Sbellard     s->current_frame_offset = s->frame_start;
295c896fe29Sbellard 
2960a209d4bSRichard Henderson #ifdef CONFIG_DEBUG_TCG
2970a209d4bSRichard Henderson     s->goto_tb_issue_mask = 0;
2980a209d4bSRichard Henderson #endif
2990a209d4bSRichard Henderson 
300*92414b31SEvgeny Voevodin     s->gen_opc_ptr = s->gen_opc_buf;
301c4afe5c4SEvgeny Voevodin     s->gen_opparam_ptr = gen_opparam_buf;
302b76f0d8cSYeongkyoon Lee 
303b76f0d8cSYeongkyoon Lee #if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU)
304b76f0d8cSYeongkyoon Lee     /* Initialize qemu_ld/st labels to assist code generation at the end of TB
305b76f0d8cSYeongkyoon Lee        for TLB miss cases at the end of TB */
306b76f0d8cSYeongkyoon Lee     s->qemu_ldst_labels = tcg_malloc(sizeof(TCGLabelQemuLdst) *
307b76f0d8cSYeongkyoon Lee                                      TCG_MAX_QEMU_LDST);
308b76f0d8cSYeongkyoon Lee     s->nb_qemu_ldst_labels = 0;
309b76f0d8cSYeongkyoon Lee #endif
310c896fe29Sbellard }
311c896fe29Sbellard 
312c896fe29Sbellard static inline void tcg_temp_alloc(TCGContext *s, int n)
313c896fe29Sbellard {
314c896fe29Sbellard     if (n > TCG_MAX_TEMPS)
315c896fe29Sbellard         tcg_abort();
316c896fe29Sbellard }
317c896fe29Sbellard 
318a7812ae4Spbrook static inline int tcg_global_reg_new_internal(TCGType type, int reg,
319a7812ae4Spbrook                                               const char *name)
320c896fe29Sbellard {
321c896fe29Sbellard     TCGContext *s = &tcg_ctx;
322c896fe29Sbellard     TCGTemp *ts;
323c896fe29Sbellard     int idx;
324c896fe29Sbellard 
325c896fe29Sbellard #if TCG_TARGET_REG_BITS == 32
326c896fe29Sbellard     if (type != TCG_TYPE_I32)
327c896fe29Sbellard         tcg_abort();
328c896fe29Sbellard #endif
329c896fe29Sbellard     if (tcg_regset_test_reg(s->reserved_regs, reg))
330c896fe29Sbellard         tcg_abort();
331c896fe29Sbellard     idx = s->nb_globals;
332c896fe29Sbellard     tcg_temp_alloc(s, s->nb_globals + 1);
333c896fe29Sbellard     ts = &s->temps[s->nb_globals];
334c896fe29Sbellard     ts->base_type = type;
335c896fe29Sbellard     ts->type = type;
336c896fe29Sbellard     ts->fixed_reg = 1;
337c896fe29Sbellard     ts->reg = reg;
338c896fe29Sbellard     ts->name = name;
339c896fe29Sbellard     s->nb_globals++;
340c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
341a7812ae4Spbrook     return idx;
342a7812ae4Spbrook }
343a7812ae4Spbrook 
344a7812ae4Spbrook TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name)
345a7812ae4Spbrook {
346a7812ae4Spbrook     int idx;
347a7812ae4Spbrook 
348a7812ae4Spbrook     idx = tcg_global_reg_new_internal(TCG_TYPE_I32, reg, name);
349a7812ae4Spbrook     return MAKE_TCGV_I32(idx);
350a7812ae4Spbrook }
351a7812ae4Spbrook 
352a7812ae4Spbrook TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name)
353a7812ae4Spbrook {
354a7812ae4Spbrook     int idx;
355a7812ae4Spbrook 
356a7812ae4Spbrook     idx = tcg_global_reg_new_internal(TCG_TYPE_I64, reg, name);
357a7812ae4Spbrook     return MAKE_TCGV_I64(idx);
358c896fe29Sbellard }
359c896fe29Sbellard 
360a7812ae4Spbrook static inline int tcg_global_mem_new_internal(TCGType type, int reg,
361a7812ae4Spbrook                                               tcg_target_long offset,
362c896fe29Sbellard                                               const char *name)
363c896fe29Sbellard {
364c896fe29Sbellard     TCGContext *s = &tcg_ctx;
365c896fe29Sbellard     TCGTemp *ts;
366c896fe29Sbellard     int idx;
367c896fe29Sbellard 
368c896fe29Sbellard     idx = s->nb_globals;
369c896fe29Sbellard #if TCG_TARGET_REG_BITS == 32
370c896fe29Sbellard     if (type == TCG_TYPE_I64) {
371c896fe29Sbellard         char buf[64];
372c588979bSths         tcg_temp_alloc(s, s->nb_globals + 2);
373c896fe29Sbellard         ts = &s->temps[s->nb_globals];
374c896fe29Sbellard         ts->base_type = type;
375c896fe29Sbellard         ts->type = TCG_TYPE_I32;
376c896fe29Sbellard         ts->fixed_reg = 0;
377c896fe29Sbellard         ts->mem_allocated = 1;
378c896fe29Sbellard         ts->mem_reg = reg;
379c896fe29Sbellard #ifdef TCG_TARGET_WORDS_BIGENDIAN
380c896fe29Sbellard         ts->mem_offset = offset + 4;
381c896fe29Sbellard #else
382c896fe29Sbellard         ts->mem_offset = offset;
383c896fe29Sbellard #endif
384c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
385c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
386c896fe29Sbellard         ts->name = strdup(buf);
387c896fe29Sbellard         ts++;
388c896fe29Sbellard 
389c896fe29Sbellard         ts->base_type = type;
390c896fe29Sbellard         ts->type = TCG_TYPE_I32;
391c896fe29Sbellard         ts->fixed_reg = 0;
392c896fe29Sbellard         ts->mem_allocated = 1;
393c896fe29Sbellard         ts->mem_reg = reg;
394c896fe29Sbellard #ifdef TCG_TARGET_WORDS_BIGENDIAN
395c896fe29Sbellard         ts->mem_offset = offset;
396c896fe29Sbellard #else
397c896fe29Sbellard         ts->mem_offset = offset + 4;
398c896fe29Sbellard #endif
399c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
400c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
401c896fe29Sbellard         ts->name = strdup(buf);
402c896fe29Sbellard 
403c896fe29Sbellard         s->nb_globals += 2;
404c896fe29Sbellard     } else
405c896fe29Sbellard #endif
406c896fe29Sbellard     {
407c896fe29Sbellard         tcg_temp_alloc(s, s->nb_globals + 1);
408c896fe29Sbellard         ts = &s->temps[s->nb_globals];
409c896fe29Sbellard         ts->base_type = type;
410c896fe29Sbellard         ts->type = type;
411c896fe29Sbellard         ts->fixed_reg = 0;
412c896fe29Sbellard         ts->mem_allocated = 1;
413c896fe29Sbellard         ts->mem_reg = reg;
414c896fe29Sbellard         ts->mem_offset = offset;
415c896fe29Sbellard         ts->name = name;
416c896fe29Sbellard         s->nb_globals++;
417c896fe29Sbellard     }
418a7812ae4Spbrook     return idx;
419c896fe29Sbellard }
420c896fe29Sbellard 
421a7812ae4Spbrook TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset,
422a7812ae4Spbrook                                 const char *name)
423a7812ae4Spbrook {
424a7812ae4Spbrook     int idx;
425a7812ae4Spbrook 
426a7812ae4Spbrook     idx = tcg_global_mem_new_internal(TCG_TYPE_I32, reg, offset, name);
427a7812ae4Spbrook     return MAKE_TCGV_I32(idx);
428a7812ae4Spbrook }
429a7812ae4Spbrook 
430a7812ae4Spbrook TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset,
431a7812ae4Spbrook                                 const char *name)
432a7812ae4Spbrook {
433a7812ae4Spbrook     int idx;
434a7812ae4Spbrook 
435a7812ae4Spbrook     idx = tcg_global_mem_new_internal(TCG_TYPE_I64, reg, offset, name);
436a7812ae4Spbrook     return MAKE_TCGV_I64(idx);
437a7812ae4Spbrook }
438a7812ae4Spbrook 
439a7812ae4Spbrook static inline int tcg_temp_new_internal(TCGType type, int temp_local)
440c896fe29Sbellard {
441c896fe29Sbellard     TCGContext *s = &tcg_ctx;
442c896fe29Sbellard     TCGTemp *ts;
443641d5fbeSbellard     int idx, k;
444c896fe29Sbellard 
445641d5fbeSbellard     k = type;
446641d5fbeSbellard     if (temp_local)
447641d5fbeSbellard         k += TCG_TYPE_COUNT;
448641d5fbeSbellard     idx = s->first_free_temp[k];
449e8996ee0Sbellard     if (idx != -1) {
450e8996ee0Sbellard         /* There is already an available temp with the
451e8996ee0Sbellard            right type */
452e8996ee0Sbellard         ts = &s->temps[idx];
453641d5fbeSbellard         s->first_free_temp[k] = ts->next_free_temp;
454e8996ee0Sbellard         ts->temp_allocated = 1;
455641d5fbeSbellard         assert(ts->temp_local == temp_local);
456e8996ee0Sbellard     } else {
457c896fe29Sbellard         idx = s->nb_temps;
458c896fe29Sbellard #if TCG_TARGET_REG_BITS == 32
459c896fe29Sbellard         if (type == TCG_TYPE_I64) {
4608df1ca4bSths             tcg_temp_alloc(s, s->nb_temps + 2);
461c896fe29Sbellard             ts = &s->temps[s->nb_temps];
462c896fe29Sbellard             ts->base_type = type;
463c896fe29Sbellard             ts->type = TCG_TYPE_I32;
464e8996ee0Sbellard             ts->temp_allocated = 1;
465641d5fbeSbellard             ts->temp_local = temp_local;
466c896fe29Sbellard             ts->name = NULL;
467c896fe29Sbellard             ts++;
468c896fe29Sbellard             ts->base_type = TCG_TYPE_I32;
469c896fe29Sbellard             ts->type = TCG_TYPE_I32;
470e8996ee0Sbellard             ts->temp_allocated = 1;
471641d5fbeSbellard             ts->temp_local = temp_local;
472c896fe29Sbellard             ts->name = NULL;
473c896fe29Sbellard             s->nb_temps += 2;
474c896fe29Sbellard         } else
475c896fe29Sbellard #endif
476c896fe29Sbellard         {
477c896fe29Sbellard             tcg_temp_alloc(s, s->nb_temps + 1);
478c896fe29Sbellard             ts = &s->temps[s->nb_temps];
479c896fe29Sbellard             ts->base_type = type;
480c896fe29Sbellard             ts->type = type;
481e8996ee0Sbellard             ts->temp_allocated = 1;
482641d5fbeSbellard             ts->temp_local = temp_local;
483c896fe29Sbellard             ts->name = NULL;
484c896fe29Sbellard             s->nb_temps++;
485c896fe29Sbellard         }
486e8996ee0Sbellard     }
48727bfd83cSPeter Maydell 
48827bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
48927bfd83cSPeter Maydell     s->temps_in_use++;
49027bfd83cSPeter Maydell #endif
491a7812ae4Spbrook     return idx;
492c896fe29Sbellard }
493c896fe29Sbellard 
494a7812ae4Spbrook TCGv_i32 tcg_temp_new_internal_i32(int temp_local)
495a7812ae4Spbrook {
496a7812ae4Spbrook     int idx;
497a7812ae4Spbrook 
498a7812ae4Spbrook     idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local);
499a7812ae4Spbrook     return MAKE_TCGV_I32(idx);
500a7812ae4Spbrook }
501a7812ae4Spbrook 
502a7812ae4Spbrook TCGv_i64 tcg_temp_new_internal_i64(int temp_local)
503a7812ae4Spbrook {
504a7812ae4Spbrook     int idx;
505a7812ae4Spbrook 
506a7812ae4Spbrook     idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local);
507a7812ae4Spbrook     return MAKE_TCGV_I64(idx);
508a7812ae4Spbrook }
509a7812ae4Spbrook 
510a7812ae4Spbrook static inline void tcg_temp_free_internal(int idx)
511c896fe29Sbellard {
512c896fe29Sbellard     TCGContext *s = &tcg_ctx;
513c896fe29Sbellard     TCGTemp *ts;
514641d5fbeSbellard     int k;
515c896fe29Sbellard 
51627bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
51727bfd83cSPeter Maydell     s->temps_in_use--;
51827bfd83cSPeter Maydell     if (s->temps_in_use < 0) {
51927bfd83cSPeter Maydell         fprintf(stderr, "More temporaries freed than allocated!\n");
52027bfd83cSPeter Maydell     }
52127bfd83cSPeter Maydell #endif
52227bfd83cSPeter Maydell 
523e8996ee0Sbellard     assert(idx >= s->nb_globals && idx < s->nb_temps);
524c896fe29Sbellard     ts = &s->temps[idx];
525e8996ee0Sbellard     assert(ts->temp_allocated != 0);
526e8996ee0Sbellard     ts->temp_allocated = 0;
527641d5fbeSbellard     k = ts->base_type;
528641d5fbeSbellard     if (ts->temp_local)
529641d5fbeSbellard         k += TCG_TYPE_COUNT;
530641d5fbeSbellard     ts->next_free_temp = s->first_free_temp[k];
531641d5fbeSbellard     s->first_free_temp[k] = idx;
532e8996ee0Sbellard }
533e8996ee0Sbellard 
534a7812ae4Spbrook void tcg_temp_free_i32(TCGv_i32 arg)
535e8996ee0Sbellard {
536a7812ae4Spbrook     tcg_temp_free_internal(GET_TCGV_I32(arg));
537a7812ae4Spbrook }
538a7812ae4Spbrook 
539a7812ae4Spbrook void tcg_temp_free_i64(TCGv_i64 arg)
540a7812ae4Spbrook {
541a7812ae4Spbrook     tcg_temp_free_internal(GET_TCGV_I64(arg));
542a7812ae4Spbrook }
543a7812ae4Spbrook 
544a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
545a7812ae4Spbrook {
546a7812ae4Spbrook     TCGv_i32 t0;
547a7812ae4Spbrook     t0 = tcg_temp_new_i32();
548e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
549e8996ee0Sbellard     return t0;
550c896fe29Sbellard }
551c896fe29Sbellard 
552a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
553c896fe29Sbellard {
554a7812ae4Spbrook     TCGv_i64 t0;
555a7812ae4Spbrook     t0 = tcg_temp_new_i64();
556e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
557e8996ee0Sbellard     return t0;
558c896fe29Sbellard }
559c896fe29Sbellard 
560a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
561bdffd4a9Saurel32 {
562a7812ae4Spbrook     TCGv_i32 t0;
563a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
564bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
565bdffd4a9Saurel32     return t0;
566bdffd4a9Saurel32 }
567bdffd4a9Saurel32 
568a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
569bdffd4a9Saurel32 {
570a7812ae4Spbrook     TCGv_i64 t0;
571a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
572bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
573bdffd4a9Saurel32     return t0;
574bdffd4a9Saurel32 }
575bdffd4a9Saurel32 
57627bfd83cSPeter Maydell #if defined(CONFIG_DEBUG_TCG)
57727bfd83cSPeter Maydell void tcg_clear_temp_count(void)
57827bfd83cSPeter Maydell {
57927bfd83cSPeter Maydell     TCGContext *s = &tcg_ctx;
58027bfd83cSPeter Maydell     s->temps_in_use = 0;
58127bfd83cSPeter Maydell }
58227bfd83cSPeter Maydell 
58327bfd83cSPeter Maydell int tcg_check_temp_count(void)
58427bfd83cSPeter Maydell {
58527bfd83cSPeter Maydell     TCGContext *s = &tcg_ctx;
58627bfd83cSPeter Maydell     if (s->temps_in_use) {
58727bfd83cSPeter Maydell         /* Clear the count so that we don't give another
58827bfd83cSPeter Maydell          * warning immediately next time around.
58927bfd83cSPeter Maydell          */
59027bfd83cSPeter Maydell         s->temps_in_use = 0;
59127bfd83cSPeter Maydell         return 1;
59227bfd83cSPeter Maydell     }
59327bfd83cSPeter Maydell     return 0;
59427bfd83cSPeter Maydell }
59527bfd83cSPeter Maydell #endif
59627bfd83cSPeter Maydell 
597c896fe29Sbellard void tcg_register_helper(void *func, const char *name)
598c896fe29Sbellard {
599c896fe29Sbellard     TCGContext *s = &tcg_ctx;
600c896fe29Sbellard     int n;
601c896fe29Sbellard     if ((s->nb_helpers + 1) > s->allocated_helpers) {
602c896fe29Sbellard         n = s->allocated_helpers;
603c896fe29Sbellard         if (n == 0) {
604c896fe29Sbellard             n = 4;
605c896fe29Sbellard         } else {
606c896fe29Sbellard             n *= 2;
607c896fe29Sbellard         }
608c896fe29Sbellard         s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo));
609c896fe29Sbellard         s->allocated_helpers = n;
610c896fe29Sbellard     }
6114dc81f28Sbellard     s->helpers[s->nb_helpers].func = (tcg_target_ulong)func;
612c896fe29Sbellard     s->helpers[s->nb_helpers].name = name;
613c896fe29Sbellard     s->nb_helpers++;
614c896fe29Sbellard }
615c896fe29Sbellard 
61639cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment
61739cf05d3Sbellard    and endian swap. Maybe it would be better to do the alignment
61839cf05d3Sbellard    and endian swap in tcg_reg_alloc_call(). */
619a7812ae4Spbrook void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
620a7812ae4Spbrook                    int sizemask, TCGArg ret, int nargs, TCGArg *args)
621c896fe29Sbellard {
622a7812ae4Spbrook     int i;
623a7812ae4Spbrook     int real_args;
624a7812ae4Spbrook     int nb_rets;
625a7812ae4Spbrook     TCGArg *nparam;
6262bece2c8SRichard Henderson 
6272bece2c8SRichard Henderson #if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
6282bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
6292bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
6302bece2c8SRichard Henderson         int is_signed = sizemask & (2 << (i+1)*2);
6312bece2c8SRichard Henderson         if (!is_64bit) {
6322bece2c8SRichard Henderson             TCGv_i64 temp = tcg_temp_new_i64();
6332bece2c8SRichard Henderson             TCGv_i64 orig = MAKE_TCGV_I64(args[i]);
6342bece2c8SRichard Henderson             if (is_signed) {
6352bece2c8SRichard Henderson                 tcg_gen_ext32s_i64(temp, orig);
6362bece2c8SRichard Henderson             } else {
6372bece2c8SRichard Henderson                 tcg_gen_ext32u_i64(temp, orig);
6382bece2c8SRichard Henderson             }
6392bece2c8SRichard Henderson             args[i] = GET_TCGV_I64(temp);
6402bece2c8SRichard Henderson         }
6412bece2c8SRichard Henderson     }
6422bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
6432bece2c8SRichard Henderson 
644efd7f486SEvgeny Voevodin     *s->gen_opc_ptr++ = INDEX_op_call;
645c4afe5c4SEvgeny Voevodin     nparam = s->gen_opparam_ptr++;
646a7812ae4Spbrook     if (ret != TCG_CALL_DUMMY_ARG) {
647a7812ae4Spbrook #if TCG_TARGET_REG_BITS < 64
648a7812ae4Spbrook         if (sizemask & 1) {
649a7812ae4Spbrook #ifdef TCG_TARGET_WORDS_BIGENDIAN
650c4afe5c4SEvgeny Voevodin             *s->gen_opparam_ptr++ = ret + 1;
651c4afe5c4SEvgeny Voevodin             *s->gen_opparam_ptr++ = ret;
652a7812ae4Spbrook #else
653c4afe5c4SEvgeny Voevodin             *s->gen_opparam_ptr++ = ret;
654c4afe5c4SEvgeny Voevodin             *s->gen_opparam_ptr++ = ret + 1;
655a7812ae4Spbrook #endif
656a7812ae4Spbrook             nb_rets = 2;
657a7812ae4Spbrook         } else
658a7812ae4Spbrook #endif
659a7812ae4Spbrook         {
660c4afe5c4SEvgeny Voevodin             *s->gen_opparam_ptr++ = ret;
661a7812ae4Spbrook             nb_rets = 1;
662a7812ae4Spbrook         }
663a7812ae4Spbrook     } else {
664a7812ae4Spbrook         nb_rets = 0;
665a7812ae4Spbrook     }
666a7812ae4Spbrook     real_args = 0;
667a7812ae4Spbrook     for (i = 0; i < nargs; i++) {
668a7812ae4Spbrook #if TCG_TARGET_REG_BITS < 64
6692bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
6702bece2c8SRichard Henderson         if (is_64bit) {
67139cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS
67239cf05d3Sbellard             /* some targets want aligned 64 bit args */
673ebd486d5Smalc             if (real_args & 1) {
674c4afe5c4SEvgeny Voevodin                 *s->gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG;
675ebd486d5Smalc                 real_args++;
67639cf05d3Sbellard             }
67739cf05d3Sbellard #endif
6783f90f252SRichard Henderson 	    /* If stack grows up, then we will be placing successive
6793f90f252SRichard Henderson 	       arguments at lower addresses, which means we need to
6803f90f252SRichard Henderson 	       reverse the order compared to how we would normally
6813f90f252SRichard Henderson 	       treat either big or little-endian.  For those arguments
6823f90f252SRichard Henderson 	       that will wind up in registers, this still works for
6833f90f252SRichard Henderson 	       HPPA (the only current STACK_GROWSUP target) since the
6843f90f252SRichard Henderson 	       argument registers are *also* allocated in decreasing
6853f90f252SRichard Henderson 	       order.  If another such target is added, this logic may
6863f90f252SRichard Henderson 	       have to get more complicated to differentiate between
6873f90f252SRichard Henderson 	       stack arguments and register arguments.  */
6883f90f252SRichard Henderson #if defined(TCG_TARGET_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
689c4afe5c4SEvgeny Voevodin             *s->gen_opparam_ptr++ = args[i] + 1;
690c4afe5c4SEvgeny Voevodin             *s->gen_opparam_ptr++ = args[i];
691c896fe29Sbellard #else
692c4afe5c4SEvgeny Voevodin             *s->gen_opparam_ptr++ = args[i];
693c4afe5c4SEvgeny Voevodin             *s->gen_opparam_ptr++ = args[i] + 1;
694c896fe29Sbellard #endif
695a7812ae4Spbrook             real_args += 2;
6962bece2c8SRichard Henderson             continue;
6972bece2c8SRichard Henderson         }
6982bece2c8SRichard Henderson #endif /* TCG_TARGET_REG_BITS < 64 */
6992bece2c8SRichard Henderson 
700c4afe5c4SEvgeny Voevodin         *s->gen_opparam_ptr++ = args[i];
701a7812ae4Spbrook         real_args++;
702c896fe29Sbellard     }
703c4afe5c4SEvgeny Voevodin     *s->gen_opparam_ptr++ = GET_TCGV_PTR(func);
704a7812ae4Spbrook 
705c4afe5c4SEvgeny Voevodin     *s->gen_opparam_ptr++ = flags;
706a7812ae4Spbrook 
707a7812ae4Spbrook     *nparam = (nb_rets << 16) | (real_args + 1);
708a7812ae4Spbrook 
709a7812ae4Spbrook     /* total parameters, needed to go backward in the instruction stream */
710c4afe5c4SEvgeny Voevodin     *s->gen_opparam_ptr++ = 1 + nb_rets + real_args + 3;
7112bece2c8SRichard Henderson 
7122bece2c8SRichard Henderson #if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
7132bece2c8SRichard Henderson     for (i = 0; i < nargs; ++i) {
7142bece2c8SRichard Henderson         int is_64bit = sizemask & (1 << (i+1)*2);
7152bece2c8SRichard Henderson         if (!is_64bit) {
7162bece2c8SRichard Henderson             TCGv_i64 temp = MAKE_TCGV_I64(args[i]);
7172bece2c8SRichard Henderson             tcg_temp_free_i64(temp);
7182bece2c8SRichard Henderson         }
7192bece2c8SRichard Henderson     }
7202bece2c8SRichard Henderson #endif /* TCG_TARGET_EXTEND_ARGS */
721a7812ae4Spbrook }
722c896fe29Sbellard 
723ac56dd48Spbrook #if TCG_TARGET_REG_BITS == 32
724a7812ae4Spbrook void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
725c896fe29Sbellard                         int c, int right, int arith)
726c896fe29Sbellard {
727cf60bce4Sbellard     if (c == 0) {
728a7812ae4Spbrook         tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
729cf60bce4Sbellard         tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
730cf60bce4Sbellard     } else if (c >= 32) {
731c896fe29Sbellard         c -= 32;
732c896fe29Sbellard         if (right) {
733c896fe29Sbellard             if (arith) {
734a7812ae4Spbrook                 tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
735ac56dd48Spbrook                 tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31);
736c896fe29Sbellard             } else {
737a7812ae4Spbrook                 tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
738ac56dd48Spbrook                 tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
739c896fe29Sbellard             }
740c896fe29Sbellard         } else {
741a7812ae4Spbrook             tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c);
742a7812ae4Spbrook             tcg_gen_movi_i32(TCGV_LOW(ret), 0);
743c896fe29Sbellard         }
744c896fe29Sbellard     } else {
745a7812ae4Spbrook         TCGv_i32 t0, t1;
746c896fe29Sbellard 
747a7812ae4Spbrook         t0 = tcg_temp_new_i32();
748a7812ae4Spbrook         t1 = tcg_temp_new_i32();
749c896fe29Sbellard         if (right) {
750ac56dd48Spbrook             tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c);
751c896fe29Sbellard             if (arith)
752ac56dd48Spbrook                 tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c);
753c896fe29Sbellard             else
754ac56dd48Spbrook                 tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c);
755a7812ae4Spbrook             tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c);
756a7812ae4Spbrook             tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0);
757ac56dd48Spbrook             tcg_gen_mov_i32(TCGV_HIGH(ret), t1);
758c896fe29Sbellard         } else {
759a7812ae4Spbrook             tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c);
760c896fe29Sbellard             /* Note: ret can be the same as arg1, so we use t1 */
761a7812ae4Spbrook             tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c);
762ac56dd48Spbrook             tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c);
763ac56dd48Spbrook             tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0);
764a7812ae4Spbrook             tcg_gen_mov_i32(TCGV_LOW(ret), t1);
765c896fe29Sbellard         }
766a7812ae4Spbrook         tcg_temp_free_i32(t0);
767a7812ae4Spbrook         tcg_temp_free_i32(t1);
768c896fe29Sbellard     }
769c896fe29Sbellard }
770ac56dd48Spbrook #endif
771c896fe29Sbellard 
772be210acbSRichard Henderson 
7738fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
774c896fe29Sbellard {
775c896fe29Sbellard     int i;
776c896fe29Sbellard     TCGTemp *ts;
777c896fe29Sbellard     for(i = 0; i < s->nb_globals; i++) {
778c896fe29Sbellard         ts = &s->temps[i];
779c896fe29Sbellard         if (ts->fixed_reg) {
780c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
781c896fe29Sbellard         } else {
782c896fe29Sbellard             ts->val_type = TEMP_VAL_MEM;
783c896fe29Sbellard         }
784c896fe29Sbellard     }
785e8996ee0Sbellard     for(i = s->nb_globals; i < s->nb_temps; i++) {
786e8996ee0Sbellard         ts = &s->temps[i];
7877dfd8c6aSAurelien Jarno         if (ts->temp_local) {
7887dfd8c6aSAurelien Jarno             ts->val_type = TEMP_VAL_MEM;
7897dfd8c6aSAurelien Jarno         } else {
790e8996ee0Sbellard             ts->val_type = TEMP_VAL_DEAD;
7917dfd8c6aSAurelien Jarno         }
792e8996ee0Sbellard         ts->mem_allocated = 0;
793e8996ee0Sbellard         ts->fixed_reg = 0;
794e8996ee0Sbellard     }
795c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
796c896fe29Sbellard         s->reg_to_temp[i] = -1;
797c896fe29Sbellard     }
798c896fe29Sbellard }
799c896fe29Sbellard 
800ac56dd48Spbrook static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size,
801ac56dd48Spbrook                                  int idx)
802c896fe29Sbellard {
803c896fe29Sbellard     TCGTemp *ts;
804ac56dd48Spbrook 
8057f6f0ae5SStefan Weil     assert(idx >= 0 && idx < s->nb_temps);
806ac56dd48Spbrook     ts = &s->temps[idx];
8077f6f0ae5SStefan Weil     assert(ts);
808ac56dd48Spbrook     if (idx < s->nb_globals) {
809ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
810c896fe29Sbellard     } else {
811641d5fbeSbellard         if (ts->temp_local)
812641d5fbeSbellard             snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
813641d5fbeSbellard         else
814ac56dd48Spbrook             snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
815c896fe29Sbellard     }
816c896fe29Sbellard     return buf;
817c896fe29Sbellard }
818c896fe29Sbellard 
819a7812ae4Spbrook char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg)
820ac56dd48Spbrook {
821a7812ae4Spbrook     return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I32(arg));
822a7812ae4Spbrook }
823a7812ae4Spbrook 
824a7812ae4Spbrook char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg)
825a7812ae4Spbrook {
826a810a2deSblueswir1     return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I64(arg));
827ac56dd48Spbrook }
828ac56dd48Spbrook 
829e8996ee0Sbellard static int helper_cmp(const void *p1, const void *p2)
830e8996ee0Sbellard {
831e8996ee0Sbellard     const TCGHelperInfo *th1 = p1;
832e8996ee0Sbellard     const TCGHelperInfo *th2 = p2;
833e8996ee0Sbellard     if (th1->func < th2->func)
834e8996ee0Sbellard         return -1;
835e8996ee0Sbellard     else if (th1->func == th2->func)
836e8996ee0Sbellard         return 0;
837e8996ee0Sbellard     else
838e8996ee0Sbellard         return 1;
839e8996ee0Sbellard }
840e8996ee0Sbellard 
841e8996ee0Sbellard /* find helper definition (Note: A hash table would be better) */
8424dc81f28Sbellard static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val)
8434dc81f28Sbellard {
844e8996ee0Sbellard     int m, m_min, m_max;
845e8996ee0Sbellard     TCGHelperInfo *th;
846e8996ee0Sbellard     tcg_target_ulong v;
847e8996ee0Sbellard 
848e8996ee0Sbellard     if (unlikely(!s->helpers_sorted)) {
849e8996ee0Sbellard         qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo),
850e8996ee0Sbellard               helper_cmp);
851e8996ee0Sbellard         s->helpers_sorted = 1;
852e8996ee0Sbellard     }
853e8996ee0Sbellard 
854e8996ee0Sbellard     /* binary search */
855e8996ee0Sbellard     m_min = 0;
856e8996ee0Sbellard     m_max = s->nb_helpers - 1;
857e8996ee0Sbellard     while (m_min <= m_max) {
858e8996ee0Sbellard         m = (m_min + m_max) >> 1;
859e8996ee0Sbellard         th = &s->helpers[m];
860e8996ee0Sbellard         v = th->func;
861e8996ee0Sbellard         if (v == val)
862e8996ee0Sbellard             return th;
863e8996ee0Sbellard         else if (val < v) {
864e8996ee0Sbellard             m_max = m - 1;
865e8996ee0Sbellard         } else {
866e8996ee0Sbellard             m_min = m + 1;
867e8996ee0Sbellard         }
8684dc81f28Sbellard     }
8694dc81f28Sbellard     return NULL;
8704dc81f28Sbellard }
8714dc81f28Sbellard 
872f48f3edeSblueswir1 static const char * const cond_name[] =
873f48f3edeSblueswir1 {
8740aed257fSRichard Henderson     [TCG_COND_NEVER] = "never",
8750aed257fSRichard Henderson     [TCG_COND_ALWAYS] = "always",
876f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
877f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
878f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
879f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
880f48f3edeSblueswir1     [TCG_COND_LE] = "le",
881f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
882f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
883f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
884f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
885f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
886f48f3edeSblueswir1 };
887f48f3edeSblueswir1 
888eeacee4dSBlue Swirl void tcg_dump_ops(TCGContext *s)
889c896fe29Sbellard {
890c896fe29Sbellard     const uint16_t *opc_ptr;
891c896fe29Sbellard     const TCGArg *args;
892c896fe29Sbellard     TCGArg arg;
893a9751609SRichard Henderson     TCGOpcode c;
894a9751609SRichard Henderson     int i, k, nb_oargs, nb_iargs, nb_cargs, first_insn;
895c896fe29Sbellard     const TCGOpDef *def;
896c896fe29Sbellard     char buf[128];
897c896fe29Sbellard 
8987e4597d7Sbellard     first_insn = 1;
899*92414b31SEvgeny Voevodin     opc_ptr = s->gen_opc_buf;
900c896fe29Sbellard     args = gen_opparam_buf;
901efd7f486SEvgeny Voevodin     while (opc_ptr < s->gen_opc_ptr) {
902c896fe29Sbellard         c = *opc_ptr++;
903c896fe29Sbellard         def = &tcg_op_defs[c];
9047e4597d7Sbellard         if (c == INDEX_op_debug_insn_start) {
9057e4597d7Sbellard             uint64_t pc;
9067e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
9077e4597d7Sbellard             pc = ((uint64_t)args[1] << 32) | args[0];
9087e4597d7Sbellard #else
9097e4597d7Sbellard             pc = args[0];
9107e4597d7Sbellard #endif
911eeacee4dSBlue Swirl             if (!first_insn) {
912eeacee4dSBlue Swirl                 qemu_log("\n");
913eeacee4dSBlue Swirl             }
914eeacee4dSBlue Swirl             qemu_log(" ---- 0x%" PRIx64, pc);
9157e4597d7Sbellard             first_insn = 0;
9167e4597d7Sbellard             nb_oargs = def->nb_oargs;
9177e4597d7Sbellard             nb_iargs = def->nb_iargs;
9187e4597d7Sbellard             nb_cargs = def->nb_cargs;
9197e4597d7Sbellard         } else if (c == INDEX_op_call) {
920c896fe29Sbellard             TCGArg arg;
9214dc81f28Sbellard 
922c896fe29Sbellard             /* variable number of arguments */
923c896fe29Sbellard             arg = *args++;
924c896fe29Sbellard             nb_oargs = arg >> 16;
925c896fe29Sbellard             nb_iargs = arg & 0xffff;
926c896fe29Sbellard             nb_cargs = def->nb_cargs;
927b03cce8eSbellard 
928eeacee4dSBlue Swirl             qemu_log(" %s ", def->name);
9297e4597d7Sbellard 
930b03cce8eSbellard             /* function name */
931eeacee4dSBlue Swirl             qemu_log("%s",
932eeacee4dSBlue Swirl                      tcg_get_arg_str_idx(s, buf, sizeof(buf),
933eeacee4dSBlue Swirl                                          args[nb_oargs + nb_iargs - 1]));
934b03cce8eSbellard             /* flags */
935eeacee4dSBlue Swirl             qemu_log(",$0x%" TCG_PRIlx, args[nb_oargs + nb_iargs]);
936b03cce8eSbellard             /* nb out args */
937eeacee4dSBlue Swirl             qemu_log(",$%d", nb_oargs);
938b03cce8eSbellard             for(i = 0; i < nb_oargs; i++) {
939eeacee4dSBlue Swirl                 qemu_log(",");
940eeacee4dSBlue Swirl                 qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf),
941eeacee4dSBlue Swirl                                                    args[i]));
942b03cce8eSbellard             }
943b03cce8eSbellard             for(i = 0; i < (nb_iargs - 1); i++) {
944eeacee4dSBlue Swirl                 qemu_log(",");
94539cf05d3Sbellard                 if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) {
946eeacee4dSBlue Swirl                     qemu_log("<dummy>");
94739cf05d3Sbellard                 } else {
948eeacee4dSBlue Swirl                     qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf),
949eeacee4dSBlue Swirl                                                        args[nb_oargs + i]));
950b03cce8eSbellard                 }
95139cf05d3Sbellard             }
952fba3161fSAurelien Jarno         } else if (c == INDEX_op_movi_i32 || c == INDEX_op_movi_i64) {
953e8996ee0Sbellard             tcg_target_ulong val;
954e8996ee0Sbellard             TCGHelperInfo *th;
955e8996ee0Sbellard 
956e8996ee0Sbellard             nb_oargs = def->nb_oargs;
957e8996ee0Sbellard             nb_iargs = def->nb_iargs;
958e8996ee0Sbellard             nb_cargs = def->nb_cargs;
959eeacee4dSBlue Swirl             qemu_log(" %s %s,$", def->name,
960e8996ee0Sbellard                      tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0]));
961e8996ee0Sbellard             val = args[1];
962e8996ee0Sbellard             th = tcg_find_helper(s, val);
963e8996ee0Sbellard             if (th) {
964eeacee4dSBlue Swirl                 qemu_log("%s", th->name);
965e8996ee0Sbellard             } else {
966eeacee4dSBlue Swirl                 if (c == INDEX_op_movi_i32) {
967eeacee4dSBlue Swirl                     qemu_log("0x%x", (uint32_t)val);
968eeacee4dSBlue Swirl                 } else {
969eeacee4dSBlue Swirl                     qemu_log("0x%" PRIx64 , (uint64_t)val);
970eeacee4dSBlue Swirl                 }
971e8996ee0Sbellard             }
972b03cce8eSbellard         } else {
973eeacee4dSBlue Swirl             qemu_log(" %s ", def->name);
974b03cce8eSbellard             if (c == INDEX_op_nopn) {
975c896fe29Sbellard                 /* variable number of arguments */
976c896fe29Sbellard                 nb_cargs = *args;
977c896fe29Sbellard                 nb_oargs = 0;
978c896fe29Sbellard                 nb_iargs = 0;
979c896fe29Sbellard             } else {
980c896fe29Sbellard                 nb_oargs = def->nb_oargs;
981c896fe29Sbellard                 nb_iargs = def->nb_iargs;
982c896fe29Sbellard                 nb_cargs = def->nb_cargs;
983c896fe29Sbellard             }
984c896fe29Sbellard 
985c896fe29Sbellard             k = 0;
986c896fe29Sbellard             for(i = 0; i < nb_oargs; i++) {
987eeacee4dSBlue Swirl                 if (k != 0) {
988eeacee4dSBlue Swirl                     qemu_log(",");
989eeacee4dSBlue Swirl                 }
990eeacee4dSBlue Swirl                 qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf),
991eeacee4dSBlue Swirl                                                    args[k++]));
992c896fe29Sbellard             }
993c896fe29Sbellard             for(i = 0; i < nb_iargs; i++) {
994eeacee4dSBlue Swirl                 if (k != 0) {
995eeacee4dSBlue Swirl                     qemu_log(",");
996eeacee4dSBlue Swirl                 }
997eeacee4dSBlue Swirl                 qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf),
998eeacee4dSBlue Swirl                                                    args[k++]));
999c896fe29Sbellard             }
1000be210acbSRichard Henderson             switch (c) {
1001be210acbSRichard Henderson             case INDEX_op_brcond_i32:
1002ffc5ea09SRichard Henderson             case INDEX_op_setcond_i32:
1003ffc5ea09SRichard Henderson             case INDEX_op_movcond_i32:
1004be210acbSRichard Henderson             case INDEX_op_brcond2_i32:
1005be210acbSRichard Henderson             case INDEX_op_setcond2_i32:
1006ffc5ea09SRichard Henderson             case INDEX_op_brcond_i64:
1007be210acbSRichard Henderson             case INDEX_op_setcond_i64:
1008ffc5ea09SRichard Henderson             case INDEX_op_movcond_i64:
1009eeacee4dSBlue Swirl                 if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]]) {
1010eeacee4dSBlue Swirl                     qemu_log(",%s", cond_name[args[k++]]);
1011eeacee4dSBlue Swirl                 } else {
1012eeacee4dSBlue Swirl                     qemu_log(",$0x%" TCG_PRIlx, args[k++]);
1013eeacee4dSBlue Swirl                 }
1014f48f3edeSblueswir1                 i = 1;
1015be210acbSRichard Henderson                 break;
1016be210acbSRichard Henderson             default:
1017f48f3edeSblueswir1                 i = 0;
1018be210acbSRichard Henderson                 break;
1019be210acbSRichard Henderson             }
1020f48f3edeSblueswir1             for(; i < nb_cargs; i++) {
1021eeacee4dSBlue Swirl                 if (k != 0) {
1022eeacee4dSBlue Swirl                     qemu_log(",");
1023eeacee4dSBlue Swirl                 }
1024c896fe29Sbellard                 arg = args[k++];
1025eeacee4dSBlue Swirl                 qemu_log("$0x%" TCG_PRIlx, arg);
1026c896fe29Sbellard             }
1027b03cce8eSbellard         }
1028eeacee4dSBlue Swirl         qemu_log("\n");
1029c896fe29Sbellard         args += nb_iargs + nb_oargs + nb_cargs;
1030c896fe29Sbellard     }
1031c896fe29Sbellard }
1032c896fe29Sbellard 
1033c896fe29Sbellard /* we give more priority to constraints with less registers */
1034c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
1035c896fe29Sbellard {
1036c896fe29Sbellard     const TCGArgConstraint *arg_ct;
1037c896fe29Sbellard 
1038c896fe29Sbellard     int i, n;
1039c896fe29Sbellard     arg_ct = &def->args_ct[k];
1040c896fe29Sbellard     if (arg_ct->ct & TCG_CT_ALIAS) {
1041c896fe29Sbellard         /* an alias is equivalent to a single register */
1042c896fe29Sbellard         n = 1;
1043c896fe29Sbellard     } else {
1044c896fe29Sbellard         if (!(arg_ct->ct & TCG_CT_REG))
1045c896fe29Sbellard             return 0;
1046c896fe29Sbellard         n = 0;
1047c896fe29Sbellard         for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
1048c896fe29Sbellard             if (tcg_regset_test_reg(arg_ct->u.regs, i))
1049c896fe29Sbellard                 n++;
1050c896fe29Sbellard         }
1051c896fe29Sbellard     }
1052c896fe29Sbellard     return TCG_TARGET_NB_REGS - n + 1;
1053c896fe29Sbellard }
1054c896fe29Sbellard 
1055c896fe29Sbellard /* sort from highest priority to lowest */
1056c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
1057c896fe29Sbellard {
1058c896fe29Sbellard     int i, j, p1, p2, tmp;
1059c896fe29Sbellard 
1060c896fe29Sbellard     for(i = 0; i < n; i++)
1061c896fe29Sbellard         def->sorted_args[start + i] = start + i;
1062c896fe29Sbellard     if (n <= 1)
1063c896fe29Sbellard         return;
1064c896fe29Sbellard     for(i = 0; i < n - 1; i++) {
1065c896fe29Sbellard         for(j = i + 1; j < n; j++) {
1066c896fe29Sbellard             p1 = get_constraint_priority(def, def->sorted_args[start + i]);
1067c896fe29Sbellard             p2 = get_constraint_priority(def, def->sorted_args[start + j]);
1068c896fe29Sbellard             if (p1 < p2) {
1069c896fe29Sbellard                 tmp = def->sorted_args[start + i];
1070c896fe29Sbellard                 def->sorted_args[start + i] = def->sorted_args[start + j];
1071c896fe29Sbellard                 def->sorted_args[start + j] = tmp;
1072c896fe29Sbellard             }
1073c896fe29Sbellard         }
1074c896fe29Sbellard     }
1075c896fe29Sbellard }
1076c896fe29Sbellard 
1077c896fe29Sbellard void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
1078c896fe29Sbellard {
1079a9751609SRichard Henderson     TCGOpcode op;
1080c896fe29Sbellard     TCGOpDef *def;
1081c896fe29Sbellard     const char *ct_str;
1082c896fe29Sbellard     int i, nb_args;
1083c896fe29Sbellard 
1084c896fe29Sbellard     for(;;) {
1085a9751609SRichard Henderson         if (tdefs->op == (TCGOpcode)-1)
1086c896fe29Sbellard             break;
1087c896fe29Sbellard         op = tdefs->op;
1088c3b08d0eSStefan Weil         assert((unsigned)op < NB_OPS);
1089c896fe29Sbellard         def = &tcg_op_defs[op];
1090c68aaa18SStefan Weil #if defined(CONFIG_DEBUG_TCG)
1091c68aaa18SStefan Weil         /* Duplicate entry in op definitions? */
1092c68aaa18SStefan Weil         assert(!def->used);
1093c68aaa18SStefan Weil         def->used = 1;
1094c68aaa18SStefan Weil #endif
1095c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
1096c896fe29Sbellard         for(i = 0; i < nb_args; i++) {
1097c896fe29Sbellard             ct_str = tdefs->args_ct_str[i];
1098c68aaa18SStefan Weil             /* Incomplete TCGTargetOpDef entry? */
1099c68aaa18SStefan Weil             assert(ct_str != NULL);
1100c896fe29Sbellard             tcg_regset_clear(def->args_ct[i].u.regs);
1101c896fe29Sbellard             def->args_ct[i].ct = 0;
1102c896fe29Sbellard             if (ct_str[0] >= '0' && ct_str[0] <= '9') {
1103c896fe29Sbellard                 int oarg;
1104c896fe29Sbellard                 oarg = ct_str[0] - '0';
1105c896fe29Sbellard                 assert(oarg < def->nb_oargs);
1106c896fe29Sbellard                 assert(def->args_ct[oarg].ct & TCG_CT_REG);
1107c896fe29Sbellard                 /* TCG_CT_ALIAS is for the output arguments. The input
11085ff9d6a4Sbellard                    argument is tagged with TCG_CT_IALIAS. */
1109c896fe29Sbellard                 def->args_ct[i] = def->args_ct[oarg];
11105ff9d6a4Sbellard                 def->args_ct[oarg].ct = TCG_CT_ALIAS;
11115ff9d6a4Sbellard                 def->args_ct[oarg].alias_index = i;
1112c896fe29Sbellard                 def->args_ct[i].ct |= TCG_CT_IALIAS;
11135ff9d6a4Sbellard                 def->args_ct[i].alias_index = oarg;
1114c896fe29Sbellard             } else {
1115c896fe29Sbellard                 for(;;) {
1116c896fe29Sbellard                     if (*ct_str == '\0')
1117c896fe29Sbellard                         break;
1118c896fe29Sbellard                     switch(*ct_str) {
1119c896fe29Sbellard                     case 'i':
1120c896fe29Sbellard                         def->args_ct[i].ct |= TCG_CT_CONST;
1121c896fe29Sbellard                         ct_str++;
1122c896fe29Sbellard                         break;
1123c896fe29Sbellard                     default:
1124c896fe29Sbellard                         if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) {
1125c896fe29Sbellard                             fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n",
1126c896fe29Sbellard                                     ct_str, i, def->name);
1127c896fe29Sbellard                             exit(1);
1128c896fe29Sbellard                         }
1129c896fe29Sbellard                     }
1130c896fe29Sbellard                 }
1131c896fe29Sbellard             }
1132c896fe29Sbellard         }
1133c896fe29Sbellard 
1134c68aaa18SStefan Weil         /* TCGTargetOpDef entry with too much information? */
1135c68aaa18SStefan Weil         assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
1136c68aaa18SStefan Weil 
1137c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
1138c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
1139c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
1140c896fe29Sbellard 
1141c896fe29Sbellard #if 0
1142c896fe29Sbellard         {
1143c896fe29Sbellard             int i;
1144c896fe29Sbellard 
1145c896fe29Sbellard             printf("%s: sorted=", def->name);
1146c896fe29Sbellard             for(i = 0; i < def->nb_oargs + def->nb_iargs; i++)
1147c896fe29Sbellard                 printf(" %d", def->sorted_args[i]);
1148c896fe29Sbellard             printf("\n");
1149c896fe29Sbellard         }
1150c896fe29Sbellard #endif
1151c896fe29Sbellard         tdefs++;
1152c896fe29Sbellard     }
1153c896fe29Sbellard 
1154c68aaa18SStefan Weil #if defined(CONFIG_DEBUG_TCG)
1155a9751609SRichard Henderson     i = 0;
1156c68aaa18SStefan Weil     for (op = 0; op < ARRAY_SIZE(tcg_op_defs); op++) {
1157f412c762SRichard Henderson         const TCGOpDef *def = &tcg_op_defs[op];
1158f412c762SRichard Henderson         if (op < INDEX_op_call
1159f412c762SRichard Henderson             || op == INDEX_op_debug_insn_start
1160f412c762SRichard Henderson             || (def->flags & TCG_OPF_NOT_PRESENT)) {
1161c68aaa18SStefan Weil             /* Wrong entry in op definitions? */
1162f412c762SRichard Henderson             if (def->used) {
1163f412c762SRichard Henderson                 fprintf(stderr, "Invalid op definition for %s\n", def->name);
1164a9751609SRichard Henderson                 i = 1;
1165a9751609SRichard Henderson             }
1166c68aaa18SStefan Weil         } else {
1167c68aaa18SStefan Weil             /* Missing entry in op definitions? */
1168f412c762SRichard Henderson             if (!def->used) {
1169f412c762SRichard Henderson                 fprintf(stderr, "Missing op definition for %s\n", def->name);
1170a9751609SRichard Henderson                 i = 1;
1171c68aaa18SStefan Weil             }
1172c68aaa18SStefan Weil         }
1173a9751609SRichard Henderson     }
1174a9751609SRichard Henderson     if (i == 1) {
1175a9751609SRichard Henderson         tcg_abort();
1176a9751609SRichard Henderson     }
1177c68aaa18SStefan Weil #endif
1178c896fe29Sbellard }
1179c896fe29Sbellard 
1180c896fe29Sbellard #ifdef USE_LIVENESS_ANALYSIS
1181c896fe29Sbellard 
1182c896fe29Sbellard /* set a nop for an operation using 'nb_args' */
1183c896fe29Sbellard static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr,
1184c896fe29Sbellard                                TCGArg *args, int nb_args)
1185c896fe29Sbellard {
1186c896fe29Sbellard     if (nb_args == 0) {
1187c896fe29Sbellard         *opc_ptr = INDEX_op_nop;
1188c896fe29Sbellard     } else {
1189c896fe29Sbellard         *opc_ptr = INDEX_op_nopn;
1190c896fe29Sbellard         args[0] = nb_args;
1191c896fe29Sbellard         args[nb_args - 1] = nb_args;
1192c896fe29Sbellard     }
1193c896fe29Sbellard }
1194c896fe29Sbellard 
11959c43b68dSAurelien Jarno /* liveness analysis: end of function: all temps are dead, and globals
11969c43b68dSAurelien Jarno    should be in memory. */
11979c43b68dSAurelien Jarno static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps,
11989c43b68dSAurelien Jarno                                    uint8_t *mem_temps)
1199c896fe29Sbellard {
12009c43b68dSAurelien Jarno     memset(dead_temps, 1, s->nb_temps);
12019c43b68dSAurelien Jarno     memset(mem_temps, 1, s->nb_globals);
12029c43b68dSAurelien Jarno     memset(mem_temps + s->nb_globals, 0, s->nb_temps - s->nb_globals);
1203c896fe29Sbellard }
1204c896fe29Sbellard 
12059c43b68dSAurelien Jarno /* liveness analysis: end of basic block: all temps are dead, globals
12069c43b68dSAurelien Jarno    and local temps should be in memory. */
12079c43b68dSAurelien Jarno static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps,
12089c43b68dSAurelien Jarno                                  uint8_t *mem_temps)
1209641d5fbeSbellard {
1210641d5fbeSbellard     int i;
1211641d5fbeSbellard 
12129c43b68dSAurelien Jarno     memset(dead_temps, 1, s->nb_temps);
12139c43b68dSAurelien Jarno     memset(mem_temps, 1, s->nb_globals);
1214641d5fbeSbellard     for(i = s->nb_globals; i < s->nb_temps; i++) {
12159c43b68dSAurelien Jarno         mem_temps[i] = s->temps[i].temp_local;
1216641d5fbeSbellard     }
1217641d5fbeSbellard }
1218641d5fbeSbellard 
1219866cb6cbSAurelien Jarno /* Liveness analysis : update the opc_dead_args array to tell if a
1220c896fe29Sbellard    given input arguments is dead. Instructions updating dead
1221c896fe29Sbellard    temporaries are removed. */
12228fcd3692Sblueswir1 static void tcg_liveness_analysis(TCGContext *s)
1223c896fe29Sbellard {
1224a9751609SRichard Henderson     int i, op_index, nb_args, nb_iargs, nb_oargs, arg, nb_ops;
1225a9751609SRichard Henderson     TCGOpcode op;
1226c896fe29Sbellard     TCGArg *args;
1227c896fe29Sbellard     const TCGOpDef *def;
12289c43b68dSAurelien Jarno     uint8_t *dead_temps, *mem_temps;
1229ec7a869dSAurelien Jarno     uint16_t dead_args;
1230ec7a869dSAurelien Jarno     uint8_t sync_args;
1231c896fe29Sbellard 
1232efd7f486SEvgeny Voevodin     s->gen_opc_ptr++; /* skip end */
1233c896fe29Sbellard 
1234*92414b31SEvgeny Voevodin     nb_ops = s->gen_opc_ptr - s->gen_opc_buf;
1235c896fe29Sbellard 
1236866cb6cbSAurelien Jarno     s->op_dead_args = tcg_malloc(nb_ops * sizeof(uint16_t));
1237ec7a869dSAurelien Jarno     s->op_sync_args = tcg_malloc(nb_ops * sizeof(uint8_t));
1238c896fe29Sbellard 
1239c896fe29Sbellard     dead_temps = tcg_malloc(s->nb_temps);
12409c43b68dSAurelien Jarno     mem_temps = tcg_malloc(s->nb_temps);
12419c43b68dSAurelien Jarno     tcg_la_func_end(s, dead_temps, mem_temps);
1242c896fe29Sbellard 
1243c4afe5c4SEvgeny Voevodin     args = s->gen_opparam_ptr;
1244c896fe29Sbellard     op_index = nb_ops - 1;
1245c896fe29Sbellard     while (op_index >= 0) {
1246*92414b31SEvgeny Voevodin         op = s->gen_opc_buf[op_index];
1247c896fe29Sbellard         def = &tcg_op_defs[op];
1248c896fe29Sbellard         switch(op) {
1249c896fe29Sbellard         case INDEX_op_call:
1250c6e113f5Sbellard             {
1251c6e113f5Sbellard                 int call_flags;
1252c6e113f5Sbellard 
1253c896fe29Sbellard                 nb_args = args[-1];
1254c896fe29Sbellard                 args -= nb_args;
1255c896fe29Sbellard                 nb_iargs = args[0] & 0xffff;
1256c896fe29Sbellard                 nb_oargs = args[0] >> 16;
1257c896fe29Sbellard                 args++;
1258c6e113f5Sbellard                 call_flags = args[nb_oargs + nb_iargs];
1259c6e113f5Sbellard 
1260c6e113f5Sbellard                 /* pure functions can be removed if their result is not
1261c6e113f5Sbellard                    used */
126278505279SAurelien Jarno                 if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
1263c6e113f5Sbellard                     for(i = 0; i < nb_oargs; i++) {
1264c6e113f5Sbellard                         arg = args[i];
12659c43b68dSAurelien Jarno                         if (!dead_temps[arg] || mem_temps[arg]) {
1266c6e113f5Sbellard                             goto do_not_remove_call;
1267c6e113f5Sbellard                         }
12689c43b68dSAurelien Jarno                     }
1269*92414b31SEvgeny Voevodin                     tcg_set_nop(s, s->gen_opc_buf + op_index,
1270c6e113f5Sbellard                                 args - 1, nb_args);
1271c6e113f5Sbellard                 } else {
1272c6e113f5Sbellard                 do_not_remove_call:
1273c896fe29Sbellard 
1274c896fe29Sbellard                     /* output args are dead */
12756b64b624SAurelien Jarno                     dead_args = 0;
1276ec7a869dSAurelien Jarno                     sync_args = 0;
1277c896fe29Sbellard                     for(i = 0; i < nb_oargs; i++) {
1278c896fe29Sbellard                         arg = args[i];
12796b64b624SAurelien Jarno                         if (dead_temps[arg]) {
12806b64b624SAurelien Jarno                             dead_args |= (1 << i);
12816b64b624SAurelien Jarno                         }
12829c43b68dSAurelien Jarno                         if (mem_temps[arg]) {
12839c43b68dSAurelien Jarno                             sync_args |= (1 << i);
12849c43b68dSAurelien Jarno                         }
1285c896fe29Sbellard                         dead_temps[arg] = 1;
12869c43b68dSAurelien Jarno                         mem_temps[arg] = 0;
1287c896fe29Sbellard                     }
1288c896fe29Sbellard 
128978505279SAurelien Jarno                     if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
129078505279SAurelien Jarno                         /* globals should be synced to memory */
129178505279SAurelien Jarno                         memset(mem_temps, 1, s->nb_globals);
129278505279SAurelien Jarno                     }
129378505279SAurelien Jarno                     if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
129478505279SAurelien Jarno                                         TCG_CALL_NO_READ_GLOBALS))) {
12959c43b68dSAurelien Jarno                         /* globals should go back to memory */
12969c43b68dSAurelien Jarno                         memset(dead_temps, 1, s->nb_globals);
1297b9c18f56Saurel32                     }
1298c896fe29Sbellard 
1299c896fe29Sbellard                     /* input args are live */
1300866cb6cbSAurelien Jarno                     for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
1301866cb6cbSAurelien Jarno                         arg = args[i];
130239cf05d3Sbellard                         if (arg != TCG_CALL_DUMMY_ARG) {
1303c896fe29Sbellard                             if (dead_temps[arg]) {
1304866cb6cbSAurelien Jarno                                 dead_args |= (1 << i);
1305c896fe29Sbellard                             }
1306c896fe29Sbellard                             dead_temps[arg] = 0;
1307c896fe29Sbellard                         }
130839cf05d3Sbellard                     }
1309866cb6cbSAurelien Jarno                     s->op_dead_args[op_index] = dead_args;
1310ec7a869dSAurelien Jarno                     s->op_sync_args[op_index] = sync_args;
1311c6e113f5Sbellard                 }
1312c896fe29Sbellard                 args--;
1313c6e113f5Sbellard             }
1314c896fe29Sbellard             break;
13157e4597d7Sbellard         case INDEX_op_debug_insn_start:
13167e4597d7Sbellard             args -= def->nb_args;
13177e4597d7Sbellard             break;
1318c896fe29Sbellard         case INDEX_op_nopn:
1319c896fe29Sbellard             nb_args = args[-1];
1320c896fe29Sbellard             args -= nb_args;
1321c896fe29Sbellard             break;
13225ff9d6a4Sbellard         case INDEX_op_discard:
13235ff9d6a4Sbellard             args--;
13245ff9d6a4Sbellard             /* mark the temporary as dead */
13255ff9d6a4Sbellard             dead_temps[args[0]] = 1;
13269c43b68dSAurelien Jarno             mem_temps[args[0]] = 0;
13275ff9d6a4Sbellard             break;
1328c896fe29Sbellard         case INDEX_op_end:
1329c896fe29Sbellard             break;
13301305c451SRichard Henderson 
13311305c451SRichard Henderson         case INDEX_op_add2_i32:
13321305c451SRichard Henderson         case INDEX_op_sub2_i32:
13331305c451SRichard Henderson             args -= 6;
13341305c451SRichard Henderson             nb_iargs = 4;
13351305c451SRichard Henderson             nb_oargs = 2;
13361305c451SRichard Henderson             /* Test if the high part of the operation is dead, but not
13371305c451SRichard Henderson                the low part.  The result can be optimized to a simple
13381305c451SRichard Henderson                add or sub.  This happens often for x86_64 guest when the
13391305c451SRichard Henderson                cpu mode is set to 32 bit.  */
13403c5645faSKirill Batuzov             if (dead_temps[args[1]] && !mem_temps[args[1]]) {
13413c5645faSKirill Batuzov                 if (dead_temps[args[0]] && !mem_temps[args[0]]) {
13421305c451SRichard Henderson                     goto do_remove;
13431305c451SRichard Henderson                 }
13441305c451SRichard Henderson                 /* Create the single operation plus nop.  */
13451305c451SRichard Henderson                 if (op == INDEX_op_add2_i32) {
13461305c451SRichard Henderson                     op = INDEX_op_add_i32;
13471305c451SRichard Henderson                 } else {
13481305c451SRichard Henderson                     op = INDEX_op_sub_i32;
13491305c451SRichard Henderson                 }
1350*92414b31SEvgeny Voevodin                 s->gen_opc_buf[op_index] = op;
13511305c451SRichard Henderson                 args[1] = args[2];
13521305c451SRichard Henderson                 args[2] = args[4];
1353*92414b31SEvgeny Voevodin                 assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop);
1354*92414b31SEvgeny Voevodin                 tcg_set_nop(s, s->gen_opc_buf + op_index + 1, args + 3, 3);
13551305c451SRichard Henderson                 /* Fall through and mark the single-word operation live.  */
13561305c451SRichard Henderson                 nb_iargs = 2;
13571305c451SRichard Henderson                 nb_oargs = 1;
13581305c451SRichard Henderson             }
13591305c451SRichard Henderson             goto do_not_remove;
13601305c451SRichard Henderson 
13611414968aSRichard Henderson         case INDEX_op_mulu2_i32:
13621414968aSRichard Henderson             args -= 4;
13631414968aSRichard Henderson             nb_iargs = 2;
13641414968aSRichard Henderson             nb_oargs = 2;
13651414968aSRichard Henderson             /* Likewise, test for the high part of the operation dead.  */
13663c5645faSKirill Batuzov             if (dead_temps[args[1]] && !mem_temps[args[1]]) {
13673c5645faSKirill Batuzov                 if (dead_temps[args[0]] && !mem_temps[args[0]]) {
13681414968aSRichard Henderson                     goto do_remove;
13691414968aSRichard Henderson                 }
1370*92414b31SEvgeny Voevodin                 s->gen_opc_buf[op_index] = op = INDEX_op_mul_i32;
13711414968aSRichard Henderson                 args[1] = args[2];
13721414968aSRichard Henderson                 args[2] = args[3];
1373*92414b31SEvgeny Voevodin                 assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop);
1374*92414b31SEvgeny Voevodin                 tcg_set_nop(s, s->gen_opc_buf + op_index + 1, args + 3, 1);
13751414968aSRichard Henderson                 /* Fall through and mark the single-word operation live.  */
13761414968aSRichard Henderson                 nb_oargs = 1;
13771414968aSRichard Henderson             }
13781414968aSRichard Henderson             goto do_not_remove;
13791414968aSRichard Henderson 
1380c896fe29Sbellard         default:
13811305c451SRichard Henderson             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1382c896fe29Sbellard             args -= def->nb_args;
1383c896fe29Sbellard             nb_iargs = def->nb_iargs;
1384c896fe29Sbellard             nb_oargs = def->nb_oargs;
1385c896fe29Sbellard 
1386c896fe29Sbellard             /* Test if the operation can be removed because all
13875ff9d6a4Sbellard                its outputs are dead. We assume that nb_oargs == 0
13885ff9d6a4Sbellard                implies side effects */
13895ff9d6a4Sbellard             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
1390c896fe29Sbellard                 for(i = 0; i < nb_oargs; i++) {
1391c896fe29Sbellard                     arg = args[i];
13929c43b68dSAurelien Jarno                     if (!dead_temps[arg] || mem_temps[arg]) {
1393c896fe29Sbellard                         goto do_not_remove;
1394c896fe29Sbellard                     }
13959c43b68dSAurelien Jarno                 }
13961305c451SRichard Henderson             do_remove:
1397*92414b31SEvgeny Voevodin                 tcg_set_nop(s, s->gen_opc_buf + op_index, args, def->nb_args);
1398c896fe29Sbellard #ifdef CONFIG_PROFILER
1399a23a9ec6Sbellard                 s->del_op_count++;
1400c896fe29Sbellard #endif
1401c896fe29Sbellard             } else {
1402c896fe29Sbellard             do_not_remove:
1403c896fe29Sbellard 
1404c896fe29Sbellard                 /* output args are dead */
14056b64b624SAurelien Jarno                 dead_args = 0;
1406ec7a869dSAurelien Jarno                 sync_args = 0;
1407c896fe29Sbellard                 for(i = 0; i < nb_oargs; i++) {
1408c896fe29Sbellard                     arg = args[i];
14096b64b624SAurelien Jarno                     if (dead_temps[arg]) {
14106b64b624SAurelien Jarno                         dead_args |= (1 << i);
14116b64b624SAurelien Jarno                     }
14129c43b68dSAurelien Jarno                     if (mem_temps[arg]) {
14139c43b68dSAurelien Jarno                         sync_args |= (1 << i);
14149c43b68dSAurelien Jarno                     }
1415c896fe29Sbellard                     dead_temps[arg] = 1;
14169c43b68dSAurelien Jarno                     mem_temps[arg] = 0;
1417c896fe29Sbellard                 }
1418c896fe29Sbellard 
1419c896fe29Sbellard                 /* if end of basic block, update */
1420c896fe29Sbellard                 if (def->flags & TCG_OPF_BB_END) {
14219c43b68dSAurelien Jarno                     tcg_la_bb_end(s, dead_temps, mem_temps);
14223d5c5f87SAurelien Jarno                 } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
14233d5c5f87SAurelien Jarno                     /* globals should be synced to memory */
14249c43b68dSAurelien Jarno                     memset(mem_temps, 1, s->nb_globals);
1425c896fe29Sbellard                 }
1426c896fe29Sbellard 
1427c896fe29Sbellard                 /* input args are live */
1428866cb6cbSAurelien Jarno                 for(i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
1429866cb6cbSAurelien Jarno                     arg = args[i];
1430c896fe29Sbellard                     if (dead_temps[arg]) {
1431866cb6cbSAurelien Jarno                         dead_args |= (1 << i);
1432c896fe29Sbellard                     }
1433c896fe29Sbellard                     dead_temps[arg] = 0;
1434c896fe29Sbellard                 }
1435866cb6cbSAurelien Jarno                 s->op_dead_args[op_index] = dead_args;
1436ec7a869dSAurelien Jarno                 s->op_sync_args[op_index] = sync_args;
1437c896fe29Sbellard             }
1438c896fe29Sbellard             break;
1439c896fe29Sbellard         }
1440c896fe29Sbellard         op_index--;
1441c896fe29Sbellard     }
1442c896fe29Sbellard 
1443c896fe29Sbellard     if (args != gen_opparam_buf)
1444c896fe29Sbellard         tcg_abort();
1445c896fe29Sbellard }
1446c896fe29Sbellard #else
1447c896fe29Sbellard /* dummy liveness analysis */
1448655feed5Smalc static void tcg_liveness_analysis(TCGContext *s)
1449c896fe29Sbellard {
1450c896fe29Sbellard     int nb_ops;
1451*92414b31SEvgeny Voevodin     nb_ops = s->gen_opc_ptr - s->gen_opc_buf;
1452c896fe29Sbellard 
1453866cb6cbSAurelien Jarno     s->op_dead_args = tcg_malloc(nb_ops * sizeof(uint16_t));
1454866cb6cbSAurelien Jarno     memset(s->op_dead_args, 0, nb_ops * sizeof(uint16_t));
1455ec7a869dSAurelien Jarno     s->op_sync_args = tcg_malloc(nb_ops * sizeof(uint8_t));
1456ec7a869dSAurelien Jarno     memset(s->op_sync_args, 0, nb_ops * sizeof(uint8_t));
1457c896fe29Sbellard }
1458c896fe29Sbellard #endif
1459c896fe29Sbellard 
1460c896fe29Sbellard #ifndef NDEBUG
1461c896fe29Sbellard static void dump_regs(TCGContext *s)
1462c896fe29Sbellard {
1463c896fe29Sbellard     TCGTemp *ts;
1464c896fe29Sbellard     int i;
1465c896fe29Sbellard     char buf[64];
1466c896fe29Sbellard 
1467c896fe29Sbellard     for(i = 0; i < s->nb_temps; i++) {
1468c896fe29Sbellard         ts = &s->temps[i];
1469ac56dd48Spbrook         printf("  %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i));
1470c896fe29Sbellard         switch(ts->val_type) {
1471c896fe29Sbellard         case TEMP_VAL_REG:
1472c896fe29Sbellard             printf("%s", tcg_target_reg_names[ts->reg]);
1473c896fe29Sbellard             break;
1474c896fe29Sbellard         case TEMP_VAL_MEM:
1475c896fe29Sbellard             printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]);
1476c896fe29Sbellard             break;
1477c896fe29Sbellard         case TEMP_VAL_CONST:
1478c896fe29Sbellard             printf("$0x%" TCG_PRIlx, ts->val);
1479c896fe29Sbellard             break;
1480c896fe29Sbellard         case TEMP_VAL_DEAD:
1481c896fe29Sbellard             printf("D");
1482c896fe29Sbellard             break;
1483c896fe29Sbellard         default:
1484c896fe29Sbellard             printf("???");
1485c896fe29Sbellard             break;
1486c896fe29Sbellard         }
1487c896fe29Sbellard         printf("\n");
1488c896fe29Sbellard     }
1489c896fe29Sbellard 
1490c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
1491c896fe29Sbellard         if (s->reg_to_temp[i] >= 0) {
1492c896fe29Sbellard             printf("%s: %s\n",
1493c896fe29Sbellard                    tcg_target_reg_names[i],
1494ac56dd48Spbrook                    tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i]));
1495c896fe29Sbellard         }
1496c896fe29Sbellard     }
1497c896fe29Sbellard }
1498c896fe29Sbellard 
1499c896fe29Sbellard static void check_regs(TCGContext *s)
1500c896fe29Sbellard {
1501c896fe29Sbellard     int reg, k;
1502c896fe29Sbellard     TCGTemp *ts;
1503c896fe29Sbellard     char buf[64];
1504c896fe29Sbellard 
1505c896fe29Sbellard     for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1506c896fe29Sbellard         k = s->reg_to_temp[reg];
1507c896fe29Sbellard         if (k >= 0) {
1508c896fe29Sbellard             ts = &s->temps[k];
1509c896fe29Sbellard             if (ts->val_type != TEMP_VAL_REG ||
1510c896fe29Sbellard                 ts->reg != reg) {
1511c896fe29Sbellard                 printf("Inconsistency for register %s:\n",
1512c896fe29Sbellard                        tcg_target_reg_names[reg]);
1513b03cce8eSbellard                 goto fail;
1514c896fe29Sbellard             }
1515c896fe29Sbellard         }
1516c896fe29Sbellard     }
1517c896fe29Sbellard     for(k = 0; k < s->nb_temps; k++) {
1518c896fe29Sbellard         ts = &s->temps[k];
1519c896fe29Sbellard         if (ts->val_type == TEMP_VAL_REG &&
1520c896fe29Sbellard             !ts->fixed_reg &&
1521c896fe29Sbellard             s->reg_to_temp[ts->reg] != k) {
1522c896fe29Sbellard                 printf("Inconsistency for temp %s:\n",
1523ac56dd48Spbrook                        tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
1524b03cce8eSbellard         fail:
1525c896fe29Sbellard                 printf("reg state:\n");
1526c896fe29Sbellard                 dump_regs(s);
1527c896fe29Sbellard                 tcg_abort();
1528c896fe29Sbellard         }
1529c896fe29Sbellard     }
1530c896fe29Sbellard }
1531c896fe29Sbellard #endif
1532c896fe29Sbellard 
1533c896fe29Sbellard static void temp_allocate_frame(TCGContext *s, int temp)
1534c896fe29Sbellard {
1535c896fe29Sbellard     TCGTemp *ts;
1536c896fe29Sbellard     ts = &s->temps[temp];
15379b9c37c3SRichard Henderson #if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64)
15389b9c37c3SRichard Henderson     /* Sparc64 stack is accessed with offset of 2047 */
1539b591dc59SBlue Swirl     s->current_frame_offset = (s->current_frame_offset +
1540b591dc59SBlue Swirl                                (tcg_target_long)sizeof(tcg_target_long) - 1) &
1541b591dc59SBlue Swirl         ~(sizeof(tcg_target_long) - 1);
1542f44c9960SBlue Swirl #endif
1543b591dc59SBlue Swirl     if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) >
1544b591dc59SBlue Swirl         s->frame_end) {
15455ff9d6a4Sbellard         tcg_abort();
1546b591dc59SBlue Swirl     }
1547c896fe29Sbellard     ts->mem_offset = s->current_frame_offset;
1548c896fe29Sbellard     ts->mem_reg = s->frame_reg;
1549c896fe29Sbellard     ts->mem_allocated = 1;
1550b591dc59SBlue Swirl     s->current_frame_offset += (tcg_target_long)sizeof(tcg_target_long);
1551c896fe29Sbellard }
1552c896fe29Sbellard 
15537f6ceedfSAurelien Jarno /* sync register 'reg' by saving it to the corresponding temporary */
15547f6ceedfSAurelien Jarno static inline void tcg_reg_sync(TCGContext *s, int reg)
1555c896fe29Sbellard {
1556c896fe29Sbellard     TCGTemp *ts;
1557c896fe29Sbellard     int temp;
1558c896fe29Sbellard 
1559c896fe29Sbellard     temp = s->reg_to_temp[reg];
1560c896fe29Sbellard     ts = &s->temps[temp];
1561c896fe29Sbellard     assert(ts->val_type == TEMP_VAL_REG);
15627f6ceedfSAurelien Jarno     if (!ts->mem_coherent && !ts->fixed_reg) {
15637f6ceedfSAurelien Jarno         if (!ts->mem_allocated) {
1564c896fe29Sbellard             temp_allocate_frame(s, temp);
15657f6ceedfSAurelien Jarno         }
1566e4d5434cSblueswir1         tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1567c896fe29Sbellard     }
15687f6ceedfSAurelien Jarno     ts->mem_coherent = 1;
15697f6ceedfSAurelien Jarno }
15707f6ceedfSAurelien Jarno 
15717f6ceedfSAurelien Jarno /* free register 'reg' by spilling the corresponding temporary if necessary */
15727f6ceedfSAurelien Jarno static void tcg_reg_free(TCGContext *s, int reg)
15737f6ceedfSAurelien Jarno {
15747f6ceedfSAurelien Jarno     int temp;
15757f6ceedfSAurelien Jarno 
15767f6ceedfSAurelien Jarno     temp = s->reg_to_temp[reg];
15777f6ceedfSAurelien Jarno     if (temp != -1) {
15787f6ceedfSAurelien Jarno         tcg_reg_sync(s, reg);
15797f6ceedfSAurelien Jarno         s->temps[temp].val_type = TEMP_VAL_MEM;
1580c896fe29Sbellard         s->reg_to_temp[reg] = -1;
1581c896fe29Sbellard     }
1582c896fe29Sbellard }
1583c896fe29Sbellard 
1584c896fe29Sbellard /* Allocate a register belonging to reg1 & ~reg2 */
1585c896fe29Sbellard static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2)
1586c896fe29Sbellard {
1587c896fe29Sbellard     int i, reg;
1588c896fe29Sbellard     TCGRegSet reg_ct;
1589c896fe29Sbellard 
1590c896fe29Sbellard     tcg_regset_andnot(reg_ct, reg1, reg2);
1591c896fe29Sbellard 
1592c896fe29Sbellard     /* first try free registers */
15930954d0d9Sblueswir1     for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
1594c896fe29Sbellard         reg = tcg_target_reg_alloc_order[i];
1595c896fe29Sbellard         if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1)
1596c896fe29Sbellard             return reg;
1597c896fe29Sbellard     }
1598c896fe29Sbellard 
1599c896fe29Sbellard     /* XXX: do better spill choice */
16000954d0d9Sblueswir1     for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
1601c896fe29Sbellard         reg = tcg_target_reg_alloc_order[i];
1602c896fe29Sbellard         if (tcg_regset_test_reg(reg_ct, reg)) {
1603c896fe29Sbellard             tcg_reg_free(s, reg);
1604c896fe29Sbellard             return reg;
1605c896fe29Sbellard         }
1606c896fe29Sbellard     }
1607c896fe29Sbellard 
1608c896fe29Sbellard     tcg_abort();
1609c896fe29Sbellard }
1610c896fe29Sbellard 
1611639368ddSAurelien Jarno /* mark a temporary as dead. */
1612639368ddSAurelien Jarno static inline void temp_dead(TCGContext *s, int temp)
1613639368ddSAurelien Jarno {
1614639368ddSAurelien Jarno     TCGTemp *ts;
1615639368ddSAurelien Jarno 
1616639368ddSAurelien Jarno     ts = &s->temps[temp];
1617639368ddSAurelien Jarno     if (!ts->fixed_reg) {
1618639368ddSAurelien Jarno         if (ts->val_type == TEMP_VAL_REG) {
1619639368ddSAurelien Jarno             s->reg_to_temp[ts->reg] = -1;
1620639368ddSAurelien Jarno         }
1621639368ddSAurelien Jarno         if (temp < s->nb_globals || (ts->temp_local && ts->mem_allocated)) {
1622639368ddSAurelien Jarno             ts->val_type = TEMP_VAL_MEM;
1623639368ddSAurelien Jarno         } else {
1624639368ddSAurelien Jarno             ts->val_type = TEMP_VAL_DEAD;
1625639368ddSAurelien Jarno         }
1626639368ddSAurelien Jarno     }
1627639368ddSAurelien Jarno }
1628639368ddSAurelien Jarno 
16291ad80729SAurelien Jarno /* sync a temporary to memory. 'allocated_regs' is used in case a
1630e8996ee0Sbellard    temporary registers needs to be allocated to store a constant. */
16311ad80729SAurelien Jarno static inline void temp_sync(TCGContext *s, int temp, TCGRegSet allocated_regs)
1632c896fe29Sbellard {
1633c896fe29Sbellard     TCGTemp *ts;
1634c896fe29Sbellard 
1635641d5fbeSbellard     ts = &s->temps[temp];
1636c896fe29Sbellard     if (!ts->fixed_reg) {
1637e8996ee0Sbellard         switch(ts->val_type) {
16381ad80729SAurelien Jarno         case TEMP_VAL_CONST:
16391ad80729SAurelien Jarno             ts->reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
16401ad80729SAurelien Jarno                                     allocated_regs);
16411ad80729SAurelien Jarno             ts->val_type = TEMP_VAL_REG;
16421ad80729SAurelien Jarno             s->reg_to_temp[ts->reg] = temp;
16431ad80729SAurelien Jarno             ts->mem_coherent = 0;
16441ad80729SAurelien Jarno             tcg_out_movi(s, ts->type, ts->reg, ts->val);
16451ad80729SAurelien Jarno             /* fallthrough*/
1646e8996ee0Sbellard         case TEMP_VAL_REG:
16471ad80729SAurelien Jarno             tcg_reg_sync(s, ts->reg);
1648e8996ee0Sbellard             break;
1649e8996ee0Sbellard         case TEMP_VAL_DEAD:
1650e8996ee0Sbellard         case TEMP_VAL_MEM:
1651e8996ee0Sbellard             break;
1652e8996ee0Sbellard         default:
1653e8996ee0Sbellard             tcg_abort();
1654c896fe29Sbellard         }
1655c896fe29Sbellard     }
1656c896fe29Sbellard }
1657641d5fbeSbellard 
16581ad80729SAurelien Jarno /* save a temporary to memory. 'allocated_regs' is used in case a
16591ad80729SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
16601ad80729SAurelien Jarno static inline void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs)
16611ad80729SAurelien Jarno {
16622c0366f0SAurelien Jarno #ifdef USE_LIVENESS_ANALYSIS
16632c0366f0SAurelien Jarno     /* The liveness analysis already ensures that globals are back
16642c0366f0SAurelien Jarno        in memory. Keep an assert for safety. */
16652c0366f0SAurelien Jarno     assert(s->temps[temp].val_type == TEMP_VAL_MEM || s->temps[temp].fixed_reg);
16662c0366f0SAurelien Jarno #else
16671ad80729SAurelien Jarno     temp_sync(s, temp, allocated_regs);
16681ad80729SAurelien Jarno     temp_dead(s, temp);
16692c0366f0SAurelien Jarno #endif
16701ad80729SAurelien Jarno }
16711ad80729SAurelien Jarno 
16729814dd27SDong Xu Wang /* save globals to their canonical location and assume they can be
1673641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
1674641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
1675641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
1676641d5fbeSbellard {
1677641d5fbeSbellard     int i;
1678641d5fbeSbellard 
1679641d5fbeSbellard     for(i = 0; i < s->nb_globals; i++) {
1680641d5fbeSbellard         temp_save(s, i, allocated_regs);
1681641d5fbeSbellard     }
1682e5097dc8Sbellard }
1683e5097dc8Sbellard 
16843d5c5f87SAurelien Jarno /* sync globals to their canonical location and assume they can be
16853d5c5f87SAurelien Jarno    read by the following code. 'allocated_regs' is used in case a
16863d5c5f87SAurelien Jarno    temporary registers needs to be allocated to store a constant. */
16873d5c5f87SAurelien Jarno static void sync_globals(TCGContext *s, TCGRegSet allocated_regs)
16883d5c5f87SAurelien Jarno {
16893d5c5f87SAurelien Jarno     int i;
16903d5c5f87SAurelien Jarno 
16913d5c5f87SAurelien Jarno     for (i = 0; i < s->nb_globals; i++) {
16923d5c5f87SAurelien Jarno #ifdef USE_LIVENESS_ANALYSIS
16933d5c5f87SAurelien Jarno         assert(s->temps[i].val_type != TEMP_VAL_REG || s->temps[i].fixed_reg ||
16943d5c5f87SAurelien Jarno                s->temps[i].mem_coherent);
16953d5c5f87SAurelien Jarno #else
16963d5c5f87SAurelien Jarno         temp_sync(s, i, allocated_regs);
16973d5c5f87SAurelien Jarno #endif
16983d5c5f87SAurelien Jarno     }
16993d5c5f87SAurelien Jarno }
17003d5c5f87SAurelien Jarno 
1701e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
1702e8996ee0Sbellard    all globals are stored at their canonical location. */
1703e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
1704e5097dc8Sbellard {
1705e5097dc8Sbellard     TCGTemp *ts;
1706e5097dc8Sbellard     int i;
1707e5097dc8Sbellard 
1708c896fe29Sbellard     for(i = s->nb_globals; i < s->nb_temps; i++) {
1709c896fe29Sbellard         ts = &s->temps[i];
1710641d5fbeSbellard         if (ts->temp_local) {
1711641d5fbeSbellard             temp_save(s, i, allocated_regs);
1712641d5fbeSbellard         } else {
17132c0366f0SAurelien Jarno #ifdef USE_LIVENESS_ANALYSIS
17142c0366f0SAurelien Jarno             /* The liveness analysis already ensures that temps are dead.
17152c0366f0SAurelien Jarno                Keep an assert for safety. */
17162c0366f0SAurelien Jarno             assert(ts->val_type == TEMP_VAL_DEAD);
17172c0366f0SAurelien Jarno #else
1718639368ddSAurelien Jarno             temp_dead(s, i);
17192c0366f0SAurelien Jarno #endif
1720c896fe29Sbellard         }
1721641d5fbeSbellard     }
1722e8996ee0Sbellard 
1723e8996ee0Sbellard     save_globals(s, allocated_regs);
1724c896fe29Sbellard }
1725c896fe29Sbellard 
1726866cb6cbSAurelien Jarno #define IS_DEAD_ARG(n) ((dead_args >> (n)) & 1)
1727ec7a869dSAurelien Jarno #define NEED_SYNC_ARG(n) ((sync_args >> (n)) & 1)
1728c896fe29Sbellard 
1729ec7a869dSAurelien Jarno static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args,
1730ec7a869dSAurelien Jarno                                uint16_t dead_args, uint8_t sync_args)
1731e8996ee0Sbellard {
1732e8996ee0Sbellard     TCGTemp *ots;
1733e8996ee0Sbellard     tcg_target_ulong val;
1734e8996ee0Sbellard 
1735e8996ee0Sbellard     ots = &s->temps[args[0]];
1736e8996ee0Sbellard     val = args[1];
1737e8996ee0Sbellard 
1738e8996ee0Sbellard     if (ots->fixed_reg) {
1739e8996ee0Sbellard         /* for fixed registers, we do not do any constant
1740e8996ee0Sbellard            propagation */
1741e8996ee0Sbellard         tcg_out_movi(s, ots->type, ots->reg, val);
1742e8996ee0Sbellard     } else {
17431235fc06Sths         /* The movi is not explicitly generated here */
1744e8996ee0Sbellard         if (ots->val_type == TEMP_VAL_REG)
1745e8996ee0Sbellard             s->reg_to_temp[ots->reg] = -1;
1746e8996ee0Sbellard         ots->val_type = TEMP_VAL_CONST;
1747e8996ee0Sbellard         ots->val = val;
1748e8996ee0Sbellard     }
1749ec7a869dSAurelien Jarno     if (NEED_SYNC_ARG(0)) {
1750ec7a869dSAurelien Jarno         temp_sync(s, args[0], s->reserved_regs);
1751ec7a869dSAurelien Jarno     }
17524c4e1ab2SAurelien Jarno     if (IS_DEAD_ARG(0)) {
17534c4e1ab2SAurelien Jarno         temp_dead(s, args[0]);
17544c4e1ab2SAurelien Jarno     }
1755e8996ee0Sbellard }
1756e8996ee0Sbellard 
1757c896fe29Sbellard static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
1758ec7a869dSAurelien Jarno                               const TCGArg *args, uint16_t dead_args,
1759ec7a869dSAurelien Jarno                               uint8_t sync_args)
1760c896fe29Sbellard {
1761c29c1d7eSAurelien Jarno     TCGRegSet allocated_regs;
1762c896fe29Sbellard     TCGTemp *ts, *ots;
1763c29c1d7eSAurelien Jarno     const TCGArgConstraint *arg_ct, *oarg_ct;
1764c896fe29Sbellard 
1765c29c1d7eSAurelien Jarno     tcg_regset_set(allocated_regs, s->reserved_regs);
1766c896fe29Sbellard     ots = &s->temps[args[0]];
1767c896fe29Sbellard     ts = &s->temps[args[1]];
1768c29c1d7eSAurelien Jarno     oarg_ct = &def->args_ct[0];
1769c29c1d7eSAurelien Jarno     arg_ct = &def->args_ct[1];
1770c896fe29Sbellard 
1771c29c1d7eSAurelien Jarno     /* If the source value is not in a register, and we're going to be
1772c29c1d7eSAurelien Jarno        forced to have it in a register in order to perform the copy,
1773c29c1d7eSAurelien Jarno        then copy the SOURCE value into its own register first.  That way
1774c29c1d7eSAurelien Jarno        we don't have to reload SOURCE the next time it is used. */
1775c29c1d7eSAurelien Jarno     if (((NEED_SYNC_ARG(0) || ots->fixed_reg) && ts->val_type != TEMP_VAL_REG)
1776c29c1d7eSAurelien Jarno         || ts->val_type == TEMP_VAL_MEM) {
1777c29c1d7eSAurelien Jarno         ts->reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1778c29c1d7eSAurelien Jarno         if (ts->val_type == TEMP_VAL_MEM) {
1779c29c1d7eSAurelien Jarno             tcg_out_ld(s, ts->type, ts->reg, ts->mem_reg, ts->mem_offset);
1780c29c1d7eSAurelien Jarno             ts->mem_coherent = 1;
1781c896fe29Sbellard         } else if (ts->val_type == TEMP_VAL_CONST) {
1782c29c1d7eSAurelien Jarno             tcg_out_movi(s, ts->type, ts->reg, ts->val);
1783c29c1d7eSAurelien Jarno         }
1784c29c1d7eSAurelien Jarno         s->reg_to_temp[ts->reg] = args[1];
1785c29c1d7eSAurelien Jarno         ts->val_type = TEMP_VAL_REG;
1786c29c1d7eSAurelien Jarno     }
1787c29c1d7eSAurelien Jarno 
1788c29c1d7eSAurelien Jarno     if (IS_DEAD_ARG(0) && !ots->fixed_reg) {
1789c29c1d7eSAurelien Jarno         /* mov to a non-saved dead register makes no sense (even with
1790c29c1d7eSAurelien Jarno            liveness analysis disabled). */
1791c29c1d7eSAurelien Jarno         assert(NEED_SYNC_ARG(0));
1792c29c1d7eSAurelien Jarno         /* The code above should have moved the temp to a register. */
1793c29c1d7eSAurelien Jarno         assert(ts->val_type == TEMP_VAL_REG);
1794c29c1d7eSAurelien Jarno         if (!ots->mem_allocated) {
1795c29c1d7eSAurelien Jarno             temp_allocate_frame(s, args[0]);
1796c29c1d7eSAurelien Jarno         }
1797c29c1d7eSAurelien Jarno         tcg_out_st(s, ots->type, ts->reg, ots->mem_reg, ots->mem_offset);
1798c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1)) {
1799c29c1d7eSAurelien Jarno             temp_dead(s, args[1]);
1800c29c1d7eSAurelien Jarno         }
1801c29c1d7eSAurelien Jarno         temp_dead(s, args[0]);
1802c29c1d7eSAurelien Jarno     } else if (ts->val_type == TEMP_VAL_CONST) {
1803e8996ee0Sbellard         /* propagate constant */
1804c29c1d7eSAurelien Jarno         if (ots->val_type == TEMP_VAL_REG) {
1805e8996ee0Sbellard             s->reg_to_temp[ots->reg] = -1;
1806c29c1d7eSAurelien Jarno         }
1807e8996ee0Sbellard         ots->val_type = TEMP_VAL_CONST;
1808e8996ee0Sbellard         ots->val = ts->val;
1809e8996ee0Sbellard     } else {
1810c29c1d7eSAurelien Jarno         /* The code in the first if block should have moved the
1811c29c1d7eSAurelien Jarno            temp to a register. */
1812c29c1d7eSAurelien Jarno         assert(ts->val_type == TEMP_VAL_REG);
1813c29c1d7eSAurelien Jarno         if (IS_DEAD_ARG(1) && !ts->fixed_reg && !ots->fixed_reg) {
1814c29c1d7eSAurelien Jarno             /* the mov can be suppressed */
1815c29c1d7eSAurelien Jarno             if (ots->val_type == TEMP_VAL_REG) {
1816c29c1d7eSAurelien Jarno                 s->reg_to_temp[ots->reg] = -1;
1817c896fe29Sbellard             }
1818c29c1d7eSAurelien Jarno             ots->reg = ts->reg;
1819c29c1d7eSAurelien Jarno             temp_dead(s, args[1]);
1820c29c1d7eSAurelien Jarno         } else {
1821c29c1d7eSAurelien Jarno             if (ots->val_type != TEMP_VAL_REG) {
1822c29c1d7eSAurelien Jarno                 /* When allocating a new register, make sure to not spill the
1823c29c1d7eSAurelien Jarno                    input one. */
1824c29c1d7eSAurelien Jarno                 tcg_regset_set_reg(allocated_regs, ts->reg);
1825c29c1d7eSAurelien Jarno                 ots->reg = tcg_reg_alloc(s, oarg_ct->u.regs, allocated_regs);
1826c29c1d7eSAurelien Jarno             }
1827c29c1d7eSAurelien Jarno             tcg_out_mov(s, ots->type, ots->reg, ts->reg);
1828c29c1d7eSAurelien Jarno         }
1829c896fe29Sbellard         ots->val_type = TEMP_VAL_REG;
1830c896fe29Sbellard         ots->mem_coherent = 0;
1831c29c1d7eSAurelien Jarno         s->reg_to_temp[ots->reg] = args[0];
1832ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(0)) {
1833c29c1d7eSAurelien Jarno             tcg_reg_sync(s, ots->reg);
1834c29c1d7eSAurelien Jarno         }
1835ec7a869dSAurelien Jarno     }
1836c896fe29Sbellard }
1837c896fe29Sbellard 
1838c896fe29Sbellard static void tcg_reg_alloc_op(TCGContext *s,
1839a9751609SRichard Henderson                              const TCGOpDef *def, TCGOpcode opc,
1840ec7a869dSAurelien Jarno                              const TCGArg *args, uint16_t dead_args,
1841ec7a869dSAurelien Jarno                              uint8_t sync_args)
1842c896fe29Sbellard {
1843c896fe29Sbellard     TCGRegSet allocated_regs;
1844c896fe29Sbellard     int i, k, nb_iargs, nb_oargs, reg;
1845c896fe29Sbellard     TCGArg arg;
1846c896fe29Sbellard     const TCGArgConstraint *arg_ct;
1847c896fe29Sbellard     TCGTemp *ts;
1848c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
1849c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
1850c896fe29Sbellard 
1851c896fe29Sbellard     nb_oargs = def->nb_oargs;
1852c896fe29Sbellard     nb_iargs = def->nb_iargs;
1853c896fe29Sbellard 
1854c896fe29Sbellard     /* copy constants */
1855c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
1856c896fe29Sbellard            args + nb_oargs + nb_iargs,
1857c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
1858c896fe29Sbellard 
1859c896fe29Sbellard     /* satisfy input constraints */
1860c896fe29Sbellard     tcg_regset_set(allocated_regs, s->reserved_regs);
1861c896fe29Sbellard     for(k = 0; k < nb_iargs; k++) {
1862c896fe29Sbellard         i = def->sorted_args[nb_oargs + k];
1863c896fe29Sbellard         arg = args[i];
1864c896fe29Sbellard         arg_ct = &def->args_ct[i];
1865c896fe29Sbellard         ts = &s->temps[arg];
1866c896fe29Sbellard         if (ts->val_type == TEMP_VAL_MEM) {
1867c896fe29Sbellard             reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1868e4d5434cSblueswir1             tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1869c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
1870c896fe29Sbellard             ts->reg = reg;
1871c896fe29Sbellard             ts->mem_coherent = 1;
1872c896fe29Sbellard             s->reg_to_temp[reg] = arg;
1873c896fe29Sbellard         } else if (ts->val_type == TEMP_VAL_CONST) {
1874c896fe29Sbellard             if (tcg_target_const_match(ts->val, arg_ct)) {
1875c896fe29Sbellard                 /* constant is OK for instruction */
1876c896fe29Sbellard                 const_args[i] = 1;
1877c896fe29Sbellard                 new_args[i] = ts->val;
1878c896fe29Sbellard                 goto iarg_end;
1879c896fe29Sbellard             } else {
1880c896fe29Sbellard                 /* need to move to a register */
1881c896fe29Sbellard                 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1882c896fe29Sbellard                 tcg_out_movi(s, ts->type, reg, ts->val);
1883e8996ee0Sbellard                 ts->val_type = TEMP_VAL_REG;
1884e8996ee0Sbellard                 ts->reg = reg;
1885e8996ee0Sbellard                 ts->mem_coherent = 0;
1886e8996ee0Sbellard                 s->reg_to_temp[reg] = arg;
1887c896fe29Sbellard             }
1888c896fe29Sbellard         }
1889c896fe29Sbellard         assert(ts->val_type == TEMP_VAL_REG);
18905ff9d6a4Sbellard         if (arg_ct->ct & TCG_CT_IALIAS) {
18915ff9d6a4Sbellard             if (ts->fixed_reg) {
18925ff9d6a4Sbellard                 /* if fixed register, we must allocate a new register
18935ff9d6a4Sbellard                    if the alias is not the same register */
18945ff9d6a4Sbellard                 if (arg != args[arg_ct->alias_index])
18955ff9d6a4Sbellard                     goto allocate_in_reg;
18965ff9d6a4Sbellard             } else {
1897c896fe29Sbellard                 /* if the input is aliased to an output and if it is
1898c896fe29Sbellard                    not dead after the instruction, we must allocate
1899c896fe29Sbellard                    a new register and move it */
1900866cb6cbSAurelien Jarno                 if (!IS_DEAD_ARG(i)) {
1901c896fe29Sbellard                     goto allocate_in_reg;
1902c896fe29Sbellard                 }
19035ff9d6a4Sbellard             }
1904866cb6cbSAurelien Jarno         }
1905c896fe29Sbellard         reg = ts->reg;
1906c896fe29Sbellard         if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1907c896fe29Sbellard             /* nothing to do : the constraint is satisfied */
1908c896fe29Sbellard         } else {
1909c896fe29Sbellard         allocate_in_reg:
1910c896fe29Sbellard             /* allocate a new register matching the constraint
1911c896fe29Sbellard                and move the temporary register into it */
1912c896fe29Sbellard             reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
19133b6dac34SRichard Henderson             tcg_out_mov(s, ts->type, reg, ts->reg);
1914c896fe29Sbellard         }
1915c896fe29Sbellard         new_args[i] = reg;
1916c896fe29Sbellard         const_args[i] = 0;
1917c896fe29Sbellard         tcg_regset_set_reg(allocated_regs, reg);
1918c896fe29Sbellard     iarg_end: ;
1919c896fe29Sbellard     }
1920c896fe29Sbellard 
1921c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
1922866cb6cbSAurelien Jarno     for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
1923866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
1924639368ddSAurelien Jarno             temp_dead(s, args[i]);
1925c896fe29Sbellard         }
1926c896fe29Sbellard     }
1927c896fe29Sbellard 
1928a52ad07eSAurelien Jarno     if (def->flags & TCG_OPF_BB_END) {
1929a52ad07eSAurelien Jarno         tcg_reg_alloc_bb_end(s, allocated_regs);
1930a52ad07eSAurelien Jarno     } else {
1931c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
1932b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
1933c896fe29Sbellard             for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1934c896fe29Sbellard                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
1935c896fe29Sbellard                     tcg_reg_free(s, reg);
1936c896fe29Sbellard                 }
1937c896fe29Sbellard             }
19383d5c5f87SAurelien Jarno         }
19393d5c5f87SAurelien Jarno         if (def->flags & TCG_OPF_SIDE_EFFECTS) {
19403d5c5f87SAurelien Jarno             /* sync globals if the op has side effects and might trigger
19413d5c5f87SAurelien Jarno                an exception. */
19423d5c5f87SAurelien Jarno             sync_globals(s, allocated_regs);
1943c896fe29Sbellard         }
1944c896fe29Sbellard 
1945c896fe29Sbellard         /* satisfy the output constraints */
1946c896fe29Sbellard         tcg_regset_set(allocated_regs, s->reserved_regs);
1947c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
1948c896fe29Sbellard             i = def->sorted_args[k];
1949c896fe29Sbellard             arg = args[i];
1950c896fe29Sbellard             arg_ct = &def->args_ct[i];
1951c896fe29Sbellard             ts = &s->temps[arg];
1952c896fe29Sbellard             if (arg_ct->ct & TCG_CT_ALIAS) {
19535ff9d6a4Sbellard                 reg = new_args[arg_ct->alias_index];
1954c896fe29Sbellard             } else {
1955c896fe29Sbellard                 /* if fixed register, we try to use it */
1956c896fe29Sbellard                 reg = ts->reg;
1957c896fe29Sbellard                 if (ts->fixed_reg &&
1958c896fe29Sbellard                     tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1959c896fe29Sbellard                     goto oarg_end;
1960c896fe29Sbellard                 }
1961c896fe29Sbellard                 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1962c896fe29Sbellard             }
1963c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
1964c896fe29Sbellard             /* if a fixed register is used, then a move will be done afterwards */
1965c896fe29Sbellard             if (!ts->fixed_reg) {
1966639368ddSAurelien Jarno                 if (ts->val_type == TEMP_VAL_REG) {
1967639368ddSAurelien Jarno                     s->reg_to_temp[ts->reg] = -1;
1968639368ddSAurelien Jarno                 }
1969c896fe29Sbellard                 ts->val_type = TEMP_VAL_REG;
1970c896fe29Sbellard                 ts->reg = reg;
1971c896fe29Sbellard                 /* temp value is modified, so the value kept in memory is
1972c896fe29Sbellard                    potentially not the same */
1973c896fe29Sbellard                 ts->mem_coherent = 0;
1974c896fe29Sbellard                 s->reg_to_temp[reg] = arg;
1975c896fe29Sbellard             }
1976c896fe29Sbellard         oarg_end:
1977c896fe29Sbellard             new_args[i] = reg;
1978c896fe29Sbellard         }
1979e8996ee0Sbellard     }
1980c896fe29Sbellard 
1981c896fe29Sbellard     /* emit instruction */
1982c896fe29Sbellard     tcg_out_op(s, opc, new_args, const_args);
1983c896fe29Sbellard 
1984c896fe29Sbellard     /* move the outputs in the correct register if needed */
1985c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
1986c896fe29Sbellard         ts = &s->temps[args[i]];
1987c896fe29Sbellard         reg = new_args[i];
1988c896fe29Sbellard         if (ts->fixed_reg && ts->reg != reg) {
19893b6dac34SRichard Henderson             tcg_out_mov(s, ts->type, ts->reg, reg);
1990c896fe29Sbellard         }
1991ec7a869dSAurelien Jarno         if (NEED_SYNC_ARG(i)) {
1992ec7a869dSAurelien Jarno             tcg_reg_sync(s, reg);
1993ec7a869dSAurelien Jarno         }
1994ec7a869dSAurelien Jarno         if (IS_DEAD_ARG(i)) {
1995ec7a869dSAurelien Jarno             temp_dead(s, args[i]);
1996ec7a869dSAurelien Jarno         }
1997c896fe29Sbellard     }
1998c896fe29Sbellard }
1999c896fe29Sbellard 
2000b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP
2001b03cce8eSbellard #define STACK_DIR(x) (-(x))
2002b03cce8eSbellard #else
2003b03cce8eSbellard #define STACK_DIR(x) (x)
2004b03cce8eSbellard #endif
2005b03cce8eSbellard 
2006c896fe29Sbellard static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
2007a9751609SRichard Henderson                               TCGOpcode opc, const TCGArg *args,
2008ec7a869dSAurelien Jarno                               uint16_t dead_args, uint8_t sync_args)
2009c896fe29Sbellard {
2010c896fe29Sbellard     int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params;
2011c896fe29Sbellard     TCGArg arg, func_arg;
2012c896fe29Sbellard     TCGTemp *ts;
2013f54b3f92Saurel32     tcg_target_long stack_offset, call_stack_size, func_addr;
2014b03cce8eSbellard     int const_func_arg, allocate_args;
2015c896fe29Sbellard     TCGRegSet allocated_regs;
2016c896fe29Sbellard     const TCGArgConstraint *arg_ct;
2017c896fe29Sbellard 
2018c896fe29Sbellard     arg = *args++;
2019c896fe29Sbellard 
2020c896fe29Sbellard     nb_oargs = arg >> 16;
2021c896fe29Sbellard     nb_iargs = arg & 0xffff;
2022c896fe29Sbellard     nb_params = nb_iargs - 1;
2023c896fe29Sbellard 
2024c896fe29Sbellard     flags = args[nb_oargs + nb_iargs];
2025c896fe29Sbellard 
20266e17d0c5SStefan Weil     nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
2027c896fe29Sbellard     if (nb_regs > nb_params)
2028c896fe29Sbellard         nb_regs = nb_params;
2029c896fe29Sbellard 
2030c896fe29Sbellard     /* assign stack slots first */
2031c896fe29Sbellard     call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);
2032c896fe29Sbellard     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
2033c896fe29Sbellard         ~(TCG_TARGET_STACK_ALIGN - 1);
2034b03cce8eSbellard     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
2035b03cce8eSbellard     if (allocate_args) {
2036345649c0SBlue Swirl         /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed,
2037345649c0SBlue Swirl            preallocate call stack */
2038345649c0SBlue Swirl         tcg_abort();
2039b03cce8eSbellard     }
204039cf05d3Sbellard 
204139cf05d3Sbellard     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
2042c896fe29Sbellard     for(i = nb_regs; i < nb_params; i++) {
2043c896fe29Sbellard         arg = args[nb_oargs + i];
204439cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP
204539cf05d3Sbellard         stack_offset -= sizeof(tcg_target_long);
204639cf05d3Sbellard #endif
204739cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
2048c896fe29Sbellard             ts = &s->temps[arg];
2049c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
2050e4d5434cSblueswir1                 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
2051c896fe29Sbellard             } else if (ts->val_type == TEMP_VAL_MEM) {
2052c896fe29Sbellard                 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
2053c896fe29Sbellard                                     s->reserved_regs);
2054c896fe29Sbellard                 /* XXX: not correct if reading values from the stack */
2055e4d5434cSblueswir1                 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
2056e4d5434cSblueswir1                 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
2057c896fe29Sbellard             } else if (ts->val_type == TEMP_VAL_CONST) {
2058c896fe29Sbellard                 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
2059c896fe29Sbellard                                     s->reserved_regs);
2060c896fe29Sbellard                 /* XXX: sign extend may be needed on some targets */
2061c896fe29Sbellard                 tcg_out_movi(s, ts->type, reg, ts->val);
2062e4d5434cSblueswir1                 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
2063c896fe29Sbellard             } else {
2064c896fe29Sbellard                 tcg_abort();
2065c896fe29Sbellard             }
206639cf05d3Sbellard         }
206739cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP
206839cf05d3Sbellard         stack_offset += sizeof(tcg_target_long);
206939cf05d3Sbellard #endif
2070c896fe29Sbellard     }
2071c896fe29Sbellard 
2072c896fe29Sbellard     /* assign input registers */
2073c896fe29Sbellard     tcg_regset_set(allocated_regs, s->reserved_regs);
2074c896fe29Sbellard     for(i = 0; i < nb_regs; i++) {
2075c896fe29Sbellard         arg = args[nb_oargs + i];
207639cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
2077c896fe29Sbellard             ts = &s->temps[arg];
2078c896fe29Sbellard             reg = tcg_target_call_iarg_regs[i];
2079c896fe29Sbellard             tcg_reg_free(s, reg);
2080c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
2081c896fe29Sbellard                 if (ts->reg != reg) {
20823b6dac34SRichard Henderson                     tcg_out_mov(s, ts->type, reg, ts->reg);
2083c896fe29Sbellard                 }
2084c896fe29Sbellard             } else if (ts->val_type == TEMP_VAL_MEM) {
2085e4d5434cSblueswir1                 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
2086c896fe29Sbellard             } else if (ts->val_type == TEMP_VAL_CONST) {
2087c896fe29Sbellard                 /* XXX: sign extend ? */
2088c896fe29Sbellard                 tcg_out_movi(s, ts->type, reg, ts->val);
2089c896fe29Sbellard             } else {
2090c896fe29Sbellard                 tcg_abort();
2091c896fe29Sbellard             }
2092c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
2093c896fe29Sbellard         }
209439cf05d3Sbellard     }
2095c896fe29Sbellard 
2096c896fe29Sbellard     /* assign function address */
2097c896fe29Sbellard     func_arg = args[nb_oargs + nb_iargs - 1];
2098c896fe29Sbellard     arg_ct = &def->args_ct[0];
2099c896fe29Sbellard     ts = &s->temps[func_arg];
2100f54b3f92Saurel32     func_addr = ts->val;
2101c896fe29Sbellard     const_func_arg = 0;
2102c896fe29Sbellard     if (ts->val_type == TEMP_VAL_MEM) {
2103c896fe29Sbellard         reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
2104e4d5434cSblueswir1         tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
2105c896fe29Sbellard         func_arg = reg;
2106e8996ee0Sbellard         tcg_regset_set_reg(allocated_regs, reg);
2107c896fe29Sbellard     } else if (ts->val_type == TEMP_VAL_REG) {
2108c896fe29Sbellard         reg = ts->reg;
2109c896fe29Sbellard         if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) {
2110c896fe29Sbellard             reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
21113b6dac34SRichard Henderson             tcg_out_mov(s, ts->type, reg, ts->reg);
2112c896fe29Sbellard         }
2113c896fe29Sbellard         func_arg = reg;
2114e8996ee0Sbellard         tcg_regset_set_reg(allocated_regs, reg);
2115c896fe29Sbellard     } else if (ts->val_type == TEMP_VAL_CONST) {
2116f54b3f92Saurel32         if (tcg_target_const_match(func_addr, arg_ct)) {
2117c896fe29Sbellard             const_func_arg = 1;
2118f54b3f92Saurel32             func_arg = func_addr;
2119c896fe29Sbellard         } else {
2120c896fe29Sbellard             reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
2121f54b3f92Saurel32             tcg_out_movi(s, ts->type, reg, func_addr);
2122c896fe29Sbellard             func_arg = reg;
2123e8996ee0Sbellard             tcg_regset_set_reg(allocated_regs, reg);
2124c896fe29Sbellard         }
2125c896fe29Sbellard     } else {
2126c896fe29Sbellard         tcg_abort();
2127c896fe29Sbellard     }
2128c896fe29Sbellard 
2129e8996ee0Sbellard 
2130c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
2131866cb6cbSAurelien Jarno     for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
2132866cb6cbSAurelien Jarno         if (IS_DEAD_ARG(i)) {
2133639368ddSAurelien Jarno             temp_dead(s, args[i]);
2134c896fe29Sbellard         }
2135c896fe29Sbellard     }
2136c896fe29Sbellard 
2137c896fe29Sbellard     /* clobber call registers */
2138c896fe29Sbellard     for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
2139c896fe29Sbellard         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
2140c896fe29Sbellard             tcg_reg_free(s, reg);
2141c896fe29Sbellard         }
2142c896fe29Sbellard     }
2143c896fe29Sbellard 
214478505279SAurelien Jarno     /* Save globals if they might be written by the helper, sync them if
214578505279SAurelien Jarno        they might be read. */
214678505279SAurelien Jarno     if (flags & TCG_CALL_NO_READ_GLOBALS) {
214778505279SAurelien Jarno         /* Nothing to do */
214878505279SAurelien Jarno     } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) {
214978505279SAurelien Jarno         sync_globals(s, allocated_regs);
215078505279SAurelien Jarno     } else {
2151e8996ee0Sbellard         save_globals(s, allocated_regs);
2152b9c18f56Saurel32     }
2153c896fe29Sbellard 
2154c896fe29Sbellard     tcg_out_op(s, opc, &func_arg, &const_func_arg);
2155c896fe29Sbellard 
2156c896fe29Sbellard     /* assign output registers and emit moves if needed */
2157c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
2158c896fe29Sbellard         arg = args[i];
2159c896fe29Sbellard         ts = &s->temps[arg];
2160c896fe29Sbellard         reg = tcg_target_call_oarg_regs[i];
2161e8996ee0Sbellard         assert(s->reg_to_temp[reg] == -1);
2162c896fe29Sbellard         if (ts->fixed_reg) {
2163c896fe29Sbellard             if (ts->reg != reg) {
21643b6dac34SRichard Henderson                 tcg_out_mov(s, ts->type, ts->reg, reg);
2165c896fe29Sbellard             }
2166c896fe29Sbellard         } else {
2167639368ddSAurelien Jarno             if (ts->val_type == TEMP_VAL_REG) {
2168639368ddSAurelien Jarno                 s->reg_to_temp[ts->reg] = -1;
2169639368ddSAurelien Jarno             }
2170c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
2171c896fe29Sbellard             ts->reg = reg;
2172c896fe29Sbellard             ts->mem_coherent = 0;
2173c896fe29Sbellard             s->reg_to_temp[reg] = arg;
2174ec7a869dSAurelien Jarno             if (NEED_SYNC_ARG(i)) {
2175ec7a869dSAurelien Jarno                 tcg_reg_sync(s, reg);
2176ec7a869dSAurelien Jarno             }
2177ec7a869dSAurelien Jarno             if (IS_DEAD_ARG(i)) {
2178ec7a869dSAurelien Jarno                 temp_dead(s, args[i]);
2179c896fe29Sbellard             }
2180c896fe29Sbellard         }
21818c11ad25SAurelien Jarno     }
2182c896fe29Sbellard 
2183c896fe29Sbellard     return nb_iargs + nb_oargs + def->nb_cargs + 1;
2184c896fe29Sbellard }
2185c896fe29Sbellard 
2186c896fe29Sbellard #ifdef CONFIG_PROFILER
2187c896fe29Sbellard 
218854604f74Saurel32 static int64_t tcg_table_op_count[NB_OPS];
2189c896fe29Sbellard 
2190871e6c35SBlue Swirl static void dump_op_count(void)
2191c896fe29Sbellard {
2192c896fe29Sbellard     int i;
2193c896fe29Sbellard     FILE *f;
219454604f74Saurel32     f = fopen("/tmp/op.log", "w");
2195c896fe29Sbellard     for(i = INDEX_op_end; i < NB_OPS; i++) {
219654604f74Saurel32         fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, tcg_table_op_count[i]);
2197c896fe29Sbellard     }
2198c896fe29Sbellard     fclose(f);
2199c896fe29Sbellard }
2200c896fe29Sbellard #endif
2201c896fe29Sbellard 
2202c896fe29Sbellard 
2203c896fe29Sbellard static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
22042ba1eeb6Spbrook                                       long search_pc)
2205c896fe29Sbellard {
2206a9751609SRichard Henderson     TCGOpcode opc;
2207a9751609SRichard Henderson     int op_index;
2208c896fe29Sbellard     const TCGOpDef *def;
2209c896fe29Sbellard     const TCGArg *args;
2210c896fe29Sbellard 
2211c896fe29Sbellard #ifdef DEBUG_DISAS
22128fec2b8cSaliguori     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
221393fcfe39Saliguori         qemu_log("OP:\n");
2214eeacee4dSBlue Swirl         tcg_dump_ops(s);
221593fcfe39Saliguori         qemu_log("\n");
2216c896fe29Sbellard     }
2217c896fe29Sbellard #endif
2218c896fe29Sbellard 
2219c5cc28ffSAurelien Jarno #ifdef CONFIG_PROFILER
2220c5cc28ffSAurelien Jarno     s->opt_time -= profile_getclock();
2221c5cc28ffSAurelien Jarno #endif
2222c5cc28ffSAurelien Jarno 
22238f2e8c07SKirill Batuzov #ifdef USE_TCG_OPTIMIZATIONS
2224c4afe5c4SEvgeny Voevodin     s->gen_opparam_ptr =
2225efd7f486SEvgeny Voevodin         tcg_optimize(s, s->gen_opc_ptr, gen_opparam_buf, tcg_op_defs);
22268f2e8c07SKirill Batuzov #endif
22278f2e8c07SKirill Batuzov 
2228a23a9ec6Sbellard #ifdef CONFIG_PROFILER
2229c5cc28ffSAurelien Jarno     s->opt_time += profile_getclock();
2230a23a9ec6Sbellard     s->la_time -= profile_getclock();
2231a23a9ec6Sbellard #endif
2232c5cc28ffSAurelien Jarno 
2233c896fe29Sbellard     tcg_liveness_analysis(s);
2234c5cc28ffSAurelien Jarno 
2235a23a9ec6Sbellard #ifdef CONFIG_PROFILER
2236a23a9ec6Sbellard     s->la_time += profile_getclock();
2237a23a9ec6Sbellard #endif
2238c896fe29Sbellard 
2239c896fe29Sbellard #ifdef DEBUG_DISAS
22408fec2b8cSaliguori     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) {
2241c5cc28ffSAurelien Jarno         qemu_log("OP after optimization and liveness analysis:\n");
2242eeacee4dSBlue Swirl         tcg_dump_ops(s);
224393fcfe39Saliguori         qemu_log("\n");
2244c896fe29Sbellard     }
2245c896fe29Sbellard #endif
2246c896fe29Sbellard 
2247c896fe29Sbellard     tcg_reg_alloc_start(s);
2248c896fe29Sbellard 
2249c896fe29Sbellard     s->code_buf = gen_code_buf;
2250c896fe29Sbellard     s->code_ptr = gen_code_buf;
2251c896fe29Sbellard 
2252c896fe29Sbellard     args = gen_opparam_buf;
2253c896fe29Sbellard     op_index = 0;
2254b3db8758Sblueswir1 
2255c896fe29Sbellard     for(;;) {
2256*92414b31SEvgeny Voevodin         opc = s->gen_opc_buf[op_index];
2257c896fe29Sbellard #ifdef CONFIG_PROFILER
225854604f74Saurel32         tcg_table_op_count[opc]++;
2259c896fe29Sbellard #endif
2260c896fe29Sbellard         def = &tcg_op_defs[opc];
2261c896fe29Sbellard #if 0
2262c896fe29Sbellard         printf("%s: %d %d %d\n", def->name,
2263c896fe29Sbellard                def->nb_oargs, def->nb_iargs, def->nb_cargs);
2264c896fe29Sbellard         //        dump_regs(s);
2265c896fe29Sbellard #endif
2266c896fe29Sbellard         switch(opc) {
2267c896fe29Sbellard         case INDEX_op_mov_i32:
2268c896fe29Sbellard         case INDEX_op_mov_i64:
2269ec7a869dSAurelien Jarno             tcg_reg_alloc_mov(s, def, args, s->op_dead_args[op_index],
2270ec7a869dSAurelien Jarno                               s->op_sync_args[op_index]);
2271c896fe29Sbellard             break;
2272e8996ee0Sbellard         case INDEX_op_movi_i32:
2273e8996ee0Sbellard         case INDEX_op_movi_i64:
2274ec7a869dSAurelien Jarno             tcg_reg_alloc_movi(s, args, s->op_dead_args[op_index],
2275ec7a869dSAurelien Jarno                                s->op_sync_args[op_index]);
2276e8996ee0Sbellard             break;
22777e4597d7Sbellard         case INDEX_op_debug_insn_start:
22787e4597d7Sbellard             /* debug instruction */
22797e4597d7Sbellard             break;
2280c896fe29Sbellard         case INDEX_op_nop:
2281c896fe29Sbellard         case INDEX_op_nop1:
2282c896fe29Sbellard         case INDEX_op_nop2:
2283c896fe29Sbellard         case INDEX_op_nop3:
2284c896fe29Sbellard             break;
2285c896fe29Sbellard         case INDEX_op_nopn:
2286c896fe29Sbellard             args += args[0];
2287c896fe29Sbellard             goto next;
22885ff9d6a4Sbellard         case INDEX_op_discard:
2289639368ddSAurelien Jarno             temp_dead(s, args[0]);
22905ff9d6a4Sbellard             break;
2291c896fe29Sbellard         case INDEX_op_set_label:
2292e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
22939d6fca70SStefan Weil             tcg_out_label(s, args[0], s->code_ptr);
2294c896fe29Sbellard             break;
2295c896fe29Sbellard         case INDEX_op_call:
2296ec7a869dSAurelien Jarno             args += tcg_reg_alloc_call(s, def, opc, args,
2297ec7a869dSAurelien Jarno                                        s->op_dead_args[op_index],
2298ec7a869dSAurelien Jarno                                        s->op_sync_args[op_index]);
2299c896fe29Sbellard             goto next;
2300c896fe29Sbellard         case INDEX_op_end:
2301c896fe29Sbellard             goto the_end;
2302c896fe29Sbellard         default:
230325c4d9ccSRichard Henderson             /* Sanity check that we've not introduced any unhandled opcodes. */
230425c4d9ccSRichard Henderson             if (def->flags & TCG_OPF_NOT_PRESENT) {
230525c4d9ccSRichard Henderson                 tcg_abort();
230625c4d9ccSRichard Henderson             }
2307c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
2308c896fe29Sbellard                faster to have specialized register allocator functions for
2309c896fe29Sbellard                some common argument patterns */
2310ec7a869dSAurelien Jarno             tcg_reg_alloc_op(s, def, opc, args, s->op_dead_args[op_index],
2311ec7a869dSAurelien Jarno                              s->op_sync_args[op_index]);
2312c896fe29Sbellard             break;
2313c896fe29Sbellard         }
2314c896fe29Sbellard         args += def->nb_args;
23158df1ca4bSths     next:
23162ba1eeb6Spbrook         if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) {
2317c896fe29Sbellard             return op_index;
2318c896fe29Sbellard         }
2319c896fe29Sbellard         op_index++;
2320c896fe29Sbellard #ifndef NDEBUG
2321c896fe29Sbellard         check_regs(s);
2322c896fe29Sbellard #endif
2323c896fe29Sbellard     }
2324c896fe29Sbellard  the_end:
2325b76f0d8cSYeongkyoon Lee #if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU)
2326b76f0d8cSYeongkyoon Lee     /* Generate TB finalization at the end of block */
2327b76f0d8cSYeongkyoon Lee     tcg_out_tb_finalize(s);
2328b76f0d8cSYeongkyoon Lee #endif
2329c896fe29Sbellard     return -1;
2330c896fe29Sbellard }
2331c896fe29Sbellard 
233254604f74Saurel32 int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf)
2333c896fe29Sbellard {
2334c896fe29Sbellard #ifdef CONFIG_PROFILER
2335c896fe29Sbellard     {
2336c896fe29Sbellard         int n;
2337*92414b31SEvgeny Voevodin         n = (s->gen_opc_ptr - s->gen_opc_buf);
2338a23a9ec6Sbellard         s->op_count += n;
2339a23a9ec6Sbellard         if (n > s->op_count_max)
2340a23a9ec6Sbellard             s->op_count_max = n;
2341a23a9ec6Sbellard 
2342a23a9ec6Sbellard         s->temp_count += s->nb_temps;
2343a23a9ec6Sbellard         if (s->nb_temps > s->temp_count_max)
2344a23a9ec6Sbellard             s->temp_count_max = s->nb_temps;
2345c896fe29Sbellard     }
2346c896fe29Sbellard #endif
2347c896fe29Sbellard 
23482ba1eeb6Spbrook     tcg_gen_code_common(s, gen_code_buf, -1);
2349c896fe29Sbellard 
2350c896fe29Sbellard     /* flush instruction cache */
23512aeabc08SStefan Weil     flush_icache_range((tcg_target_ulong)gen_code_buf,
23522aeabc08SStefan Weil                        (tcg_target_ulong)s->code_ptr);
23532aeabc08SStefan Weil 
2354c896fe29Sbellard     return s->code_ptr -  gen_code_buf;
2355c896fe29Sbellard }
2356c896fe29Sbellard 
23572ba1eeb6Spbrook /* Return the index of the micro operation such as the pc after is <
2358623e265cSpbrook    offset bytes from the start of the TB.  The contents of gen_code_buf must
2359623e265cSpbrook    not be changed, though writing the same values is ok.
2360623e265cSpbrook    Return -1 if not found. */
236154604f74Saurel32 int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset)
2362c896fe29Sbellard {
2363623e265cSpbrook     return tcg_gen_code_common(s, gen_code_buf, offset);
2364c896fe29Sbellard }
2365a23a9ec6Sbellard 
2366a23a9ec6Sbellard #ifdef CONFIG_PROFILER
2367405cf9ffSStefan Weil void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
2368a23a9ec6Sbellard {
2369a23a9ec6Sbellard     TCGContext *s = &tcg_ctx;
2370a23a9ec6Sbellard     int64_t tot;
2371a23a9ec6Sbellard 
2372a23a9ec6Sbellard     tot = s->interm_time + s->code_time;
2373a23a9ec6Sbellard     cpu_fprintf(f, "JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
2374a23a9ec6Sbellard                 tot, tot / 2.4e9);
2375a23a9ec6Sbellard     cpu_fprintf(f, "translated TBs      %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n",
2376a23a9ec6Sbellard                 s->tb_count,
2377a23a9ec6Sbellard                 s->tb_count1 - s->tb_count,
2378a23a9ec6Sbellard                 s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0);
2379a23a9ec6Sbellard     cpu_fprintf(f, "avg ops/TB          %0.1f max=%d\n",
2380a23a9ec6Sbellard                 s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max);
2381a23a9ec6Sbellard     cpu_fprintf(f, "deleted ops/TB      %0.2f\n",
2382a23a9ec6Sbellard                 s->tb_count ?
2383a23a9ec6Sbellard                 (double)s->del_op_count / s->tb_count : 0);
2384a23a9ec6Sbellard     cpu_fprintf(f, "avg temps/TB        %0.2f max=%d\n",
2385a23a9ec6Sbellard                 s->tb_count ?
2386a23a9ec6Sbellard                 (double)s->temp_count / s->tb_count : 0,
2387a23a9ec6Sbellard                 s->temp_count_max);
2388a23a9ec6Sbellard 
2389a23a9ec6Sbellard     cpu_fprintf(f, "cycles/op           %0.1f\n",
2390a23a9ec6Sbellard                 s->op_count ? (double)tot / s->op_count : 0);
2391a23a9ec6Sbellard     cpu_fprintf(f, "cycles/in byte      %0.1f\n",
2392a23a9ec6Sbellard                 s->code_in_len ? (double)tot / s->code_in_len : 0);
2393a23a9ec6Sbellard     cpu_fprintf(f, "cycles/out byte     %0.1f\n",
2394a23a9ec6Sbellard                 s->code_out_len ? (double)tot / s->code_out_len : 0);
2395a23a9ec6Sbellard     if (tot == 0)
2396a23a9ec6Sbellard         tot = 1;
2397a23a9ec6Sbellard     cpu_fprintf(f, "  gen_interm time   %0.1f%%\n",
2398a23a9ec6Sbellard                 (double)s->interm_time / tot * 100.0);
2399a23a9ec6Sbellard     cpu_fprintf(f, "  gen_code time     %0.1f%%\n",
2400a23a9ec6Sbellard                 (double)s->code_time / tot * 100.0);
2401c5cc28ffSAurelien Jarno     cpu_fprintf(f, "optim./code time    %0.1f%%\n",
2402c5cc28ffSAurelien Jarno                 (double)s->opt_time / (s->code_time ? s->code_time : 1)
2403c5cc28ffSAurelien Jarno                 * 100.0);
2404a23a9ec6Sbellard     cpu_fprintf(f, "liveness/code time  %0.1f%%\n",
2405a23a9ec6Sbellard                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
2406a23a9ec6Sbellard     cpu_fprintf(f, "cpu_restore count   %" PRId64 "\n",
2407a23a9ec6Sbellard                 s->restore_count);
2408a23a9ec6Sbellard     cpu_fprintf(f, "  avg cycles        %0.1f\n",
2409a23a9ec6Sbellard                 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
2410871e6c35SBlue Swirl 
2411a23a9ec6Sbellard     dump_op_count();
2412a23a9ec6Sbellard }
2413a23a9ec6Sbellard #else
2414405cf9ffSStefan Weil void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
2415a23a9ec6Sbellard {
241624bf7b3aSbellard     cpu_fprintf(f, "[TCG profiler not compiled]\n");
2417a23a9ec6Sbellard }
2418a23a9ec6Sbellard #endif
2419813da627SRichard Henderson 
2420813da627SRichard Henderson #ifdef ELF_HOST_MACHINE
24215872bbf2SRichard Henderson /* In order to use this feature, the backend needs to do three things:
24225872bbf2SRichard Henderson 
24235872bbf2SRichard Henderson    (1) Define ELF_HOST_MACHINE to indicate both what value to
24245872bbf2SRichard Henderson        put into the ELF image and to indicate support for the feature.
24255872bbf2SRichard Henderson 
24265872bbf2SRichard Henderson    (2) Define tcg_register_jit.  This should create a buffer containing
24275872bbf2SRichard Henderson        the contents of a .debug_frame section that describes the post-
24285872bbf2SRichard Henderson        prologue unwind info for the tcg machine.
24295872bbf2SRichard Henderson 
24305872bbf2SRichard Henderson    (3) Call tcg_register_jit_int, with the constructed .debug_frame.
24315872bbf2SRichard Henderson */
2432813da627SRichard Henderson 
2433813da627SRichard Henderson /* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
2434813da627SRichard Henderson typedef enum {
2435813da627SRichard Henderson     JIT_NOACTION = 0,
2436813da627SRichard Henderson     JIT_REGISTER_FN,
2437813da627SRichard Henderson     JIT_UNREGISTER_FN
2438813da627SRichard Henderson } jit_actions_t;
2439813da627SRichard Henderson 
2440813da627SRichard Henderson struct jit_code_entry {
2441813da627SRichard Henderson     struct jit_code_entry *next_entry;
2442813da627SRichard Henderson     struct jit_code_entry *prev_entry;
2443813da627SRichard Henderson     const void *symfile_addr;
2444813da627SRichard Henderson     uint64_t symfile_size;
2445813da627SRichard Henderson };
2446813da627SRichard Henderson 
2447813da627SRichard Henderson struct jit_descriptor {
2448813da627SRichard Henderson     uint32_t version;
2449813da627SRichard Henderson     uint32_t action_flag;
2450813da627SRichard Henderson     struct jit_code_entry *relevant_entry;
2451813da627SRichard Henderson     struct jit_code_entry *first_entry;
2452813da627SRichard Henderson };
2453813da627SRichard Henderson 
2454813da627SRichard Henderson void __jit_debug_register_code(void) __attribute__((noinline));
2455813da627SRichard Henderson void __jit_debug_register_code(void)
2456813da627SRichard Henderson {
2457813da627SRichard Henderson     asm("");
2458813da627SRichard Henderson }
2459813da627SRichard Henderson 
2460813da627SRichard Henderson /* Must statically initialize the version, because GDB may check
2461813da627SRichard Henderson    the version before we can set it.  */
2462813da627SRichard Henderson struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
2463813da627SRichard Henderson 
2464813da627SRichard Henderson /* End GDB interface.  */
2465813da627SRichard Henderson 
2466813da627SRichard Henderson static int find_string(const char *strtab, const char *str)
2467813da627SRichard Henderson {
2468813da627SRichard Henderson     const char *p = strtab + 1;
2469813da627SRichard Henderson 
2470813da627SRichard Henderson     while (1) {
2471813da627SRichard Henderson         if (strcmp(p, str) == 0) {
2472813da627SRichard Henderson             return p - strtab;
2473813da627SRichard Henderson         }
2474813da627SRichard Henderson         p += strlen(p) + 1;
2475813da627SRichard Henderson     }
2476813da627SRichard Henderson }
2477813da627SRichard Henderson 
24785872bbf2SRichard Henderson static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
2479813da627SRichard Henderson                                  void *debug_frame, size_t debug_frame_size)
2480813da627SRichard Henderson {
24815872bbf2SRichard Henderson     struct __attribute__((packed)) DebugInfo {
24825872bbf2SRichard Henderson         uint32_t  len;
24835872bbf2SRichard Henderson         uint16_t  version;
24845872bbf2SRichard Henderson         uint32_t  abbrev;
24855872bbf2SRichard Henderson         uint8_t   ptr_size;
24865872bbf2SRichard Henderson         uint8_t   cu_die;
24875872bbf2SRichard Henderson         uint16_t  cu_lang;
24885872bbf2SRichard Henderson         uintptr_t cu_low_pc;
24895872bbf2SRichard Henderson         uintptr_t cu_high_pc;
24905872bbf2SRichard Henderson         uint8_t   fn_die;
24915872bbf2SRichard Henderson         char      fn_name[16];
24925872bbf2SRichard Henderson         uintptr_t fn_low_pc;
24935872bbf2SRichard Henderson         uintptr_t fn_high_pc;
24945872bbf2SRichard Henderson         uint8_t   cu_eoc;
24955872bbf2SRichard Henderson     };
2496813da627SRichard Henderson 
2497813da627SRichard Henderson     struct ElfImage {
2498813da627SRichard Henderson         ElfW(Ehdr) ehdr;
2499813da627SRichard Henderson         ElfW(Phdr) phdr;
25005872bbf2SRichard Henderson         ElfW(Shdr) shdr[7];
25015872bbf2SRichard Henderson         ElfW(Sym)  sym[2];
25025872bbf2SRichard Henderson         struct DebugInfo di;
25035872bbf2SRichard Henderson         uint8_t    da[24];
25045872bbf2SRichard Henderson         char       str[80];
25055872bbf2SRichard Henderson     };
25065872bbf2SRichard Henderson 
25075872bbf2SRichard Henderson     struct ElfImage *img;
25085872bbf2SRichard Henderson 
25095872bbf2SRichard Henderson     static const struct ElfImage img_template = {
25105872bbf2SRichard Henderson         .ehdr = {
25115872bbf2SRichard Henderson             .e_ident[EI_MAG0] = ELFMAG0,
25125872bbf2SRichard Henderson             .e_ident[EI_MAG1] = ELFMAG1,
25135872bbf2SRichard Henderson             .e_ident[EI_MAG2] = ELFMAG2,
25145872bbf2SRichard Henderson             .e_ident[EI_MAG3] = ELFMAG3,
25155872bbf2SRichard Henderson             .e_ident[EI_CLASS] = ELF_CLASS,
25165872bbf2SRichard Henderson             .e_ident[EI_DATA] = ELF_DATA,
25175872bbf2SRichard Henderson             .e_ident[EI_VERSION] = EV_CURRENT,
25185872bbf2SRichard Henderson             .e_type = ET_EXEC,
25195872bbf2SRichard Henderson             .e_machine = ELF_HOST_MACHINE,
25205872bbf2SRichard Henderson             .e_version = EV_CURRENT,
25215872bbf2SRichard Henderson             .e_phoff = offsetof(struct ElfImage, phdr),
25225872bbf2SRichard Henderson             .e_shoff = offsetof(struct ElfImage, shdr),
25235872bbf2SRichard Henderson             .e_ehsize = sizeof(ElfW(Shdr)),
25245872bbf2SRichard Henderson             .e_phentsize = sizeof(ElfW(Phdr)),
25255872bbf2SRichard Henderson             .e_phnum = 1,
25265872bbf2SRichard Henderson             .e_shentsize = sizeof(ElfW(Shdr)),
25275872bbf2SRichard Henderson             .e_shnum = ARRAY_SIZE(img->shdr),
25285872bbf2SRichard Henderson             .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
2529abbb3eaeSRichard Henderson #ifdef ELF_HOST_FLAGS
2530abbb3eaeSRichard Henderson             .e_flags = ELF_HOST_FLAGS,
2531abbb3eaeSRichard Henderson #endif
2532abbb3eaeSRichard Henderson #ifdef ELF_OSABI
2533abbb3eaeSRichard Henderson             .e_ident[EI_OSABI] = ELF_OSABI,
2534abbb3eaeSRichard Henderson #endif
25355872bbf2SRichard Henderson         },
25365872bbf2SRichard Henderson         .phdr = {
25375872bbf2SRichard Henderson             .p_type = PT_LOAD,
25385872bbf2SRichard Henderson             .p_flags = PF_X,
25395872bbf2SRichard Henderson         },
25405872bbf2SRichard Henderson         .shdr = {
25415872bbf2SRichard Henderson             [0] = { .sh_type = SHT_NULL },
25425872bbf2SRichard Henderson             /* Trick: The contents of code_gen_buffer are not present in
25435872bbf2SRichard Henderson                this fake ELF file; that got allocated elsewhere.  Therefore
25445872bbf2SRichard Henderson                we mark .text as SHT_NOBITS (similar to .bss) so that readers
25455872bbf2SRichard Henderson                will not look for contents.  We can record any address.  */
25465872bbf2SRichard Henderson             [1] = { /* .text */
25475872bbf2SRichard Henderson                 .sh_type = SHT_NOBITS,
25485872bbf2SRichard Henderson                 .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
25495872bbf2SRichard Henderson             },
25505872bbf2SRichard Henderson             [2] = { /* .debug_info */
25515872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
25525872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, di),
25535872bbf2SRichard Henderson                 .sh_size = sizeof(struct DebugInfo),
25545872bbf2SRichard Henderson             },
25555872bbf2SRichard Henderson             [3] = { /* .debug_abbrev */
25565872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
25575872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, da),
25585872bbf2SRichard Henderson                 .sh_size = sizeof(img->da),
25595872bbf2SRichard Henderson             },
25605872bbf2SRichard Henderson             [4] = { /* .debug_frame */
25615872bbf2SRichard Henderson                 .sh_type = SHT_PROGBITS,
25625872bbf2SRichard Henderson                 .sh_offset = sizeof(struct ElfImage),
25635872bbf2SRichard Henderson             },
25645872bbf2SRichard Henderson             [5] = { /* .symtab */
25655872bbf2SRichard Henderson                 .sh_type = SHT_SYMTAB,
25665872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, sym),
25675872bbf2SRichard Henderson                 .sh_size = sizeof(img->sym),
25685872bbf2SRichard Henderson                 .sh_info = 1,
25695872bbf2SRichard Henderson                 .sh_link = ARRAY_SIZE(img->shdr) - 1,
25705872bbf2SRichard Henderson                 .sh_entsize = sizeof(ElfW(Sym)),
25715872bbf2SRichard Henderson             },
25725872bbf2SRichard Henderson             [6] = { /* .strtab */
25735872bbf2SRichard Henderson                 .sh_type = SHT_STRTAB,
25745872bbf2SRichard Henderson                 .sh_offset = offsetof(struct ElfImage, str),
25755872bbf2SRichard Henderson                 .sh_size = sizeof(img->str),
25765872bbf2SRichard Henderson             }
25775872bbf2SRichard Henderson         },
25785872bbf2SRichard Henderson         .sym = {
25795872bbf2SRichard Henderson             [1] = { /* code_gen_buffer */
25805872bbf2SRichard Henderson                 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
25815872bbf2SRichard Henderson                 .st_shndx = 1,
25825872bbf2SRichard Henderson             }
25835872bbf2SRichard Henderson         },
25845872bbf2SRichard Henderson         .di = {
25855872bbf2SRichard Henderson             .len = sizeof(struct DebugInfo) - 4,
25865872bbf2SRichard Henderson             .version = 2,
25875872bbf2SRichard Henderson             .ptr_size = sizeof(void *),
25885872bbf2SRichard Henderson             .cu_die = 1,
25895872bbf2SRichard Henderson             .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
25905872bbf2SRichard Henderson             .fn_die = 2,
25915872bbf2SRichard Henderson             .fn_name = "code_gen_buffer"
25925872bbf2SRichard Henderson         },
25935872bbf2SRichard Henderson         .da = {
25945872bbf2SRichard Henderson             1,          /* abbrev number (the cu) */
25955872bbf2SRichard Henderson             0x11, 1,    /* DW_TAG_compile_unit, has children */
25965872bbf2SRichard Henderson             0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
25975872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
25985872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
25995872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
26005872bbf2SRichard Henderson             2,          /* abbrev number (the fn) */
26015872bbf2SRichard Henderson             0x2e, 0,    /* DW_TAG_subprogram, no children */
26025872bbf2SRichard Henderson             0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
26035872bbf2SRichard Henderson             0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
26045872bbf2SRichard Henderson             0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
26055872bbf2SRichard Henderson             0, 0,       /* end of abbrev */
26065872bbf2SRichard Henderson             0           /* no more abbrev */
26075872bbf2SRichard Henderson         },
26085872bbf2SRichard Henderson         .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
26095872bbf2SRichard Henderson                ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
2610813da627SRichard Henderson     };
2611813da627SRichard Henderson 
2612813da627SRichard Henderson     /* We only need a single jit entry; statically allocate it.  */
2613813da627SRichard Henderson     static struct jit_code_entry one_entry;
2614813da627SRichard Henderson 
26155872bbf2SRichard Henderson     uintptr_t buf = (uintptr_t)buf_ptr;
2616813da627SRichard Henderson     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
2617813da627SRichard Henderson 
26185872bbf2SRichard Henderson     img = g_malloc(img_size);
26195872bbf2SRichard Henderson     *img = img_template;
2620813da627SRichard Henderson     memcpy(img + 1, debug_frame, debug_frame_size);
2621813da627SRichard Henderson 
26225872bbf2SRichard Henderson     img->phdr.p_vaddr = buf;
26235872bbf2SRichard Henderson     img->phdr.p_paddr = buf;
26245872bbf2SRichard Henderson     img->phdr.p_memsz = buf_size;
2625813da627SRichard Henderson 
26265872bbf2SRichard Henderson     img->shdr[1].sh_name = find_string(img->str, ".text");
26275872bbf2SRichard Henderson     img->shdr[1].sh_addr = buf;
26285872bbf2SRichard Henderson     img->shdr[1].sh_size = buf_size;
2629813da627SRichard Henderson 
26305872bbf2SRichard Henderson     img->shdr[2].sh_name = find_string(img->str, ".debug_info");
26315872bbf2SRichard Henderson     img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
26325872bbf2SRichard Henderson 
26335872bbf2SRichard Henderson     img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
26345872bbf2SRichard Henderson     img->shdr[4].sh_size = debug_frame_size;
26355872bbf2SRichard Henderson 
26365872bbf2SRichard Henderson     img->shdr[5].sh_name = find_string(img->str, ".symtab");
26375872bbf2SRichard Henderson     img->shdr[6].sh_name = find_string(img->str, ".strtab");
26385872bbf2SRichard Henderson 
26395872bbf2SRichard Henderson     img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
26405872bbf2SRichard Henderson     img->sym[1].st_value = buf;
26415872bbf2SRichard Henderson     img->sym[1].st_size = buf_size;
26425872bbf2SRichard Henderson 
26435872bbf2SRichard Henderson     img->di.cu_low_pc = buf;
26445872bbf2SRichard Henderson     img->di.cu_high_pc = buf_size;
26455872bbf2SRichard Henderson     img->di.fn_low_pc = buf;
26465872bbf2SRichard Henderson     img->di.fn_high_pc = buf_size;
2647813da627SRichard Henderson 
2648813da627SRichard Henderson #ifdef DEBUG_JIT
2649813da627SRichard Henderson     /* Enable this block to be able to debug the ELF image file creation.
2650813da627SRichard Henderson        One can use readelf, objdump, or other inspection utilities.  */
2651813da627SRichard Henderson     {
2652813da627SRichard Henderson         FILE *f = fopen("/tmp/qemu.jit", "w+b");
2653813da627SRichard Henderson         if (f) {
26545872bbf2SRichard Henderson             if (fwrite(img, img_size, 1, f) != img_size) {
2655813da627SRichard Henderson                 /* Avoid stupid unused return value warning for fwrite.  */
2656813da627SRichard Henderson             }
2657813da627SRichard Henderson             fclose(f);
2658813da627SRichard Henderson         }
2659813da627SRichard Henderson     }
2660813da627SRichard Henderson #endif
2661813da627SRichard Henderson 
2662813da627SRichard Henderson     one_entry.symfile_addr = img;
2663813da627SRichard Henderson     one_entry.symfile_size = img_size;
2664813da627SRichard Henderson 
2665813da627SRichard Henderson     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
2666813da627SRichard Henderson     __jit_debug_descriptor.relevant_entry = &one_entry;
2667813da627SRichard Henderson     __jit_debug_descriptor.first_entry = &one_entry;
2668813da627SRichard Henderson     __jit_debug_register_code();
2669813da627SRichard Henderson }
2670813da627SRichard Henderson #else
26715872bbf2SRichard Henderson /* No support for the feature.  Provide the entry point expected by exec.c,
26725872bbf2SRichard Henderson    and implement the internal function we declared earlier.  */
2673813da627SRichard Henderson 
2674813da627SRichard Henderson static void tcg_register_jit_int(void *buf, size_t size,
2675813da627SRichard Henderson                                  void *debug_frame, size_t debug_frame_size)
2676813da627SRichard Henderson {
2677813da627SRichard Henderson }
2678813da627SRichard Henderson 
2679813da627SRichard Henderson void tcg_register_jit(void *buf, size_t buf_size)
2680813da627SRichard Henderson {
2681813da627SRichard Henderson }
2682813da627SRichard Henderson #endif /* ELF_HOST_MACHINE */
2683