xref: /qemu/tcg/tcg.c (revision a7812ae412311d7d47f8aa85656faadac9d64b56)
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 suppress various consistency checks (faster) */
26c896fe29Sbellard #define NDEBUG
27c896fe29Sbellard 
28c896fe29Sbellard /* define it to use liveness analysis (better code) */
29c896fe29Sbellard #define USE_LIVENESS_ANALYSIS
30c896fe29Sbellard 
31c896fe29Sbellard #include <assert.h>
32c896fe29Sbellard #include <stdarg.h>
33c896fe29Sbellard #include <stdlib.h>
34c896fe29Sbellard #include <stdio.h>
35c896fe29Sbellard #include <string.h>
36c896fe29Sbellard #include <inttypes.h>
373fe43da7Sbellard #ifdef _WIN32
383fe43da7Sbellard #include <malloc.h>
393fe43da7Sbellard #endif
40c896fe29Sbellard 
41c896fe29Sbellard #include "config.h"
42ca10f867Saurel32 #include "qemu-common.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 #include "exec-all.h"
50c896fe29Sbellard 
51c896fe29Sbellard #include "tcg-op.h"
52c896fe29Sbellard #include "elf.h"
53c896fe29Sbellard 
54c896fe29Sbellard 
55c896fe29Sbellard static void patch_reloc(uint8_t *code_ptr, int type,
56f54b3f92Saurel32                         tcg_target_long value, tcg_target_long addend);
57c896fe29Sbellard 
58c896fe29Sbellard TCGOpDef tcg_op_defs[] = {
59c896fe29Sbellard #define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size },
60c896fe29Sbellard #define DEF2(s, iargs, oargs, cargs, flags) { #s, iargs, oargs, cargs, iargs + oargs + cargs, flags, 0 },
61c896fe29Sbellard #include "tcg-opc.h"
62c896fe29Sbellard #undef DEF
63c896fe29Sbellard #undef DEF2
64c896fe29Sbellard };
65c896fe29Sbellard 
66b1d8e52eSblueswir1 static TCGRegSet tcg_target_available_regs[2];
67b1d8e52eSblueswir1 static TCGRegSet tcg_target_call_clobber_regs;
68c896fe29Sbellard 
69c896fe29Sbellard /* XXX: move that inside the context */
70c896fe29Sbellard uint16_t *gen_opc_ptr;
71c896fe29Sbellard TCGArg *gen_opparam_ptr;
72c896fe29Sbellard 
73c896fe29Sbellard static inline void tcg_out8(TCGContext *s, uint8_t v)
74c896fe29Sbellard {
75c896fe29Sbellard     *s->code_ptr++ = v;
76c896fe29Sbellard }
77c896fe29Sbellard 
78c896fe29Sbellard static inline void tcg_out16(TCGContext *s, uint16_t v)
79c896fe29Sbellard {
80c896fe29Sbellard     *(uint16_t *)s->code_ptr = v;
81c896fe29Sbellard     s->code_ptr += 2;
82c896fe29Sbellard }
83c896fe29Sbellard 
84c896fe29Sbellard static inline void tcg_out32(TCGContext *s, uint32_t v)
85c896fe29Sbellard {
86c896fe29Sbellard     *(uint32_t *)s->code_ptr = v;
87c896fe29Sbellard     s->code_ptr += 4;
88c896fe29Sbellard }
89c896fe29Sbellard 
90c896fe29Sbellard /* label relocation processing */
91c896fe29Sbellard 
92c896fe29Sbellard void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type,
93c896fe29Sbellard                    int label_index, long addend)
94c896fe29Sbellard {
95c896fe29Sbellard     TCGLabel *l;
96c896fe29Sbellard     TCGRelocation *r;
97c896fe29Sbellard 
98c896fe29Sbellard     l = &s->labels[label_index];
99c896fe29Sbellard     if (l->has_value) {
100623e265cSpbrook         /* FIXME: This may break relocations on RISC targets that
101623e265cSpbrook            modify instruction fields in place.  The caller may not have
102623e265cSpbrook            written the initial value.  */
103f54b3f92Saurel32         patch_reloc(code_ptr, type, l->u.value, addend);
104c896fe29Sbellard     } else {
105c896fe29Sbellard         /* add a new relocation entry */
106c896fe29Sbellard         r = tcg_malloc(sizeof(TCGRelocation));
107c896fe29Sbellard         r->type = type;
108c896fe29Sbellard         r->ptr = code_ptr;
109c896fe29Sbellard         r->addend = addend;
110c896fe29Sbellard         r->next = l->u.first_reloc;
111c896fe29Sbellard         l->u.first_reloc = r;
112c896fe29Sbellard     }
113c896fe29Sbellard }
114c896fe29Sbellard 
115c896fe29Sbellard static void tcg_out_label(TCGContext *s, int label_index,
116c896fe29Sbellard                           tcg_target_long value)
117c896fe29Sbellard {
118c896fe29Sbellard     TCGLabel *l;
119c896fe29Sbellard     TCGRelocation *r;
120c896fe29Sbellard 
121c896fe29Sbellard     l = &s->labels[label_index];
122c896fe29Sbellard     if (l->has_value)
123c896fe29Sbellard         tcg_abort();
124c896fe29Sbellard     r = l->u.first_reloc;
125c896fe29Sbellard     while (r != NULL) {
126f54b3f92Saurel32         patch_reloc(r->ptr, r->type, value, r->addend);
127c896fe29Sbellard         r = r->next;
128c896fe29Sbellard     }
129c896fe29Sbellard     l->has_value = 1;
130c896fe29Sbellard     l->u.value = value;
131c896fe29Sbellard }
132c896fe29Sbellard 
133c896fe29Sbellard int gen_new_label(void)
134c896fe29Sbellard {
135c896fe29Sbellard     TCGContext *s = &tcg_ctx;
136c896fe29Sbellard     int idx;
137c896fe29Sbellard     TCGLabel *l;
138c896fe29Sbellard 
139c896fe29Sbellard     if (s->nb_labels >= TCG_MAX_LABELS)
140c896fe29Sbellard         tcg_abort();
141c896fe29Sbellard     idx = s->nb_labels++;
142c896fe29Sbellard     l = &s->labels[idx];
143c896fe29Sbellard     l->has_value = 0;
144c896fe29Sbellard     l->u.first_reloc = NULL;
145c896fe29Sbellard     return idx;
146c896fe29Sbellard }
147c896fe29Sbellard 
148c896fe29Sbellard #include "tcg-target.c"
149c896fe29Sbellard 
150c896fe29Sbellard /* pool based memory allocation */
151c896fe29Sbellard void *tcg_malloc_internal(TCGContext *s, int size)
152c896fe29Sbellard {
153c896fe29Sbellard     TCGPool *p;
154c896fe29Sbellard     int pool_size;
155c896fe29Sbellard 
156c896fe29Sbellard     if (size > TCG_POOL_CHUNK_SIZE) {
157c896fe29Sbellard         /* big malloc: insert a new pool (XXX: could optimize) */
158c896fe29Sbellard         p = qemu_malloc(sizeof(TCGPool) + size);
159c896fe29Sbellard         p->size = size;
160c896fe29Sbellard         if (s->pool_current)
161c896fe29Sbellard             s->pool_current->next = p;
162c896fe29Sbellard         else
163c896fe29Sbellard             s->pool_first = p;
164c896fe29Sbellard         p->next = s->pool_current;
165c896fe29Sbellard     } else {
166c896fe29Sbellard         p = s->pool_current;
167c896fe29Sbellard         if (!p) {
168c896fe29Sbellard             p = s->pool_first;
169c896fe29Sbellard             if (!p)
170c896fe29Sbellard                 goto new_pool;
171c896fe29Sbellard         } else {
172c896fe29Sbellard             if (!p->next) {
173c896fe29Sbellard             new_pool:
174c896fe29Sbellard                 pool_size = TCG_POOL_CHUNK_SIZE;
175c896fe29Sbellard                 p = qemu_malloc(sizeof(TCGPool) + pool_size);
176c896fe29Sbellard                 p->size = pool_size;
177c896fe29Sbellard                 p->next = NULL;
178c896fe29Sbellard                 if (s->pool_current)
179c896fe29Sbellard                     s->pool_current->next = p;
180c896fe29Sbellard                 else
181c896fe29Sbellard                     s->pool_first = p;
182c896fe29Sbellard             } else {
183c896fe29Sbellard                 p = p->next;
184c896fe29Sbellard             }
185c896fe29Sbellard         }
186c896fe29Sbellard     }
187c896fe29Sbellard     s->pool_current = p;
188c896fe29Sbellard     s->pool_cur = p->data + size;
189c896fe29Sbellard     s->pool_end = p->data + p->size;
190c896fe29Sbellard     return p->data;
191c896fe29Sbellard }
192c896fe29Sbellard 
193c896fe29Sbellard void tcg_pool_reset(TCGContext *s)
194c896fe29Sbellard {
195c896fe29Sbellard     s->pool_cur = s->pool_end = NULL;
196c896fe29Sbellard     s->pool_current = NULL;
197c896fe29Sbellard }
198c896fe29Sbellard 
199c896fe29Sbellard void tcg_context_init(TCGContext *s)
200c896fe29Sbellard {
201c896fe29Sbellard     int op, total_args, n;
202c896fe29Sbellard     TCGOpDef *def;
203c896fe29Sbellard     TCGArgConstraint *args_ct;
204c896fe29Sbellard     int *sorted_args;
205c896fe29Sbellard 
206c896fe29Sbellard     memset(s, 0, sizeof(*s));
207c896fe29Sbellard     s->temps = s->static_temps;
208c896fe29Sbellard     s->nb_globals = 0;
209c896fe29Sbellard 
210c896fe29Sbellard     /* Count total number of arguments and allocate the corresponding
211c896fe29Sbellard        space */
212c896fe29Sbellard     total_args = 0;
213c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
214c896fe29Sbellard         def = &tcg_op_defs[op];
215c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
216c896fe29Sbellard         total_args += n;
217c896fe29Sbellard     }
218c896fe29Sbellard 
219c896fe29Sbellard     args_ct = qemu_malloc(sizeof(TCGArgConstraint) * total_args);
220c896fe29Sbellard     sorted_args = qemu_malloc(sizeof(int) * total_args);
221c896fe29Sbellard 
222c896fe29Sbellard     for(op = 0; op < NB_OPS; op++) {
223c896fe29Sbellard         def = &tcg_op_defs[op];
224c896fe29Sbellard         def->args_ct = args_ct;
225c896fe29Sbellard         def->sorted_args = sorted_args;
226c896fe29Sbellard         n = def->nb_iargs + def->nb_oargs;
227c896fe29Sbellard         sorted_args += n;
228c896fe29Sbellard         args_ct += n;
229c896fe29Sbellard     }
230c896fe29Sbellard 
231c896fe29Sbellard     tcg_target_init(s);
232b03cce8eSbellard 
233b03cce8eSbellard     /* init global prologue and epilogue */
234b03cce8eSbellard     s->code_buf = code_gen_prologue;
235b03cce8eSbellard     s->code_ptr = s->code_buf;
236b03cce8eSbellard     tcg_target_qemu_prologue(s);
237b03cce8eSbellard     flush_icache_range((unsigned long)s->code_buf,
238b03cce8eSbellard                        (unsigned long)s->code_ptr);
239c896fe29Sbellard }
240c896fe29Sbellard 
241c896fe29Sbellard void tcg_set_frame(TCGContext *s, int reg,
242c896fe29Sbellard                    tcg_target_long start, tcg_target_long size)
243c896fe29Sbellard {
244c896fe29Sbellard     s->frame_start = start;
245c896fe29Sbellard     s->frame_end = start + size;
246c896fe29Sbellard     s->frame_reg = reg;
247c896fe29Sbellard }
248c896fe29Sbellard 
249c896fe29Sbellard void tcg_func_start(TCGContext *s)
250c896fe29Sbellard {
251e8996ee0Sbellard     int i;
252c896fe29Sbellard     tcg_pool_reset(s);
253c896fe29Sbellard     s->nb_temps = s->nb_globals;
254641d5fbeSbellard     for(i = 0; i < (TCG_TYPE_COUNT * 2); i++)
255e8996ee0Sbellard         s->first_free_temp[i] = -1;
256c896fe29Sbellard     s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS);
257c896fe29Sbellard     s->nb_labels = 0;
258c896fe29Sbellard     s->current_frame_offset = s->frame_start;
259c896fe29Sbellard 
260c896fe29Sbellard     gen_opc_ptr = gen_opc_buf;
261c896fe29Sbellard     gen_opparam_ptr = gen_opparam_buf;
262c896fe29Sbellard }
263c896fe29Sbellard 
264c896fe29Sbellard static inline void tcg_temp_alloc(TCGContext *s, int n)
265c896fe29Sbellard {
266c896fe29Sbellard     if (n > TCG_MAX_TEMPS)
267c896fe29Sbellard         tcg_abort();
268c896fe29Sbellard }
269c896fe29Sbellard 
270*a7812ae4Spbrook static inline int tcg_global_reg_new_internal(TCGType type, int reg,
271*a7812ae4Spbrook                                               const char *name)
272c896fe29Sbellard {
273c896fe29Sbellard     TCGContext *s = &tcg_ctx;
274c896fe29Sbellard     TCGTemp *ts;
275c896fe29Sbellard     int idx;
276c896fe29Sbellard 
277c896fe29Sbellard #if TCG_TARGET_REG_BITS == 32
278c896fe29Sbellard     if (type != TCG_TYPE_I32)
279c896fe29Sbellard         tcg_abort();
280c896fe29Sbellard #endif
281c896fe29Sbellard     if (tcg_regset_test_reg(s->reserved_regs, reg))
282c896fe29Sbellard         tcg_abort();
283c896fe29Sbellard     idx = s->nb_globals;
284c896fe29Sbellard     tcg_temp_alloc(s, s->nb_globals + 1);
285c896fe29Sbellard     ts = &s->temps[s->nb_globals];
286c896fe29Sbellard     ts->base_type = type;
287c896fe29Sbellard     ts->type = type;
288c896fe29Sbellard     ts->fixed_reg = 1;
289c896fe29Sbellard     ts->reg = reg;
290c896fe29Sbellard     ts->name = name;
291c896fe29Sbellard     s->nb_globals++;
292c896fe29Sbellard     tcg_regset_set_reg(s->reserved_regs, reg);
293*a7812ae4Spbrook     return idx;
294*a7812ae4Spbrook }
295*a7812ae4Spbrook 
296*a7812ae4Spbrook TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name)
297*a7812ae4Spbrook {
298*a7812ae4Spbrook     int idx;
299*a7812ae4Spbrook 
300*a7812ae4Spbrook     idx = tcg_global_reg_new_internal(TCG_TYPE_I32, reg, name);
301*a7812ae4Spbrook     return MAKE_TCGV_I32(idx);
302*a7812ae4Spbrook }
303*a7812ae4Spbrook 
304*a7812ae4Spbrook TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name)
305*a7812ae4Spbrook {
306*a7812ae4Spbrook     int idx;
307*a7812ae4Spbrook 
308*a7812ae4Spbrook     idx = tcg_global_reg_new_internal(TCG_TYPE_I64, reg, name);
309*a7812ae4Spbrook     return MAKE_TCGV_I64(idx);
310c896fe29Sbellard }
311c896fe29Sbellard 
3126a8d7b76Sbellard #if TCG_TARGET_REG_BITS == 32
3136a8d7b76Sbellard /* temporary hack to avoid register shortage for tcg_qemu_st64() */
314*a7812ae4Spbrook TCGv_i64 tcg_global_reg2_new_hack(TCGType type, int reg1, int reg2,
3156a8d7b76Sbellard                                   const char *name)
3166a8d7b76Sbellard {
3176a8d7b76Sbellard     TCGContext *s = &tcg_ctx;
3186a8d7b76Sbellard     TCGTemp *ts;
3196a8d7b76Sbellard     int idx;
3206a8d7b76Sbellard     char buf[64];
3216a8d7b76Sbellard 
3226a8d7b76Sbellard     if (type != TCG_TYPE_I64)
3236a8d7b76Sbellard         tcg_abort();
3246a8d7b76Sbellard     idx = s->nb_globals;
3256a8d7b76Sbellard     tcg_temp_alloc(s, s->nb_globals + 2);
3266a8d7b76Sbellard     ts = &s->temps[s->nb_globals];
3276a8d7b76Sbellard     ts->base_type = type;
3286a8d7b76Sbellard     ts->type = TCG_TYPE_I32;
3296a8d7b76Sbellard     ts->fixed_reg = 1;
3306a8d7b76Sbellard     ts->reg = reg1;
3316a8d7b76Sbellard     pstrcpy(buf, sizeof(buf), name);
3326a8d7b76Sbellard     pstrcat(buf, sizeof(buf), "_0");
3336a8d7b76Sbellard     ts->name = strdup(buf);
3346a8d7b76Sbellard 
3356a8d7b76Sbellard     ts++;
3366a8d7b76Sbellard     ts->base_type = type;
3376a8d7b76Sbellard     ts->type = TCG_TYPE_I32;
3386a8d7b76Sbellard     ts->fixed_reg = 1;
3396a8d7b76Sbellard     ts->reg = reg2;
3406a8d7b76Sbellard     pstrcpy(buf, sizeof(buf), name);
3416a8d7b76Sbellard     pstrcat(buf, sizeof(buf), "_1");
3426a8d7b76Sbellard     ts->name = strdup(buf);
3436a8d7b76Sbellard 
3446a8d7b76Sbellard     s->nb_globals += 2;
345*a7812ae4Spbrook     return MAKE_TCGV_I64(idx);
3466a8d7b76Sbellard }
3476a8d7b76Sbellard #endif
3486a8d7b76Sbellard 
349*a7812ae4Spbrook static inline int tcg_global_mem_new_internal(TCGType type, int reg,
350*a7812ae4Spbrook                                               tcg_target_long offset,
351c896fe29Sbellard                                               const char *name)
352c896fe29Sbellard {
353c896fe29Sbellard     TCGContext *s = &tcg_ctx;
354c896fe29Sbellard     TCGTemp *ts;
355c896fe29Sbellard     int idx;
356c896fe29Sbellard 
357c896fe29Sbellard     idx = s->nb_globals;
358c896fe29Sbellard #if TCG_TARGET_REG_BITS == 32
359c896fe29Sbellard     if (type == TCG_TYPE_I64) {
360c896fe29Sbellard         char buf[64];
361c588979bSths         tcg_temp_alloc(s, s->nb_globals + 2);
362c896fe29Sbellard         ts = &s->temps[s->nb_globals];
363c896fe29Sbellard         ts->base_type = type;
364c896fe29Sbellard         ts->type = TCG_TYPE_I32;
365c896fe29Sbellard         ts->fixed_reg = 0;
366c896fe29Sbellard         ts->mem_allocated = 1;
367c896fe29Sbellard         ts->mem_reg = reg;
368c896fe29Sbellard #ifdef TCG_TARGET_WORDS_BIGENDIAN
369c896fe29Sbellard         ts->mem_offset = offset + 4;
370c896fe29Sbellard #else
371c896fe29Sbellard         ts->mem_offset = offset;
372c896fe29Sbellard #endif
373c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
374c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_0");
375c896fe29Sbellard         ts->name = strdup(buf);
376c896fe29Sbellard         ts++;
377c896fe29Sbellard 
378c896fe29Sbellard         ts->base_type = type;
379c896fe29Sbellard         ts->type = TCG_TYPE_I32;
380c896fe29Sbellard         ts->fixed_reg = 0;
381c896fe29Sbellard         ts->mem_allocated = 1;
382c896fe29Sbellard         ts->mem_reg = reg;
383c896fe29Sbellard #ifdef TCG_TARGET_WORDS_BIGENDIAN
384c896fe29Sbellard         ts->mem_offset = offset;
385c896fe29Sbellard #else
386c896fe29Sbellard         ts->mem_offset = offset + 4;
387c896fe29Sbellard #endif
388c896fe29Sbellard         pstrcpy(buf, sizeof(buf), name);
389c896fe29Sbellard         pstrcat(buf, sizeof(buf), "_1");
390c896fe29Sbellard         ts->name = strdup(buf);
391c896fe29Sbellard 
392c896fe29Sbellard         s->nb_globals += 2;
393c896fe29Sbellard     } else
394c896fe29Sbellard #endif
395c896fe29Sbellard     {
396c896fe29Sbellard         tcg_temp_alloc(s, s->nb_globals + 1);
397c896fe29Sbellard         ts = &s->temps[s->nb_globals];
398c896fe29Sbellard         ts->base_type = type;
399c896fe29Sbellard         ts->type = type;
400c896fe29Sbellard         ts->fixed_reg = 0;
401c896fe29Sbellard         ts->mem_allocated = 1;
402c896fe29Sbellard         ts->mem_reg = reg;
403c896fe29Sbellard         ts->mem_offset = offset;
404c896fe29Sbellard         ts->name = name;
405c896fe29Sbellard         s->nb_globals++;
406c896fe29Sbellard     }
407*a7812ae4Spbrook     return idx;
408c896fe29Sbellard }
409c896fe29Sbellard 
410*a7812ae4Spbrook TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset,
411*a7812ae4Spbrook                                 const char *name)
412*a7812ae4Spbrook {
413*a7812ae4Spbrook     int idx;
414*a7812ae4Spbrook 
415*a7812ae4Spbrook     idx = tcg_global_mem_new_internal(TCG_TYPE_I32, reg, offset, name);
416*a7812ae4Spbrook     return MAKE_TCGV_I32(idx);
417*a7812ae4Spbrook }
418*a7812ae4Spbrook 
419*a7812ae4Spbrook TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset,
420*a7812ae4Spbrook                                 const char *name)
421*a7812ae4Spbrook {
422*a7812ae4Spbrook     int idx;
423*a7812ae4Spbrook 
424*a7812ae4Spbrook     idx = tcg_global_mem_new_internal(TCG_TYPE_I64, reg, offset, name);
425*a7812ae4Spbrook     return MAKE_TCGV_I64(idx);
426*a7812ae4Spbrook }
427*a7812ae4Spbrook 
428*a7812ae4Spbrook static inline int tcg_temp_new_internal(TCGType type, int temp_local)
429c896fe29Sbellard {
430c896fe29Sbellard     TCGContext *s = &tcg_ctx;
431c896fe29Sbellard     TCGTemp *ts;
432641d5fbeSbellard     int idx, k;
433c896fe29Sbellard 
434641d5fbeSbellard     k = type;
435641d5fbeSbellard     if (temp_local)
436641d5fbeSbellard         k += TCG_TYPE_COUNT;
437641d5fbeSbellard     idx = s->first_free_temp[k];
438e8996ee0Sbellard     if (idx != -1) {
439e8996ee0Sbellard         /* There is already an available temp with the
440e8996ee0Sbellard            right type */
441e8996ee0Sbellard         ts = &s->temps[idx];
442641d5fbeSbellard         s->first_free_temp[k] = ts->next_free_temp;
443e8996ee0Sbellard         ts->temp_allocated = 1;
444641d5fbeSbellard         assert(ts->temp_local == temp_local);
445e8996ee0Sbellard     } else {
446c896fe29Sbellard         idx = s->nb_temps;
447c896fe29Sbellard #if TCG_TARGET_REG_BITS == 32
448c896fe29Sbellard         if (type == TCG_TYPE_I64) {
4498df1ca4bSths             tcg_temp_alloc(s, s->nb_temps + 2);
450c896fe29Sbellard             ts = &s->temps[s->nb_temps];
451c896fe29Sbellard             ts->base_type = type;
452c896fe29Sbellard             ts->type = TCG_TYPE_I32;
453e8996ee0Sbellard             ts->temp_allocated = 1;
454641d5fbeSbellard             ts->temp_local = temp_local;
455c896fe29Sbellard             ts->name = NULL;
456c896fe29Sbellard             ts++;
457c896fe29Sbellard             ts->base_type = TCG_TYPE_I32;
458c896fe29Sbellard             ts->type = TCG_TYPE_I32;
459e8996ee0Sbellard             ts->temp_allocated = 1;
460641d5fbeSbellard             ts->temp_local = temp_local;
461c896fe29Sbellard             ts->name = NULL;
462c896fe29Sbellard             s->nb_temps += 2;
463c896fe29Sbellard         } else
464c896fe29Sbellard #endif
465c896fe29Sbellard         {
466c896fe29Sbellard             tcg_temp_alloc(s, s->nb_temps + 1);
467c896fe29Sbellard             ts = &s->temps[s->nb_temps];
468c896fe29Sbellard             ts->base_type = type;
469c896fe29Sbellard             ts->type = type;
470e8996ee0Sbellard             ts->temp_allocated = 1;
471641d5fbeSbellard             ts->temp_local = temp_local;
472c896fe29Sbellard             ts->name = NULL;
473c896fe29Sbellard             s->nb_temps++;
474c896fe29Sbellard         }
475e8996ee0Sbellard     }
476*a7812ae4Spbrook     return idx;
477c896fe29Sbellard }
478c896fe29Sbellard 
479*a7812ae4Spbrook TCGv_i32 tcg_temp_new_internal_i32(int temp_local)
480*a7812ae4Spbrook {
481*a7812ae4Spbrook     int idx;
482*a7812ae4Spbrook 
483*a7812ae4Spbrook     idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local);
484*a7812ae4Spbrook     return MAKE_TCGV_I32(idx);
485*a7812ae4Spbrook }
486*a7812ae4Spbrook 
487*a7812ae4Spbrook TCGv_i64 tcg_temp_new_internal_i64(int temp_local)
488*a7812ae4Spbrook {
489*a7812ae4Spbrook     int idx;
490*a7812ae4Spbrook 
491*a7812ae4Spbrook     idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local);
492*a7812ae4Spbrook     return MAKE_TCGV_I64(idx);
493*a7812ae4Spbrook }
494*a7812ae4Spbrook 
495*a7812ae4Spbrook static inline void tcg_temp_free_internal(int idx)
496c896fe29Sbellard {
497c896fe29Sbellard     TCGContext *s = &tcg_ctx;
498c896fe29Sbellard     TCGTemp *ts;
499641d5fbeSbellard     int k;
500c896fe29Sbellard 
501e8996ee0Sbellard     assert(idx >= s->nb_globals && idx < s->nb_temps);
502c896fe29Sbellard     ts = &s->temps[idx];
503e8996ee0Sbellard     assert(ts->temp_allocated != 0);
504e8996ee0Sbellard     ts->temp_allocated = 0;
505641d5fbeSbellard     k = ts->base_type;
506641d5fbeSbellard     if (ts->temp_local)
507641d5fbeSbellard         k += TCG_TYPE_COUNT;
508641d5fbeSbellard     ts->next_free_temp = s->first_free_temp[k];
509641d5fbeSbellard     s->first_free_temp[k] = idx;
510e8996ee0Sbellard }
511e8996ee0Sbellard 
512*a7812ae4Spbrook void tcg_temp_free_i32(TCGv_i32 arg)
513e8996ee0Sbellard {
514*a7812ae4Spbrook     tcg_temp_free_internal(GET_TCGV_I32(arg));
515*a7812ae4Spbrook }
516*a7812ae4Spbrook 
517*a7812ae4Spbrook void tcg_temp_free_i64(TCGv_i64 arg)
518*a7812ae4Spbrook {
519*a7812ae4Spbrook     tcg_temp_free_internal(GET_TCGV_I64(arg));
520*a7812ae4Spbrook }
521*a7812ae4Spbrook 
522*a7812ae4Spbrook TCGv_i32 tcg_const_i32(int32_t val)
523*a7812ae4Spbrook {
524*a7812ae4Spbrook     TCGv_i32 t0;
525*a7812ae4Spbrook     t0 = tcg_temp_new_i32();
526e8996ee0Sbellard     tcg_gen_movi_i32(t0, val);
527e8996ee0Sbellard     return t0;
528c896fe29Sbellard }
529c896fe29Sbellard 
530*a7812ae4Spbrook TCGv_i64 tcg_const_i64(int64_t val)
531c896fe29Sbellard {
532*a7812ae4Spbrook     TCGv_i64 t0;
533*a7812ae4Spbrook     t0 = tcg_temp_new_i64();
534e8996ee0Sbellard     tcg_gen_movi_i64(t0, val);
535e8996ee0Sbellard     return t0;
536c896fe29Sbellard }
537c896fe29Sbellard 
538*a7812ae4Spbrook TCGv_i32 tcg_const_local_i32(int32_t val)
539bdffd4a9Saurel32 {
540*a7812ae4Spbrook     TCGv_i32 t0;
541*a7812ae4Spbrook     t0 = tcg_temp_local_new_i32();
542bdffd4a9Saurel32     tcg_gen_movi_i32(t0, val);
543bdffd4a9Saurel32     return t0;
544bdffd4a9Saurel32 }
545bdffd4a9Saurel32 
546*a7812ae4Spbrook TCGv_i64 tcg_const_local_i64(int64_t val)
547bdffd4a9Saurel32 {
548*a7812ae4Spbrook     TCGv_i64 t0;
549*a7812ae4Spbrook     t0 = tcg_temp_local_new_i64();
550bdffd4a9Saurel32     tcg_gen_movi_i64(t0, val);
551bdffd4a9Saurel32     return t0;
552bdffd4a9Saurel32 }
553bdffd4a9Saurel32 
554c896fe29Sbellard void tcg_register_helper(void *func, const char *name)
555c896fe29Sbellard {
556c896fe29Sbellard     TCGContext *s = &tcg_ctx;
557c896fe29Sbellard     int n;
558c896fe29Sbellard     if ((s->nb_helpers + 1) > s->allocated_helpers) {
559c896fe29Sbellard         n = s->allocated_helpers;
560c896fe29Sbellard         if (n == 0) {
561c896fe29Sbellard             n = 4;
562c896fe29Sbellard         } else {
563c896fe29Sbellard             n *= 2;
564c896fe29Sbellard         }
565c896fe29Sbellard         s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo));
566c896fe29Sbellard         s->allocated_helpers = n;
567c896fe29Sbellard     }
5684dc81f28Sbellard     s->helpers[s->nb_helpers].func = (tcg_target_ulong)func;
569c896fe29Sbellard     s->helpers[s->nb_helpers].name = name;
570c896fe29Sbellard     s->nb_helpers++;
571c896fe29Sbellard }
572c896fe29Sbellard 
57339cf05d3Sbellard /* Note: we convert the 64 bit args to 32 bit and do some alignment
57439cf05d3Sbellard    and endian swap. Maybe it would be better to do the alignment
57539cf05d3Sbellard    and endian swap in tcg_reg_alloc_call(). */
576*a7812ae4Spbrook void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
577*a7812ae4Spbrook                    int sizemask, TCGArg ret, int nargs, TCGArg *args)
578c896fe29Sbellard {
579*a7812ae4Spbrook     int call_type;
580*a7812ae4Spbrook     int i;
581*a7812ae4Spbrook     int real_args;
582*a7812ae4Spbrook     int nb_rets;
583*a7812ae4Spbrook     TCGArg *nparam;
584*a7812ae4Spbrook     *gen_opc_ptr++ = INDEX_op_call;
585*a7812ae4Spbrook     nparam = gen_opparam_ptr++;
586c896fe29Sbellard     call_type = (flags & TCG_CALL_TYPE_MASK);
587*a7812ae4Spbrook     if (ret != TCG_CALL_DUMMY_ARG) {
588*a7812ae4Spbrook #if TCG_TARGET_REG_BITS < 64
589*a7812ae4Spbrook         if (sizemask & 1) {
590*a7812ae4Spbrook #ifdef TCG_TARGET_WORDS_BIGENDIAN
591*a7812ae4Spbrook             *gen_opparam_ptr++ = ret + 1;
592*a7812ae4Spbrook             *gen_opparam_ptr++ = ret;
593*a7812ae4Spbrook #else
594*a7812ae4Spbrook             *gen_opparam_ptr++ = ret;
595*a7812ae4Spbrook             *gen_opparam_ptr++ = ret + 1;
596*a7812ae4Spbrook #endif
597*a7812ae4Spbrook             nb_rets = 2;
598*a7812ae4Spbrook         } else
599*a7812ae4Spbrook #endif
600*a7812ae4Spbrook         {
601*a7812ae4Spbrook             *gen_opparam_ptr++ = ret;
602*a7812ae4Spbrook             nb_rets = 1;
603*a7812ae4Spbrook         }
604*a7812ae4Spbrook     } else {
605*a7812ae4Spbrook         nb_rets = 0;
606*a7812ae4Spbrook     }
607*a7812ae4Spbrook     real_args = 0;
608*a7812ae4Spbrook     for (i = 0; i < nargs; i++) {
609*a7812ae4Spbrook #if TCG_TARGET_REG_BITS < 64
610*a7812ae4Spbrook         if (sizemask & (2 << i)) {
611c896fe29Sbellard #ifdef TCG_TARGET_I386
612c896fe29Sbellard             /* REGPARM case: if the third parameter is 64 bit, it is
613c896fe29Sbellard                allocated on the stack */
614*a7812ae4Spbrook             if (i == 2 && call_type == TCG_CALL_TYPE_REGPARM) {
615c896fe29Sbellard                 call_type = TCG_CALL_TYPE_REGPARM_2;
616c896fe29Sbellard                 flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type;
617c896fe29Sbellard             }
618*a7812ae4Spbrook #endif
61939cf05d3Sbellard #ifdef TCG_TARGET_CALL_ALIGN_ARGS
62039cf05d3Sbellard             /* some targets want aligned 64 bit args */
621*a7812ae4Spbrook             if (i & 1) {
622*a7812ae4Spbrook                 *gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG;
62339cf05d3Sbellard             }
62439cf05d3Sbellard #endif
625c896fe29Sbellard #ifdef TCG_TARGET_WORDS_BIGENDIAN
626*a7812ae4Spbrook             *gen_opparam_ptr++ = args[i] + 1;
627*a7812ae4Spbrook             *gen_opparam_ptr++ = args[i];
628c896fe29Sbellard #else
629*a7812ae4Spbrook             *gen_opparam_ptr++ = args[i];
630*a7812ae4Spbrook             *gen_opparam_ptr++ = args[i] + 1;
631c896fe29Sbellard #endif
632*a7812ae4Spbrook             real_args += 2;
633*a7812ae4Spbrook         } else
634c896fe29Sbellard #endif
635c896fe29Sbellard         {
636*a7812ae4Spbrook             *gen_opparam_ptr++ = args[i];
637*a7812ae4Spbrook             real_args++;
638c896fe29Sbellard         }
639*a7812ae4Spbrook     }
640*a7812ae4Spbrook     *gen_opparam_ptr++ = GET_TCGV_PTR(func);
641*a7812ae4Spbrook 
642*a7812ae4Spbrook     *gen_opparam_ptr++ = flags;
643*a7812ae4Spbrook 
644*a7812ae4Spbrook     *nparam = (nb_rets << 16) | (real_args + 1);
645*a7812ae4Spbrook 
646*a7812ae4Spbrook     /* total parameters, needed to go backward in the instruction stream */
647*a7812ae4Spbrook     *gen_opparam_ptr++ = 1 + nb_rets + real_args + 3;
648*a7812ae4Spbrook }
649c896fe29Sbellard 
650ac56dd48Spbrook #if TCG_TARGET_REG_BITS == 32
651*a7812ae4Spbrook void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
652c896fe29Sbellard                         int c, int right, int arith)
653c896fe29Sbellard {
654cf60bce4Sbellard     if (c == 0) {
655*a7812ae4Spbrook         tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
656cf60bce4Sbellard         tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
657cf60bce4Sbellard     } else if (c >= 32) {
658c896fe29Sbellard         c -= 32;
659c896fe29Sbellard         if (right) {
660c896fe29Sbellard             if (arith) {
661*a7812ae4Spbrook                 tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
662ac56dd48Spbrook                 tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31);
663c896fe29Sbellard             } else {
664*a7812ae4Spbrook                 tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
665ac56dd48Spbrook                 tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
666c896fe29Sbellard             }
667c896fe29Sbellard         } else {
668*a7812ae4Spbrook             tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c);
669*a7812ae4Spbrook             tcg_gen_movi_i32(TCGV_LOW(ret), 0);
670c896fe29Sbellard         }
671c896fe29Sbellard     } else {
672*a7812ae4Spbrook         TCGv_i32 t0, t1;
673c896fe29Sbellard 
674*a7812ae4Spbrook         t0 = tcg_temp_new_i32();
675*a7812ae4Spbrook         t1 = tcg_temp_new_i32();
676c896fe29Sbellard         if (right) {
677ac56dd48Spbrook             tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c);
678c896fe29Sbellard             if (arith)
679ac56dd48Spbrook                 tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c);
680c896fe29Sbellard             else
681ac56dd48Spbrook                 tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c);
682*a7812ae4Spbrook             tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c);
683*a7812ae4Spbrook             tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0);
684ac56dd48Spbrook             tcg_gen_mov_i32(TCGV_HIGH(ret), t1);
685c896fe29Sbellard         } else {
686*a7812ae4Spbrook             tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c);
687c896fe29Sbellard             /* Note: ret can be the same as arg1, so we use t1 */
688*a7812ae4Spbrook             tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c);
689ac56dd48Spbrook             tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c);
690ac56dd48Spbrook             tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0);
691*a7812ae4Spbrook             tcg_gen_mov_i32(TCGV_LOW(ret), t1);
692c896fe29Sbellard         }
693*a7812ae4Spbrook         tcg_temp_free_i32(t0);
694*a7812ae4Spbrook         tcg_temp_free_i32(t1);
695c896fe29Sbellard     }
696c896fe29Sbellard }
697ac56dd48Spbrook #endif
698c896fe29Sbellard 
6998fcd3692Sblueswir1 static void tcg_reg_alloc_start(TCGContext *s)
700c896fe29Sbellard {
701c896fe29Sbellard     int i;
702c896fe29Sbellard     TCGTemp *ts;
703c896fe29Sbellard     for(i = 0; i < s->nb_globals; i++) {
704c896fe29Sbellard         ts = &s->temps[i];
705c896fe29Sbellard         if (ts->fixed_reg) {
706c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
707c896fe29Sbellard         } else {
708c896fe29Sbellard             ts->val_type = TEMP_VAL_MEM;
709c896fe29Sbellard         }
710c896fe29Sbellard     }
711e8996ee0Sbellard     for(i = s->nb_globals; i < s->nb_temps; i++) {
712e8996ee0Sbellard         ts = &s->temps[i];
713e8996ee0Sbellard         ts->val_type = TEMP_VAL_DEAD;
714e8996ee0Sbellard         ts->mem_allocated = 0;
715e8996ee0Sbellard         ts->fixed_reg = 0;
716e8996ee0Sbellard     }
717c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
718c896fe29Sbellard         s->reg_to_temp[i] = -1;
719c896fe29Sbellard     }
720c896fe29Sbellard }
721c896fe29Sbellard 
722ac56dd48Spbrook static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size,
723ac56dd48Spbrook                                  int idx)
724c896fe29Sbellard {
725c896fe29Sbellard     TCGTemp *ts;
726ac56dd48Spbrook 
727ac56dd48Spbrook     ts = &s->temps[idx];
728ac56dd48Spbrook     if (idx < s->nb_globals) {
729ac56dd48Spbrook         pstrcpy(buf, buf_size, ts->name);
730c896fe29Sbellard     } else {
731641d5fbeSbellard         if (ts->temp_local)
732641d5fbeSbellard             snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
733641d5fbeSbellard         else
734ac56dd48Spbrook             snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
735c896fe29Sbellard     }
736c896fe29Sbellard     return buf;
737c896fe29Sbellard }
738c896fe29Sbellard 
739*a7812ae4Spbrook char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg)
740ac56dd48Spbrook {
741*a7812ae4Spbrook     return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I32(arg));
742*a7812ae4Spbrook }
743*a7812ae4Spbrook 
744*a7812ae4Spbrook char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg)
745*a7812ae4Spbrook {
746*a7812ae4Spbrook     return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I32(arg));
747ac56dd48Spbrook }
748ac56dd48Spbrook 
749e8996ee0Sbellard static int helper_cmp(const void *p1, const void *p2)
750e8996ee0Sbellard {
751e8996ee0Sbellard     const TCGHelperInfo *th1 = p1;
752e8996ee0Sbellard     const TCGHelperInfo *th2 = p2;
753e8996ee0Sbellard     if (th1->func < th2->func)
754e8996ee0Sbellard         return -1;
755e8996ee0Sbellard     else if (th1->func == th2->func)
756e8996ee0Sbellard         return 0;
757e8996ee0Sbellard     else
758e8996ee0Sbellard         return 1;
759e8996ee0Sbellard }
760e8996ee0Sbellard 
761e8996ee0Sbellard /* find helper definition (Note: A hash table would be better) */
7624dc81f28Sbellard static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val)
7634dc81f28Sbellard {
764e8996ee0Sbellard     int m, m_min, m_max;
765e8996ee0Sbellard     TCGHelperInfo *th;
766e8996ee0Sbellard     tcg_target_ulong v;
767e8996ee0Sbellard 
768e8996ee0Sbellard     if (unlikely(!s->helpers_sorted)) {
769e8996ee0Sbellard         qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo),
770e8996ee0Sbellard               helper_cmp);
771e8996ee0Sbellard         s->helpers_sorted = 1;
772e8996ee0Sbellard     }
773e8996ee0Sbellard 
774e8996ee0Sbellard     /* binary search */
775e8996ee0Sbellard     m_min = 0;
776e8996ee0Sbellard     m_max = s->nb_helpers - 1;
777e8996ee0Sbellard     while (m_min <= m_max) {
778e8996ee0Sbellard         m = (m_min + m_max) >> 1;
779e8996ee0Sbellard         th = &s->helpers[m];
780e8996ee0Sbellard         v = th->func;
781e8996ee0Sbellard         if (v == val)
782e8996ee0Sbellard             return th;
783e8996ee0Sbellard         else if (val < v) {
784e8996ee0Sbellard             m_max = m - 1;
785e8996ee0Sbellard         } else {
786e8996ee0Sbellard             m_min = m + 1;
787e8996ee0Sbellard         }
7884dc81f28Sbellard     }
7894dc81f28Sbellard     return NULL;
7904dc81f28Sbellard }
7914dc81f28Sbellard 
792f48f3edeSblueswir1 static const char * const cond_name[] =
793f48f3edeSblueswir1 {
794f48f3edeSblueswir1     [TCG_COND_EQ] = "eq",
795f48f3edeSblueswir1     [TCG_COND_NE] = "ne",
796f48f3edeSblueswir1     [TCG_COND_LT] = "lt",
797f48f3edeSblueswir1     [TCG_COND_GE] = "ge",
798f48f3edeSblueswir1     [TCG_COND_LE] = "le",
799f48f3edeSblueswir1     [TCG_COND_GT] = "gt",
800f48f3edeSblueswir1     [TCG_COND_LTU] = "ltu",
801f48f3edeSblueswir1     [TCG_COND_GEU] = "geu",
802f48f3edeSblueswir1     [TCG_COND_LEU] = "leu",
803f48f3edeSblueswir1     [TCG_COND_GTU] = "gtu"
804f48f3edeSblueswir1 };
805f48f3edeSblueswir1 
806c896fe29Sbellard void tcg_dump_ops(TCGContext *s, FILE *outfile)
807c896fe29Sbellard {
808c896fe29Sbellard     const uint16_t *opc_ptr;
809c896fe29Sbellard     const TCGArg *args;
810c896fe29Sbellard     TCGArg arg;
8117e4597d7Sbellard     int c, i, k, nb_oargs, nb_iargs, nb_cargs, first_insn;
812c896fe29Sbellard     const TCGOpDef *def;
813c896fe29Sbellard     char buf[128];
814c896fe29Sbellard 
8157e4597d7Sbellard     first_insn = 1;
816c896fe29Sbellard     opc_ptr = gen_opc_buf;
817c896fe29Sbellard     args = gen_opparam_buf;
818c896fe29Sbellard     while (opc_ptr < gen_opc_ptr) {
819c896fe29Sbellard         c = *opc_ptr++;
820c896fe29Sbellard         def = &tcg_op_defs[c];
8217e4597d7Sbellard         if (c == INDEX_op_debug_insn_start) {
8227e4597d7Sbellard             uint64_t pc;
8237e4597d7Sbellard #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
8247e4597d7Sbellard             pc = ((uint64_t)args[1] << 32) | args[0];
8257e4597d7Sbellard #else
8267e4597d7Sbellard             pc = args[0];
8277e4597d7Sbellard #endif
8287e4597d7Sbellard             if (!first_insn)
8297e4597d7Sbellard                 fprintf(outfile, "\n");
8307e4597d7Sbellard             fprintf(outfile, " ---- 0x%" PRIx64, pc);
8317e4597d7Sbellard             first_insn = 0;
8327e4597d7Sbellard             nb_oargs = def->nb_oargs;
8337e4597d7Sbellard             nb_iargs = def->nb_iargs;
8347e4597d7Sbellard             nb_cargs = def->nb_cargs;
8357e4597d7Sbellard         } else if (c == INDEX_op_call) {
836c896fe29Sbellard             TCGArg arg;
8374dc81f28Sbellard 
838c896fe29Sbellard             /* variable number of arguments */
839c896fe29Sbellard             arg = *args++;
840c896fe29Sbellard             nb_oargs = arg >> 16;
841c896fe29Sbellard             nb_iargs = arg & 0xffff;
842c896fe29Sbellard             nb_cargs = def->nb_cargs;
843b03cce8eSbellard 
8447e4597d7Sbellard             fprintf(outfile, " %s ", def->name);
8457e4597d7Sbellard 
846b03cce8eSbellard             /* function name */
847b03cce8eSbellard             fprintf(outfile, "%s",
848e8996ee0Sbellard                     tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1]));
849b03cce8eSbellard             /* flags */
850b03cce8eSbellard             fprintf(outfile, ",$0x%" TCG_PRIlx,
851b03cce8eSbellard                     args[nb_oargs + nb_iargs]);
852b03cce8eSbellard             /* nb out args */
853b03cce8eSbellard             fprintf(outfile, ",$%d", nb_oargs);
854b03cce8eSbellard             for(i = 0; i < nb_oargs; i++) {
855b03cce8eSbellard                 fprintf(outfile, ",");
856b03cce8eSbellard                 fprintf(outfile, "%s",
857b03cce8eSbellard                         tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i]));
858b03cce8eSbellard             }
859b03cce8eSbellard             for(i = 0; i < (nb_iargs - 1); i++) {
860b03cce8eSbellard                 fprintf(outfile, ",");
86139cf05d3Sbellard                 if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) {
86239cf05d3Sbellard                     fprintf(outfile, "<dummy>");
86339cf05d3Sbellard                 } else {
864b03cce8eSbellard                     fprintf(outfile, "%s",
865b03cce8eSbellard                             tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i]));
866b03cce8eSbellard                 }
86739cf05d3Sbellard             }
868e8996ee0Sbellard         } else if (c == INDEX_op_movi_i32
869e8996ee0Sbellard #if TCG_TARGET_REG_BITS == 64
870e8996ee0Sbellard                    || c == INDEX_op_movi_i64
871e8996ee0Sbellard #endif
872e8996ee0Sbellard                    ) {
873e8996ee0Sbellard             tcg_target_ulong val;
874e8996ee0Sbellard             TCGHelperInfo *th;
875e8996ee0Sbellard 
876e8996ee0Sbellard             nb_oargs = def->nb_oargs;
877e8996ee0Sbellard             nb_iargs = def->nb_iargs;
878e8996ee0Sbellard             nb_cargs = def->nb_cargs;
879e8996ee0Sbellard             fprintf(outfile, " %s %s,$", def->name,
880e8996ee0Sbellard                     tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0]));
881e8996ee0Sbellard             val = args[1];
882e8996ee0Sbellard             th = tcg_find_helper(s, val);
883e8996ee0Sbellard             if (th) {
884e8996ee0Sbellard                 fprintf(outfile, th->name);
885e8996ee0Sbellard             } else {
886e8996ee0Sbellard                 if (c == INDEX_op_movi_i32)
887e8996ee0Sbellard                     fprintf(outfile, "0x%x", (uint32_t)val);
888e8996ee0Sbellard                 else
889e8996ee0Sbellard                     fprintf(outfile, "0x%" PRIx64 , (uint64_t)val);
890e8996ee0Sbellard             }
891b03cce8eSbellard         } else {
8927e4597d7Sbellard             fprintf(outfile, " %s ", def->name);
893b03cce8eSbellard             if (c == INDEX_op_nopn) {
894c896fe29Sbellard                 /* variable number of arguments */
895c896fe29Sbellard                 nb_cargs = *args;
896c896fe29Sbellard                 nb_oargs = 0;
897c896fe29Sbellard                 nb_iargs = 0;
898c896fe29Sbellard             } else {
899c896fe29Sbellard                 nb_oargs = def->nb_oargs;
900c896fe29Sbellard                 nb_iargs = def->nb_iargs;
901c896fe29Sbellard                 nb_cargs = def->nb_cargs;
902c896fe29Sbellard             }
903c896fe29Sbellard 
904c896fe29Sbellard             k = 0;
905c896fe29Sbellard             for(i = 0; i < nb_oargs; i++) {
906c896fe29Sbellard                 if (k != 0)
907c896fe29Sbellard                     fprintf(outfile, ",");
908ac56dd48Spbrook                 fprintf(outfile, "%s",
909ac56dd48Spbrook                         tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
910c896fe29Sbellard             }
911c896fe29Sbellard             for(i = 0; i < nb_iargs; i++) {
912c896fe29Sbellard                 if (k != 0)
913c896fe29Sbellard                     fprintf(outfile, ",");
914ac56dd48Spbrook                 fprintf(outfile, "%s",
915ac56dd48Spbrook                         tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
916c896fe29Sbellard             }
917f48f3edeSblueswir1             if (c == INDEX_op_brcond_i32
918f48f3edeSblueswir1 #if TCG_TARGET_REG_BITS == 32
919f48f3edeSblueswir1                 || c == INDEX_op_brcond2_i32
920f48f3edeSblueswir1 #elif TCG_TARGET_REG_BITS == 64
921f48f3edeSblueswir1                 || c == INDEX_op_brcond_i64
922f48f3edeSblueswir1 #endif
923f48f3edeSblueswir1                 ) {
924f48f3edeSblueswir1                 if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]])
925f48f3edeSblueswir1                     fprintf(outfile, ",%s", cond_name[args[k++]]);
926f48f3edeSblueswir1                 else
927f48f3edeSblueswir1                     fprintf(outfile, ",$0x%" TCG_PRIlx, args[k++]);
928f48f3edeSblueswir1                 i = 1;
929f48f3edeSblueswir1             }
930f48f3edeSblueswir1             else
931f48f3edeSblueswir1                 i = 0;
932f48f3edeSblueswir1             for(; i < nb_cargs; i++) {
933c896fe29Sbellard                 if (k != 0)
934c896fe29Sbellard                     fprintf(outfile, ",");
935c896fe29Sbellard                 arg = args[k++];
936c896fe29Sbellard                 fprintf(outfile, "$0x%" TCG_PRIlx, arg);
937c896fe29Sbellard             }
938b03cce8eSbellard         }
939c896fe29Sbellard         fprintf(outfile, "\n");
940c896fe29Sbellard         args += nb_iargs + nb_oargs + nb_cargs;
941c896fe29Sbellard     }
942c896fe29Sbellard }
943c896fe29Sbellard 
944c896fe29Sbellard /* we give more priority to constraints with less registers */
945c896fe29Sbellard static int get_constraint_priority(const TCGOpDef *def, int k)
946c896fe29Sbellard {
947c896fe29Sbellard     const TCGArgConstraint *arg_ct;
948c896fe29Sbellard 
949c896fe29Sbellard     int i, n;
950c896fe29Sbellard     arg_ct = &def->args_ct[k];
951c896fe29Sbellard     if (arg_ct->ct & TCG_CT_ALIAS) {
952c896fe29Sbellard         /* an alias is equivalent to a single register */
953c896fe29Sbellard         n = 1;
954c896fe29Sbellard     } else {
955c896fe29Sbellard         if (!(arg_ct->ct & TCG_CT_REG))
956c896fe29Sbellard             return 0;
957c896fe29Sbellard         n = 0;
958c896fe29Sbellard         for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
959c896fe29Sbellard             if (tcg_regset_test_reg(arg_ct->u.regs, i))
960c896fe29Sbellard                 n++;
961c896fe29Sbellard         }
962c896fe29Sbellard     }
963c896fe29Sbellard     return TCG_TARGET_NB_REGS - n + 1;
964c896fe29Sbellard }
965c896fe29Sbellard 
966c896fe29Sbellard /* sort from highest priority to lowest */
967c896fe29Sbellard static void sort_constraints(TCGOpDef *def, int start, int n)
968c896fe29Sbellard {
969c896fe29Sbellard     int i, j, p1, p2, tmp;
970c896fe29Sbellard 
971c896fe29Sbellard     for(i = 0; i < n; i++)
972c896fe29Sbellard         def->sorted_args[start + i] = start + i;
973c896fe29Sbellard     if (n <= 1)
974c896fe29Sbellard         return;
975c896fe29Sbellard     for(i = 0; i < n - 1; i++) {
976c896fe29Sbellard         for(j = i + 1; j < n; j++) {
977c896fe29Sbellard             p1 = get_constraint_priority(def, def->sorted_args[start + i]);
978c896fe29Sbellard             p2 = get_constraint_priority(def, def->sorted_args[start + j]);
979c896fe29Sbellard             if (p1 < p2) {
980c896fe29Sbellard                 tmp = def->sorted_args[start + i];
981c896fe29Sbellard                 def->sorted_args[start + i] = def->sorted_args[start + j];
982c896fe29Sbellard                 def->sorted_args[start + j] = tmp;
983c896fe29Sbellard             }
984c896fe29Sbellard         }
985c896fe29Sbellard     }
986c896fe29Sbellard }
987c896fe29Sbellard 
988c896fe29Sbellard void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
989c896fe29Sbellard {
990c896fe29Sbellard     int op;
991c896fe29Sbellard     TCGOpDef *def;
992c896fe29Sbellard     const char *ct_str;
993c896fe29Sbellard     int i, nb_args;
994c896fe29Sbellard 
995c896fe29Sbellard     for(;;) {
996c896fe29Sbellard         if (tdefs->op < 0)
997c896fe29Sbellard             break;
998c896fe29Sbellard         op = tdefs->op;
999c896fe29Sbellard         assert(op >= 0 && op < NB_OPS);
1000c896fe29Sbellard         def = &tcg_op_defs[op];
1001c896fe29Sbellard         nb_args = def->nb_iargs + def->nb_oargs;
1002c896fe29Sbellard         for(i = 0; i < nb_args; i++) {
1003c896fe29Sbellard             ct_str = tdefs->args_ct_str[i];
1004c896fe29Sbellard             tcg_regset_clear(def->args_ct[i].u.regs);
1005c896fe29Sbellard             def->args_ct[i].ct = 0;
1006c896fe29Sbellard             if (ct_str[0] >= '0' && ct_str[0] <= '9') {
1007c896fe29Sbellard                 int oarg;
1008c896fe29Sbellard                 oarg = ct_str[0] - '0';
1009c896fe29Sbellard                 assert(oarg < def->nb_oargs);
1010c896fe29Sbellard                 assert(def->args_ct[oarg].ct & TCG_CT_REG);
1011c896fe29Sbellard                 /* TCG_CT_ALIAS is for the output arguments. The input
10125ff9d6a4Sbellard                    argument is tagged with TCG_CT_IALIAS. */
1013c896fe29Sbellard                 def->args_ct[i] = def->args_ct[oarg];
10145ff9d6a4Sbellard                 def->args_ct[oarg].ct = TCG_CT_ALIAS;
10155ff9d6a4Sbellard                 def->args_ct[oarg].alias_index = i;
1016c896fe29Sbellard                 def->args_ct[i].ct |= TCG_CT_IALIAS;
10175ff9d6a4Sbellard                 def->args_ct[i].alias_index = oarg;
1018c896fe29Sbellard             } else {
1019c896fe29Sbellard                 for(;;) {
1020c896fe29Sbellard                     if (*ct_str == '\0')
1021c896fe29Sbellard                         break;
1022c896fe29Sbellard                     switch(*ct_str) {
1023c896fe29Sbellard                     case 'i':
1024c896fe29Sbellard                         def->args_ct[i].ct |= TCG_CT_CONST;
1025c896fe29Sbellard                         ct_str++;
1026c896fe29Sbellard                         break;
1027c896fe29Sbellard                     default:
1028c896fe29Sbellard                         if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) {
1029c896fe29Sbellard                             fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n",
1030c896fe29Sbellard                                     ct_str, i, def->name);
1031c896fe29Sbellard                             exit(1);
1032c896fe29Sbellard                         }
1033c896fe29Sbellard                     }
1034c896fe29Sbellard                 }
1035c896fe29Sbellard             }
1036c896fe29Sbellard         }
1037c896fe29Sbellard 
1038c896fe29Sbellard         /* sort the constraints (XXX: this is just an heuristic) */
1039c896fe29Sbellard         sort_constraints(def, 0, def->nb_oargs);
1040c896fe29Sbellard         sort_constraints(def, def->nb_oargs, def->nb_iargs);
1041c896fe29Sbellard 
1042c896fe29Sbellard #if 0
1043c896fe29Sbellard         {
1044c896fe29Sbellard             int i;
1045c896fe29Sbellard 
1046c896fe29Sbellard             printf("%s: sorted=", def->name);
1047c896fe29Sbellard             for(i = 0; i < def->nb_oargs + def->nb_iargs; i++)
1048c896fe29Sbellard                 printf(" %d", def->sorted_args[i]);
1049c896fe29Sbellard             printf("\n");
1050c896fe29Sbellard         }
1051c896fe29Sbellard #endif
1052c896fe29Sbellard         tdefs++;
1053c896fe29Sbellard     }
1054c896fe29Sbellard 
1055c896fe29Sbellard }
1056c896fe29Sbellard 
1057c896fe29Sbellard #ifdef USE_LIVENESS_ANALYSIS
1058c896fe29Sbellard 
1059c896fe29Sbellard /* set a nop for an operation using 'nb_args' */
1060c896fe29Sbellard static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr,
1061c896fe29Sbellard                                TCGArg *args, int nb_args)
1062c896fe29Sbellard {
1063c896fe29Sbellard     if (nb_args == 0) {
1064c896fe29Sbellard         *opc_ptr = INDEX_op_nop;
1065c896fe29Sbellard     } else {
1066c896fe29Sbellard         *opc_ptr = INDEX_op_nopn;
1067c896fe29Sbellard         args[0] = nb_args;
1068c896fe29Sbellard         args[nb_args - 1] = nb_args;
1069c896fe29Sbellard     }
1070c896fe29Sbellard }
1071c896fe29Sbellard 
1072641d5fbeSbellard /* liveness analysis: end of function: globals are live, temps are
1073641d5fbeSbellard    dead. */
1074641d5fbeSbellard /* XXX: at this stage, not used as there would be little gains because
1075641d5fbeSbellard    most TBs end with a conditional jump. */
1076641d5fbeSbellard static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps)
1077c896fe29Sbellard {
1078c896fe29Sbellard     memset(dead_temps, 0, s->nb_globals);
1079c896fe29Sbellard     memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals);
1080c896fe29Sbellard }
1081c896fe29Sbellard 
1082641d5fbeSbellard /* liveness analysis: end of basic block: globals are live, temps are
1083641d5fbeSbellard    dead, local temps are live. */
1084641d5fbeSbellard static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps)
1085641d5fbeSbellard {
1086641d5fbeSbellard     int i;
1087641d5fbeSbellard     TCGTemp *ts;
1088641d5fbeSbellard 
1089641d5fbeSbellard     memset(dead_temps, 0, s->nb_globals);
1090641d5fbeSbellard     ts = &s->temps[s->nb_globals];
1091641d5fbeSbellard     for(i = s->nb_globals; i < s->nb_temps; i++) {
1092641d5fbeSbellard         if (ts->temp_local)
1093641d5fbeSbellard             dead_temps[i] = 0;
1094641d5fbeSbellard         else
1095641d5fbeSbellard             dead_temps[i] = 1;
1096641d5fbeSbellard         ts++;
1097641d5fbeSbellard     }
1098641d5fbeSbellard }
1099641d5fbeSbellard 
1100c896fe29Sbellard /* Liveness analysis : update the opc_dead_iargs array to tell if a
1101c896fe29Sbellard    given input arguments is dead. Instructions updating dead
1102c896fe29Sbellard    temporaries are removed. */
11038fcd3692Sblueswir1 static void tcg_liveness_analysis(TCGContext *s)
1104c896fe29Sbellard {
1105c896fe29Sbellard     int i, op_index, op, nb_args, nb_iargs, nb_oargs, arg, nb_ops;
1106c896fe29Sbellard     TCGArg *args;
1107c896fe29Sbellard     const TCGOpDef *def;
1108c896fe29Sbellard     uint8_t *dead_temps;
1109c896fe29Sbellard     unsigned int dead_iargs;
1110c896fe29Sbellard 
1111c896fe29Sbellard     gen_opc_ptr++; /* skip end */
1112c896fe29Sbellard 
1113c896fe29Sbellard     nb_ops = gen_opc_ptr - gen_opc_buf;
1114c896fe29Sbellard 
1115c896fe29Sbellard     /* XXX: make it really dynamic */
1116c896fe29Sbellard     s->op_dead_iargs = tcg_malloc(OPC_BUF_SIZE * sizeof(uint16_t));
1117c896fe29Sbellard 
1118c896fe29Sbellard     dead_temps = tcg_malloc(s->nb_temps);
1119c896fe29Sbellard     memset(dead_temps, 1, s->nb_temps);
1120c896fe29Sbellard 
1121c896fe29Sbellard     args = gen_opparam_ptr;
1122c896fe29Sbellard     op_index = nb_ops - 1;
1123c896fe29Sbellard     while (op_index >= 0) {
1124c896fe29Sbellard         op = gen_opc_buf[op_index];
1125c896fe29Sbellard         def = &tcg_op_defs[op];
1126c896fe29Sbellard         switch(op) {
1127c896fe29Sbellard         case INDEX_op_call:
1128c6e113f5Sbellard             {
1129c6e113f5Sbellard                 int call_flags;
1130c6e113f5Sbellard 
1131c896fe29Sbellard                 nb_args = args[-1];
1132c896fe29Sbellard                 args -= nb_args;
1133c896fe29Sbellard                 nb_iargs = args[0] & 0xffff;
1134c896fe29Sbellard                 nb_oargs = args[0] >> 16;
1135c896fe29Sbellard                 args++;
1136c6e113f5Sbellard                 call_flags = args[nb_oargs + nb_iargs];
1137c6e113f5Sbellard 
1138c6e113f5Sbellard                 /* pure functions can be removed if their result is not
1139c6e113f5Sbellard                    used */
1140c6e113f5Sbellard                 if (call_flags & TCG_CALL_PURE) {
1141c6e113f5Sbellard                     for(i = 0; i < nb_oargs; i++) {
1142c6e113f5Sbellard                         arg = args[i];
1143c6e113f5Sbellard                         if (!dead_temps[arg])
1144c6e113f5Sbellard                             goto do_not_remove_call;
1145c6e113f5Sbellard                     }
1146c6e113f5Sbellard                     tcg_set_nop(s, gen_opc_buf + op_index,
1147c6e113f5Sbellard                                 args - 1, nb_args);
1148c6e113f5Sbellard                 } else {
1149c6e113f5Sbellard                 do_not_remove_call:
1150c896fe29Sbellard 
1151c896fe29Sbellard                     /* output args are dead */
1152c896fe29Sbellard                     for(i = 0; i < nb_oargs; i++) {
1153c896fe29Sbellard                         arg = args[i];
1154c896fe29Sbellard                         dead_temps[arg] = 1;
1155c896fe29Sbellard                     }
1156c896fe29Sbellard 
1157c896fe29Sbellard                     /* globals are live (they may be used by the call) */
1158c896fe29Sbellard                     memset(dead_temps, 0, s->nb_globals);
1159c896fe29Sbellard 
1160c896fe29Sbellard                     /* input args are live */
1161c896fe29Sbellard                     dead_iargs = 0;
1162c896fe29Sbellard                     for(i = 0; i < nb_iargs; i++) {
1163c896fe29Sbellard                         arg = args[i + nb_oargs];
116439cf05d3Sbellard                         if (arg != TCG_CALL_DUMMY_ARG) {
1165c896fe29Sbellard                             if (dead_temps[arg]) {
1166c896fe29Sbellard                                 dead_iargs |= (1 << i);
1167c896fe29Sbellard                             }
1168c896fe29Sbellard                             dead_temps[arg] = 0;
1169c896fe29Sbellard                         }
117039cf05d3Sbellard                     }
1171c896fe29Sbellard                     s->op_dead_iargs[op_index] = dead_iargs;
1172c6e113f5Sbellard                 }
1173c896fe29Sbellard                 args--;
1174c6e113f5Sbellard             }
1175c896fe29Sbellard             break;
1176c896fe29Sbellard         case INDEX_op_set_label:
1177c896fe29Sbellard             args--;
1178c896fe29Sbellard             /* mark end of basic block */
1179c896fe29Sbellard             tcg_la_bb_end(s, dead_temps);
1180c896fe29Sbellard             break;
11817e4597d7Sbellard         case INDEX_op_debug_insn_start:
11827e4597d7Sbellard             args -= def->nb_args;
11837e4597d7Sbellard             break;
1184c896fe29Sbellard         case INDEX_op_nopn:
1185c896fe29Sbellard             nb_args = args[-1];
1186c896fe29Sbellard             args -= nb_args;
1187c896fe29Sbellard             break;
11885ff9d6a4Sbellard         case INDEX_op_discard:
11895ff9d6a4Sbellard             args--;
11905ff9d6a4Sbellard             /* mark the temporary as dead */
11915ff9d6a4Sbellard             dead_temps[args[0]] = 1;
11925ff9d6a4Sbellard             break;
1193c896fe29Sbellard         case INDEX_op_end:
1194c896fe29Sbellard             break;
1195c896fe29Sbellard             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1196c896fe29Sbellard         default:
1197c896fe29Sbellard             if (op > INDEX_op_end) {
1198c896fe29Sbellard                 args -= def->nb_args;
1199c896fe29Sbellard                 nb_iargs = def->nb_iargs;
1200c896fe29Sbellard                 nb_oargs = def->nb_oargs;
1201c896fe29Sbellard 
1202c896fe29Sbellard                 /* Test if the operation can be removed because all
12035ff9d6a4Sbellard                    its outputs are dead. We assume that nb_oargs == 0
12045ff9d6a4Sbellard                    implies side effects */
12055ff9d6a4Sbellard                 if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
1206c896fe29Sbellard                     for(i = 0; i < nb_oargs; i++) {
1207c896fe29Sbellard                         arg = args[i];
1208c896fe29Sbellard                         if (!dead_temps[arg])
1209c896fe29Sbellard                             goto do_not_remove;
1210c896fe29Sbellard                     }
1211c896fe29Sbellard                     tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args);
1212c896fe29Sbellard #ifdef CONFIG_PROFILER
1213a23a9ec6Sbellard                     s->del_op_count++;
1214c896fe29Sbellard #endif
1215c896fe29Sbellard                 } else {
1216c896fe29Sbellard                 do_not_remove:
1217c896fe29Sbellard 
1218c896fe29Sbellard                     /* output args are dead */
1219c896fe29Sbellard                     for(i = 0; i < nb_oargs; i++) {
1220c896fe29Sbellard                         arg = args[i];
1221c896fe29Sbellard                         dead_temps[arg] = 1;
1222c896fe29Sbellard                     }
1223c896fe29Sbellard 
1224c896fe29Sbellard                     /* if end of basic block, update */
1225c896fe29Sbellard                     if (def->flags & TCG_OPF_BB_END) {
1226c896fe29Sbellard                         tcg_la_bb_end(s, dead_temps);
1227b03cce8eSbellard                     } else if (def->flags & TCG_OPF_CALL_CLOBBER) {
1228b03cce8eSbellard                         /* globals are live */
1229b03cce8eSbellard                         memset(dead_temps, 0, s->nb_globals);
1230c896fe29Sbellard                     }
1231c896fe29Sbellard 
1232c896fe29Sbellard                     /* input args are live */
1233c896fe29Sbellard                     dead_iargs = 0;
1234c896fe29Sbellard                     for(i = 0; i < nb_iargs; i++) {
1235c896fe29Sbellard                         arg = args[i + nb_oargs];
1236c896fe29Sbellard                         if (dead_temps[arg]) {
1237c896fe29Sbellard                             dead_iargs |= (1 << i);
1238c896fe29Sbellard                         }
1239c896fe29Sbellard                         dead_temps[arg] = 0;
1240c896fe29Sbellard                     }
1241c896fe29Sbellard                     s->op_dead_iargs[op_index] = dead_iargs;
1242c896fe29Sbellard                 }
1243c896fe29Sbellard             } else {
1244c896fe29Sbellard                 /* legacy dyngen operations */
1245c896fe29Sbellard                 args -= def->nb_args;
1246c896fe29Sbellard                 /* mark end of basic block */
1247c896fe29Sbellard                 tcg_la_bb_end(s, dead_temps);
1248c896fe29Sbellard             }
1249c896fe29Sbellard             break;
1250c896fe29Sbellard         }
1251c896fe29Sbellard         op_index--;
1252c896fe29Sbellard     }
1253c896fe29Sbellard 
1254c896fe29Sbellard     if (args != gen_opparam_buf)
1255c896fe29Sbellard         tcg_abort();
1256c896fe29Sbellard }
1257c896fe29Sbellard #else
1258c896fe29Sbellard /* dummy liveness analysis */
1259c896fe29Sbellard void tcg_liveness_analysis(TCGContext *s)
1260c896fe29Sbellard {
1261c896fe29Sbellard     int nb_ops;
1262c896fe29Sbellard     nb_ops = gen_opc_ptr - gen_opc_buf;
1263c896fe29Sbellard 
1264c896fe29Sbellard     s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
1265c896fe29Sbellard     memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t));
1266c896fe29Sbellard }
1267c896fe29Sbellard #endif
1268c896fe29Sbellard 
1269c896fe29Sbellard #ifndef NDEBUG
1270c896fe29Sbellard static void dump_regs(TCGContext *s)
1271c896fe29Sbellard {
1272c896fe29Sbellard     TCGTemp *ts;
1273c896fe29Sbellard     int i;
1274c896fe29Sbellard     char buf[64];
1275c896fe29Sbellard 
1276c896fe29Sbellard     for(i = 0; i < s->nb_temps; i++) {
1277c896fe29Sbellard         ts = &s->temps[i];
1278ac56dd48Spbrook         printf("  %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i));
1279c896fe29Sbellard         switch(ts->val_type) {
1280c896fe29Sbellard         case TEMP_VAL_REG:
1281c896fe29Sbellard             printf("%s", tcg_target_reg_names[ts->reg]);
1282c896fe29Sbellard             break;
1283c896fe29Sbellard         case TEMP_VAL_MEM:
1284c896fe29Sbellard             printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]);
1285c896fe29Sbellard             break;
1286c896fe29Sbellard         case TEMP_VAL_CONST:
1287c896fe29Sbellard             printf("$0x%" TCG_PRIlx, ts->val);
1288c896fe29Sbellard             break;
1289c896fe29Sbellard         case TEMP_VAL_DEAD:
1290c896fe29Sbellard             printf("D");
1291c896fe29Sbellard             break;
1292c896fe29Sbellard         default:
1293c896fe29Sbellard             printf("???");
1294c896fe29Sbellard             break;
1295c896fe29Sbellard         }
1296c896fe29Sbellard         printf("\n");
1297c896fe29Sbellard     }
1298c896fe29Sbellard 
1299c896fe29Sbellard     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
1300c896fe29Sbellard         if (s->reg_to_temp[i] >= 0) {
1301c896fe29Sbellard             printf("%s: %s\n",
1302c896fe29Sbellard                    tcg_target_reg_names[i],
1303ac56dd48Spbrook                    tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i]));
1304c896fe29Sbellard         }
1305c896fe29Sbellard     }
1306c896fe29Sbellard }
1307c896fe29Sbellard 
1308c896fe29Sbellard static void check_regs(TCGContext *s)
1309c896fe29Sbellard {
1310c896fe29Sbellard     int reg, k;
1311c896fe29Sbellard     TCGTemp *ts;
1312c896fe29Sbellard     char buf[64];
1313c896fe29Sbellard 
1314c896fe29Sbellard     for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1315c896fe29Sbellard         k = s->reg_to_temp[reg];
1316c896fe29Sbellard         if (k >= 0) {
1317c896fe29Sbellard             ts = &s->temps[k];
1318c896fe29Sbellard             if (ts->val_type != TEMP_VAL_REG ||
1319c896fe29Sbellard                 ts->reg != reg) {
1320c896fe29Sbellard                 printf("Inconsistency for register %s:\n",
1321c896fe29Sbellard                        tcg_target_reg_names[reg]);
1322b03cce8eSbellard                 goto fail;
1323c896fe29Sbellard             }
1324c896fe29Sbellard         }
1325c896fe29Sbellard     }
1326c896fe29Sbellard     for(k = 0; k < s->nb_temps; k++) {
1327c896fe29Sbellard         ts = &s->temps[k];
1328c896fe29Sbellard         if (ts->val_type == TEMP_VAL_REG &&
1329c896fe29Sbellard             !ts->fixed_reg &&
1330c896fe29Sbellard             s->reg_to_temp[ts->reg] != k) {
1331c896fe29Sbellard                 printf("Inconsistency for temp %s:\n",
1332ac56dd48Spbrook                        tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
1333b03cce8eSbellard         fail:
1334c896fe29Sbellard                 printf("reg state:\n");
1335c896fe29Sbellard                 dump_regs(s);
1336c896fe29Sbellard                 tcg_abort();
1337c896fe29Sbellard         }
1338c896fe29Sbellard     }
1339c896fe29Sbellard }
1340c896fe29Sbellard #endif
1341c896fe29Sbellard 
1342c896fe29Sbellard static void temp_allocate_frame(TCGContext *s, int temp)
1343c896fe29Sbellard {
1344c896fe29Sbellard     TCGTemp *ts;
1345c896fe29Sbellard     ts = &s->temps[temp];
1346c896fe29Sbellard     s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1);
1347c896fe29Sbellard     if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end)
13485ff9d6a4Sbellard         tcg_abort();
1349c896fe29Sbellard     ts->mem_offset = s->current_frame_offset;
1350c896fe29Sbellard     ts->mem_reg = s->frame_reg;
1351c896fe29Sbellard     ts->mem_allocated = 1;
1352c896fe29Sbellard     s->current_frame_offset += sizeof(tcg_target_long);
1353c896fe29Sbellard }
1354c896fe29Sbellard 
1355c896fe29Sbellard /* free register 'reg' by spilling the corresponding temporary if necessary */
1356c896fe29Sbellard static void tcg_reg_free(TCGContext *s, int reg)
1357c896fe29Sbellard {
1358c896fe29Sbellard     TCGTemp *ts;
1359c896fe29Sbellard     int temp;
1360c896fe29Sbellard 
1361c896fe29Sbellard     temp = s->reg_to_temp[reg];
1362c896fe29Sbellard     if (temp != -1) {
1363c896fe29Sbellard         ts = &s->temps[temp];
1364c896fe29Sbellard         assert(ts->val_type == TEMP_VAL_REG);
1365c896fe29Sbellard         if (!ts->mem_coherent) {
1366c896fe29Sbellard             if (!ts->mem_allocated)
1367c896fe29Sbellard                 temp_allocate_frame(s, temp);
1368e4d5434cSblueswir1             tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1369c896fe29Sbellard         }
1370c896fe29Sbellard         ts->val_type = TEMP_VAL_MEM;
1371c896fe29Sbellard         s->reg_to_temp[reg] = -1;
1372c896fe29Sbellard     }
1373c896fe29Sbellard }
1374c896fe29Sbellard 
1375c896fe29Sbellard /* Allocate a register belonging to reg1 & ~reg2 */
1376c896fe29Sbellard static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2)
1377c896fe29Sbellard {
1378c896fe29Sbellard     int i, reg;
1379c896fe29Sbellard     TCGRegSet reg_ct;
1380c896fe29Sbellard 
1381c896fe29Sbellard     tcg_regset_andnot(reg_ct, reg1, reg2);
1382c896fe29Sbellard 
1383c896fe29Sbellard     /* first try free registers */
13840954d0d9Sblueswir1     for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
1385c896fe29Sbellard         reg = tcg_target_reg_alloc_order[i];
1386c896fe29Sbellard         if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1)
1387c896fe29Sbellard             return reg;
1388c896fe29Sbellard     }
1389c896fe29Sbellard 
1390c896fe29Sbellard     /* XXX: do better spill choice */
13910954d0d9Sblueswir1     for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
1392c896fe29Sbellard         reg = tcg_target_reg_alloc_order[i];
1393c896fe29Sbellard         if (tcg_regset_test_reg(reg_ct, reg)) {
1394c896fe29Sbellard             tcg_reg_free(s, reg);
1395c896fe29Sbellard             return reg;
1396c896fe29Sbellard         }
1397c896fe29Sbellard     }
1398c896fe29Sbellard 
1399c896fe29Sbellard     tcg_abort();
1400c896fe29Sbellard }
1401c896fe29Sbellard 
1402641d5fbeSbellard /* save a temporary to memory. 'allocated_regs' is used in case a
1403e8996ee0Sbellard    temporary registers needs to be allocated to store a constant. */
1404641d5fbeSbellard static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs)
1405c896fe29Sbellard {
1406c896fe29Sbellard     TCGTemp *ts;
1407641d5fbeSbellard     int reg;
1408c896fe29Sbellard 
1409641d5fbeSbellard     ts = &s->temps[temp];
1410c896fe29Sbellard     if (!ts->fixed_reg) {
1411e8996ee0Sbellard         switch(ts->val_type) {
1412e8996ee0Sbellard         case TEMP_VAL_REG:
1413c896fe29Sbellard             tcg_reg_free(s, ts->reg);
1414e8996ee0Sbellard             break;
1415e8996ee0Sbellard         case TEMP_VAL_DEAD:
1416e5097dc8Sbellard             ts->val_type = TEMP_VAL_MEM;
1417e8996ee0Sbellard             break;
1418e8996ee0Sbellard         case TEMP_VAL_CONST:
1419e8996ee0Sbellard             reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1420e8996ee0Sbellard                                 allocated_regs);
1421641d5fbeSbellard             if (!ts->mem_allocated)
1422641d5fbeSbellard                 temp_allocate_frame(s, temp);
1423e8996ee0Sbellard             tcg_out_movi(s, ts->type, reg, ts->val);
1424e8996ee0Sbellard             tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1425e8996ee0Sbellard             ts->val_type = TEMP_VAL_MEM;
1426e8996ee0Sbellard             break;
1427e8996ee0Sbellard         case TEMP_VAL_MEM:
1428e8996ee0Sbellard             break;
1429e8996ee0Sbellard         default:
1430e8996ee0Sbellard             tcg_abort();
1431c896fe29Sbellard         }
1432c896fe29Sbellard     }
1433c896fe29Sbellard }
1434641d5fbeSbellard 
1435641d5fbeSbellard /* save globals to their cannonical location and assume they can be
1436641d5fbeSbellard    modified be the following code. 'allocated_regs' is used in case a
1437641d5fbeSbellard    temporary registers needs to be allocated to store a constant. */
1438641d5fbeSbellard static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
1439641d5fbeSbellard {
1440641d5fbeSbellard     int i;
1441641d5fbeSbellard 
1442641d5fbeSbellard     for(i = 0; i < s->nb_globals; i++) {
1443641d5fbeSbellard         temp_save(s, i, allocated_regs);
1444641d5fbeSbellard     }
1445e5097dc8Sbellard }
1446e5097dc8Sbellard 
1447e5097dc8Sbellard /* at the end of a basic block, we assume all temporaries are dead and
1448e8996ee0Sbellard    all globals are stored at their canonical location. */
1449e8996ee0Sbellard static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
1450e5097dc8Sbellard {
1451e5097dc8Sbellard     TCGTemp *ts;
1452e5097dc8Sbellard     int i;
1453e5097dc8Sbellard 
1454c896fe29Sbellard     for(i = s->nb_globals; i < s->nb_temps; i++) {
1455c896fe29Sbellard         ts = &s->temps[i];
1456641d5fbeSbellard         if (ts->temp_local) {
1457641d5fbeSbellard             temp_save(s, i, allocated_regs);
1458641d5fbeSbellard         } else {
1459c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
1460c896fe29Sbellard                 s->reg_to_temp[ts->reg] = -1;
1461c896fe29Sbellard             }
1462c896fe29Sbellard             ts->val_type = TEMP_VAL_DEAD;
1463c896fe29Sbellard         }
1464641d5fbeSbellard     }
1465e8996ee0Sbellard 
1466e8996ee0Sbellard     save_globals(s, allocated_regs);
1467c896fe29Sbellard }
1468c896fe29Sbellard 
1469c896fe29Sbellard #define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
1470c896fe29Sbellard 
1471e8996ee0Sbellard static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args)
1472e8996ee0Sbellard {
1473e8996ee0Sbellard     TCGTemp *ots;
1474e8996ee0Sbellard     tcg_target_ulong val;
1475e8996ee0Sbellard 
1476e8996ee0Sbellard     ots = &s->temps[args[0]];
1477e8996ee0Sbellard     val = args[1];
1478e8996ee0Sbellard 
1479e8996ee0Sbellard     if (ots->fixed_reg) {
1480e8996ee0Sbellard         /* for fixed registers, we do not do any constant
1481e8996ee0Sbellard            propagation */
1482e8996ee0Sbellard         tcg_out_movi(s, ots->type, ots->reg, val);
1483e8996ee0Sbellard     } else {
14841235fc06Sths         /* The movi is not explicitly generated here */
1485e8996ee0Sbellard         if (ots->val_type == TEMP_VAL_REG)
1486e8996ee0Sbellard             s->reg_to_temp[ots->reg] = -1;
1487e8996ee0Sbellard         ots->val_type = TEMP_VAL_CONST;
1488e8996ee0Sbellard         ots->val = val;
1489e8996ee0Sbellard     }
1490e8996ee0Sbellard }
1491e8996ee0Sbellard 
1492c896fe29Sbellard static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
1493c896fe29Sbellard                               const TCGArg *args,
1494c896fe29Sbellard                               unsigned int dead_iargs)
1495c896fe29Sbellard {
1496c896fe29Sbellard     TCGTemp *ts, *ots;
1497c896fe29Sbellard     int reg;
1498c896fe29Sbellard     const TCGArgConstraint *arg_ct;
1499c896fe29Sbellard 
1500c896fe29Sbellard     ots = &s->temps[args[0]];
1501c896fe29Sbellard     ts = &s->temps[args[1]];
1502c896fe29Sbellard     arg_ct = &def->args_ct[0];
1503c896fe29Sbellard 
1504e8996ee0Sbellard     /* XXX: always mark arg dead if IS_DEAD_IARG(0) */
1505c896fe29Sbellard     if (ts->val_type == TEMP_VAL_REG) {
1506c896fe29Sbellard         if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) {
1507c896fe29Sbellard             /* the mov can be suppressed */
1508c896fe29Sbellard             if (ots->val_type == TEMP_VAL_REG)
1509c896fe29Sbellard                 s->reg_to_temp[ots->reg] = -1;
1510c896fe29Sbellard             reg = ts->reg;
1511c896fe29Sbellard             s->reg_to_temp[reg] = -1;
1512c896fe29Sbellard             ts->val_type = TEMP_VAL_DEAD;
1513c896fe29Sbellard         } else {
1514c896fe29Sbellard             if (ots->val_type == TEMP_VAL_REG) {
1515c896fe29Sbellard                 reg = ots->reg;
1516c896fe29Sbellard             } else {
1517c896fe29Sbellard                 reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
1518c896fe29Sbellard             }
1519c896fe29Sbellard             if (ts->reg != reg) {
1520c896fe29Sbellard                 tcg_out_mov(s, reg, ts->reg);
1521c896fe29Sbellard             }
1522c896fe29Sbellard         }
1523c896fe29Sbellard     } else if (ts->val_type == TEMP_VAL_MEM) {
1524c896fe29Sbellard         if (ots->val_type == TEMP_VAL_REG) {
1525c896fe29Sbellard             reg = ots->reg;
1526c896fe29Sbellard         } else {
1527c896fe29Sbellard             reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
1528c896fe29Sbellard         }
1529e4d5434cSblueswir1         tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1530c896fe29Sbellard     } else if (ts->val_type == TEMP_VAL_CONST) {
1531e8996ee0Sbellard         if (ots->fixed_reg) {
1532c896fe29Sbellard             reg = ots->reg;
1533c896fe29Sbellard             tcg_out_movi(s, ots->type, reg, ts->val);
1534c896fe29Sbellard         } else {
1535e8996ee0Sbellard             /* propagate constant */
1536e8996ee0Sbellard             if (ots->val_type == TEMP_VAL_REG)
1537e8996ee0Sbellard                 s->reg_to_temp[ots->reg] = -1;
1538e8996ee0Sbellard             ots->val_type = TEMP_VAL_CONST;
1539e8996ee0Sbellard             ots->val = ts->val;
1540e8996ee0Sbellard             return;
1541e8996ee0Sbellard         }
1542e8996ee0Sbellard     } else {
1543c896fe29Sbellard         tcg_abort();
1544c896fe29Sbellard     }
1545c896fe29Sbellard     s->reg_to_temp[reg] = args[0];
1546c896fe29Sbellard     ots->reg = reg;
1547c896fe29Sbellard     ots->val_type = TEMP_VAL_REG;
1548c896fe29Sbellard     ots->mem_coherent = 0;
1549c896fe29Sbellard }
1550c896fe29Sbellard 
1551c896fe29Sbellard static void tcg_reg_alloc_op(TCGContext *s,
1552c896fe29Sbellard                              const TCGOpDef *def, int opc,
1553c896fe29Sbellard                              const TCGArg *args,
1554c896fe29Sbellard                              unsigned int dead_iargs)
1555c896fe29Sbellard {
1556c896fe29Sbellard     TCGRegSet allocated_regs;
1557c896fe29Sbellard     int i, k, nb_iargs, nb_oargs, reg;
1558c896fe29Sbellard     TCGArg arg;
1559c896fe29Sbellard     const TCGArgConstraint *arg_ct;
1560c896fe29Sbellard     TCGTemp *ts;
1561c896fe29Sbellard     TCGArg new_args[TCG_MAX_OP_ARGS];
1562c896fe29Sbellard     int const_args[TCG_MAX_OP_ARGS];
1563c896fe29Sbellard 
1564c896fe29Sbellard     nb_oargs = def->nb_oargs;
1565c896fe29Sbellard     nb_iargs = def->nb_iargs;
1566c896fe29Sbellard 
1567c896fe29Sbellard     /* copy constants */
1568c896fe29Sbellard     memcpy(new_args + nb_oargs + nb_iargs,
1569c896fe29Sbellard            args + nb_oargs + nb_iargs,
1570c896fe29Sbellard            sizeof(TCGArg) * def->nb_cargs);
1571c896fe29Sbellard 
1572c896fe29Sbellard     /* satisfy input constraints */
1573c896fe29Sbellard     tcg_regset_set(allocated_regs, s->reserved_regs);
1574c896fe29Sbellard     for(k = 0; k < nb_iargs; k++) {
1575c896fe29Sbellard         i = def->sorted_args[nb_oargs + k];
1576c896fe29Sbellard         arg = args[i];
1577c896fe29Sbellard         arg_ct = &def->args_ct[i];
1578c896fe29Sbellard         ts = &s->temps[arg];
1579c896fe29Sbellard         if (ts->val_type == TEMP_VAL_MEM) {
1580c896fe29Sbellard             reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1581e4d5434cSblueswir1             tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1582c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
1583c896fe29Sbellard             ts->reg = reg;
1584c896fe29Sbellard             ts->mem_coherent = 1;
1585c896fe29Sbellard             s->reg_to_temp[reg] = arg;
1586c896fe29Sbellard         } else if (ts->val_type == TEMP_VAL_CONST) {
1587c896fe29Sbellard             if (tcg_target_const_match(ts->val, arg_ct)) {
1588c896fe29Sbellard                 /* constant is OK for instruction */
1589c896fe29Sbellard                 const_args[i] = 1;
1590c896fe29Sbellard                 new_args[i] = ts->val;
1591c896fe29Sbellard                 goto iarg_end;
1592c896fe29Sbellard             } else {
1593c896fe29Sbellard                 /* need to move to a register */
1594c896fe29Sbellard                 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1595c896fe29Sbellard                 tcg_out_movi(s, ts->type, reg, ts->val);
1596e8996ee0Sbellard                 ts->val_type = TEMP_VAL_REG;
1597e8996ee0Sbellard                 ts->reg = reg;
1598e8996ee0Sbellard                 ts->mem_coherent = 0;
1599e8996ee0Sbellard                 s->reg_to_temp[reg] = arg;
1600c896fe29Sbellard             }
1601c896fe29Sbellard         }
1602c896fe29Sbellard         assert(ts->val_type == TEMP_VAL_REG);
16035ff9d6a4Sbellard         if (arg_ct->ct & TCG_CT_IALIAS) {
16045ff9d6a4Sbellard             if (ts->fixed_reg) {
16055ff9d6a4Sbellard                 /* if fixed register, we must allocate a new register
16065ff9d6a4Sbellard                    if the alias is not the same register */
16075ff9d6a4Sbellard                 if (arg != args[arg_ct->alias_index])
16085ff9d6a4Sbellard                     goto allocate_in_reg;
16095ff9d6a4Sbellard             } else {
1610c896fe29Sbellard                 /* if the input is aliased to an output and if it is
1611c896fe29Sbellard                    not dead after the instruction, we must allocate
1612c896fe29Sbellard                    a new register and move it */
16135ff9d6a4Sbellard                 if (!IS_DEAD_IARG(i - nb_oargs))
1614c896fe29Sbellard                     goto allocate_in_reg;
1615c896fe29Sbellard             }
16165ff9d6a4Sbellard         }
1617c896fe29Sbellard         reg = ts->reg;
1618c896fe29Sbellard         if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1619c896fe29Sbellard             /* nothing to do : the constraint is satisfied */
1620c896fe29Sbellard         } else {
1621c896fe29Sbellard         allocate_in_reg:
1622c896fe29Sbellard             /* allocate a new register matching the constraint
1623c896fe29Sbellard                and move the temporary register into it */
1624c896fe29Sbellard             reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1625c896fe29Sbellard             tcg_out_mov(s, reg, ts->reg);
1626c896fe29Sbellard         }
1627c896fe29Sbellard         new_args[i] = reg;
1628c896fe29Sbellard         const_args[i] = 0;
1629c896fe29Sbellard         tcg_regset_set_reg(allocated_regs, reg);
1630c896fe29Sbellard     iarg_end: ;
1631c896fe29Sbellard     }
1632c896fe29Sbellard 
1633e8996ee0Sbellard     if (def->flags & TCG_OPF_BB_END) {
1634e8996ee0Sbellard         tcg_reg_alloc_bb_end(s, allocated_regs);
1635e8996ee0Sbellard     } else {
1636c896fe29Sbellard         /* mark dead temporaries and free the associated registers */
1637c896fe29Sbellard         for(i = 0; i < nb_iargs; i++) {
1638c896fe29Sbellard             arg = args[nb_oargs + i];
1639c896fe29Sbellard             if (IS_DEAD_IARG(i)) {
1640c896fe29Sbellard                 ts = &s->temps[arg];
1641e8996ee0Sbellard                 if (!ts->fixed_reg) {
1642c896fe29Sbellard                     if (ts->val_type == TEMP_VAL_REG)
1643c896fe29Sbellard                         s->reg_to_temp[ts->reg] = -1;
1644c896fe29Sbellard                     ts->val_type = TEMP_VAL_DEAD;
1645c896fe29Sbellard                 }
1646c896fe29Sbellard             }
1647c896fe29Sbellard         }
1648c896fe29Sbellard 
1649c896fe29Sbellard         if (def->flags & TCG_OPF_CALL_CLOBBER) {
1650b03cce8eSbellard             /* XXX: permit generic clobber register list ? */
1651c896fe29Sbellard             for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1652c896fe29Sbellard                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
1653c896fe29Sbellard                     tcg_reg_free(s, reg);
1654c896fe29Sbellard                 }
1655c896fe29Sbellard             }
1656b03cce8eSbellard             /* XXX: for load/store we could do that only for the slow path
1657b03cce8eSbellard                (i.e. when a memory callback is called) */
1658b03cce8eSbellard 
1659b03cce8eSbellard             /* store globals and free associated registers (we assume the insn
1660b03cce8eSbellard                can modify any global. */
1661e8996ee0Sbellard             save_globals(s, allocated_regs);
1662c896fe29Sbellard         }
1663c896fe29Sbellard 
1664c896fe29Sbellard         /* satisfy the output constraints */
1665c896fe29Sbellard         tcg_regset_set(allocated_regs, s->reserved_regs);
1666c896fe29Sbellard         for(k = 0; k < nb_oargs; k++) {
1667c896fe29Sbellard             i = def->sorted_args[k];
1668c896fe29Sbellard             arg = args[i];
1669c896fe29Sbellard             arg_ct = &def->args_ct[i];
1670c896fe29Sbellard             ts = &s->temps[arg];
1671c896fe29Sbellard             if (arg_ct->ct & TCG_CT_ALIAS) {
16725ff9d6a4Sbellard                 reg = new_args[arg_ct->alias_index];
1673c896fe29Sbellard             } else {
1674c896fe29Sbellard                 /* if fixed register, we try to use it */
1675c896fe29Sbellard                 reg = ts->reg;
1676c896fe29Sbellard                 if (ts->fixed_reg &&
1677c896fe29Sbellard                     tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1678c896fe29Sbellard                     goto oarg_end;
1679c896fe29Sbellard                 }
1680c896fe29Sbellard                 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1681c896fe29Sbellard             }
1682c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
1683c896fe29Sbellard             /* if a fixed register is used, then a move will be done afterwards */
1684c896fe29Sbellard             if (!ts->fixed_reg) {
1685c896fe29Sbellard                 if (ts->val_type == TEMP_VAL_REG)
1686c896fe29Sbellard                     s->reg_to_temp[ts->reg] = -1;
1687c896fe29Sbellard                 ts->val_type = TEMP_VAL_REG;
1688c896fe29Sbellard                 ts->reg = reg;
1689c896fe29Sbellard                 /* temp value is modified, so the value kept in memory is
1690c896fe29Sbellard                    potentially not the same */
1691c896fe29Sbellard                 ts->mem_coherent = 0;
1692c896fe29Sbellard                 s->reg_to_temp[reg] = arg;
1693c896fe29Sbellard             }
1694c896fe29Sbellard         oarg_end:
1695c896fe29Sbellard             new_args[i] = reg;
1696c896fe29Sbellard         }
1697e8996ee0Sbellard     }
1698c896fe29Sbellard 
1699c896fe29Sbellard     /* emit instruction */
1700c896fe29Sbellard     tcg_out_op(s, opc, new_args, const_args);
1701c896fe29Sbellard 
1702c896fe29Sbellard     /* move the outputs in the correct register if needed */
1703c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
1704c896fe29Sbellard         ts = &s->temps[args[i]];
1705c896fe29Sbellard         reg = new_args[i];
1706c896fe29Sbellard         if (ts->fixed_reg && ts->reg != reg) {
1707c896fe29Sbellard             tcg_out_mov(s, ts->reg, reg);
1708c896fe29Sbellard         }
1709c896fe29Sbellard     }
1710c896fe29Sbellard }
1711c896fe29Sbellard 
1712b03cce8eSbellard #ifdef TCG_TARGET_STACK_GROWSUP
1713b03cce8eSbellard #define STACK_DIR(x) (-(x))
1714b03cce8eSbellard #else
1715b03cce8eSbellard #define STACK_DIR(x) (x)
1716b03cce8eSbellard #endif
1717b03cce8eSbellard 
1718c896fe29Sbellard static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
1719c896fe29Sbellard                               int opc, const TCGArg *args,
1720c896fe29Sbellard                               unsigned int dead_iargs)
1721c896fe29Sbellard {
1722c896fe29Sbellard     int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params;
1723c896fe29Sbellard     TCGArg arg, func_arg;
1724c896fe29Sbellard     TCGTemp *ts;
1725f54b3f92Saurel32     tcg_target_long stack_offset, call_stack_size, func_addr;
1726b03cce8eSbellard     int const_func_arg, allocate_args;
1727c896fe29Sbellard     TCGRegSet allocated_regs;
1728c896fe29Sbellard     const TCGArgConstraint *arg_ct;
1729c896fe29Sbellard 
1730c896fe29Sbellard     arg = *args++;
1731c896fe29Sbellard 
1732c896fe29Sbellard     nb_oargs = arg >> 16;
1733c896fe29Sbellard     nb_iargs = arg & 0xffff;
1734c896fe29Sbellard     nb_params = nb_iargs - 1;
1735c896fe29Sbellard 
1736c896fe29Sbellard     flags = args[nb_oargs + nb_iargs];
1737c896fe29Sbellard 
1738c896fe29Sbellard     nb_regs = tcg_target_get_call_iarg_regs_count(flags);
1739c896fe29Sbellard     if (nb_regs > nb_params)
1740c896fe29Sbellard         nb_regs = nb_params;
1741c896fe29Sbellard 
1742c896fe29Sbellard     /* assign stack slots first */
1743c896fe29Sbellard     /* XXX: preallocate call stack */
1744c896fe29Sbellard     call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);
1745c896fe29Sbellard     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
1746c896fe29Sbellard         ~(TCG_TARGET_STACK_ALIGN - 1);
1747b03cce8eSbellard     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
1748b03cce8eSbellard     if (allocate_args) {
1749b03cce8eSbellard         tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size));
1750b03cce8eSbellard     }
175139cf05d3Sbellard 
175239cf05d3Sbellard     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
1753c896fe29Sbellard     for(i = nb_regs; i < nb_params; i++) {
1754c896fe29Sbellard         arg = args[nb_oargs + i];
175539cf05d3Sbellard #ifdef TCG_TARGET_STACK_GROWSUP
175639cf05d3Sbellard         stack_offset -= sizeof(tcg_target_long);
175739cf05d3Sbellard #endif
175839cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
1759c896fe29Sbellard             ts = &s->temps[arg];
1760c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
1761e4d5434cSblueswir1                 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
1762c896fe29Sbellard             } else if (ts->val_type == TEMP_VAL_MEM) {
1763c896fe29Sbellard                 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1764c896fe29Sbellard                                     s->reserved_regs);
1765c896fe29Sbellard                 /* XXX: not correct if reading values from the stack */
1766e4d5434cSblueswir1                 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1767e4d5434cSblueswir1                 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
1768c896fe29Sbellard             } else if (ts->val_type == TEMP_VAL_CONST) {
1769c896fe29Sbellard                 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1770c896fe29Sbellard                                     s->reserved_regs);
1771c896fe29Sbellard                 /* XXX: sign extend may be needed on some targets */
1772c896fe29Sbellard                 tcg_out_movi(s, ts->type, reg, ts->val);
1773e4d5434cSblueswir1                 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
1774c896fe29Sbellard             } else {
1775c896fe29Sbellard                 tcg_abort();
1776c896fe29Sbellard             }
177739cf05d3Sbellard         }
177839cf05d3Sbellard #ifndef TCG_TARGET_STACK_GROWSUP
177939cf05d3Sbellard         stack_offset += sizeof(tcg_target_long);
178039cf05d3Sbellard #endif
1781c896fe29Sbellard     }
1782c896fe29Sbellard 
1783c896fe29Sbellard     /* assign input registers */
1784c896fe29Sbellard     tcg_regset_set(allocated_regs, s->reserved_regs);
1785c896fe29Sbellard     for(i = 0; i < nb_regs; i++) {
1786c896fe29Sbellard         arg = args[nb_oargs + i];
178739cf05d3Sbellard         if (arg != TCG_CALL_DUMMY_ARG) {
1788c896fe29Sbellard             ts = &s->temps[arg];
1789c896fe29Sbellard             reg = tcg_target_call_iarg_regs[i];
1790c896fe29Sbellard             tcg_reg_free(s, reg);
1791c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG) {
1792c896fe29Sbellard                 if (ts->reg != reg) {
1793c896fe29Sbellard                     tcg_out_mov(s, reg, ts->reg);
1794c896fe29Sbellard                 }
1795c896fe29Sbellard             } else if (ts->val_type == TEMP_VAL_MEM) {
1796e4d5434cSblueswir1                 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1797c896fe29Sbellard             } else if (ts->val_type == TEMP_VAL_CONST) {
1798c896fe29Sbellard                 /* XXX: sign extend ? */
1799c896fe29Sbellard                 tcg_out_movi(s, ts->type, reg, ts->val);
1800c896fe29Sbellard             } else {
1801c896fe29Sbellard                 tcg_abort();
1802c896fe29Sbellard             }
1803c896fe29Sbellard             tcg_regset_set_reg(allocated_regs, reg);
1804c896fe29Sbellard         }
180539cf05d3Sbellard     }
1806c896fe29Sbellard 
1807c896fe29Sbellard     /* assign function address */
1808c896fe29Sbellard     func_arg = args[nb_oargs + nb_iargs - 1];
1809c896fe29Sbellard     arg_ct = &def->args_ct[0];
1810c896fe29Sbellard     ts = &s->temps[func_arg];
1811f54b3f92Saurel32     func_addr = ts->val;
1812c896fe29Sbellard     const_func_arg = 0;
1813c896fe29Sbellard     if (ts->val_type == TEMP_VAL_MEM) {
1814c896fe29Sbellard         reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1815e4d5434cSblueswir1         tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1816c896fe29Sbellard         func_arg = reg;
1817e8996ee0Sbellard         tcg_regset_set_reg(allocated_regs, reg);
1818c896fe29Sbellard     } else if (ts->val_type == TEMP_VAL_REG) {
1819c896fe29Sbellard         reg = ts->reg;
1820c896fe29Sbellard         if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1821c896fe29Sbellard             reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1822c896fe29Sbellard             tcg_out_mov(s, reg, ts->reg);
1823c896fe29Sbellard         }
1824c896fe29Sbellard         func_arg = reg;
1825e8996ee0Sbellard         tcg_regset_set_reg(allocated_regs, reg);
1826c896fe29Sbellard     } else if (ts->val_type == TEMP_VAL_CONST) {
1827f54b3f92Saurel32         if (tcg_target_const_match(func_addr, arg_ct)) {
1828c896fe29Sbellard             const_func_arg = 1;
1829f54b3f92Saurel32             func_arg = func_addr;
1830c896fe29Sbellard         } else {
1831c896fe29Sbellard             reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1832f54b3f92Saurel32             tcg_out_movi(s, ts->type, reg, func_addr);
1833c896fe29Sbellard             func_arg = reg;
1834e8996ee0Sbellard             tcg_regset_set_reg(allocated_regs, reg);
1835c896fe29Sbellard         }
1836c896fe29Sbellard     } else {
1837c896fe29Sbellard         tcg_abort();
1838c896fe29Sbellard     }
1839c896fe29Sbellard 
1840e8996ee0Sbellard 
1841c896fe29Sbellard     /* mark dead temporaries and free the associated registers */
1842c6e113f5Sbellard     for(i = 0; i < nb_iargs; i++) {
1843c896fe29Sbellard         arg = args[nb_oargs + i];
1844c896fe29Sbellard         if (IS_DEAD_IARG(i)) {
1845c896fe29Sbellard             ts = &s->temps[arg];
1846e8996ee0Sbellard             if (!ts->fixed_reg) {
1847c896fe29Sbellard                 if (ts->val_type == TEMP_VAL_REG)
1848c896fe29Sbellard                     s->reg_to_temp[ts->reg] = -1;
1849c896fe29Sbellard                 ts->val_type = TEMP_VAL_DEAD;
1850c896fe29Sbellard             }
1851c896fe29Sbellard         }
1852c896fe29Sbellard     }
1853c896fe29Sbellard 
1854c896fe29Sbellard     /* clobber call registers */
1855c896fe29Sbellard     for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1856c896fe29Sbellard         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
1857c896fe29Sbellard             tcg_reg_free(s, reg);
1858c896fe29Sbellard         }
1859c896fe29Sbellard     }
1860c896fe29Sbellard 
1861c896fe29Sbellard     /* store globals and free associated registers (we assume the call
1862c896fe29Sbellard        can modify any global. */
1863e8996ee0Sbellard     save_globals(s, allocated_regs);
1864c896fe29Sbellard 
1865c896fe29Sbellard     tcg_out_op(s, opc, &func_arg, &const_func_arg);
1866c896fe29Sbellard 
1867b03cce8eSbellard     if (allocate_args) {
1868b03cce8eSbellard         tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size));
1869b03cce8eSbellard     }
1870c896fe29Sbellard 
1871c896fe29Sbellard     /* assign output registers and emit moves if needed */
1872c896fe29Sbellard     for(i = 0; i < nb_oargs; i++) {
1873c896fe29Sbellard         arg = args[i];
1874c896fe29Sbellard         ts = &s->temps[arg];
1875c896fe29Sbellard         reg = tcg_target_call_oarg_regs[i];
1876e8996ee0Sbellard         assert(s->reg_to_temp[reg] == -1);
1877c896fe29Sbellard         if (ts->fixed_reg) {
1878c896fe29Sbellard             if (ts->reg != reg) {
1879c896fe29Sbellard                 tcg_out_mov(s, ts->reg, reg);
1880c896fe29Sbellard             }
1881c896fe29Sbellard         } else {
1882c896fe29Sbellard             if (ts->val_type == TEMP_VAL_REG)
1883c896fe29Sbellard                 s->reg_to_temp[ts->reg] = -1;
1884c896fe29Sbellard             ts->val_type = TEMP_VAL_REG;
1885c896fe29Sbellard             ts->reg = reg;
1886c896fe29Sbellard             ts->mem_coherent = 0;
1887c896fe29Sbellard             s->reg_to_temp[reg] = arg;
1888c896fe29Sbellard         }
1889c896fe29Sbellard     }
1890c896fe29Sbellard 
1891c896fe29Sbellard     return nb_iargs + nb_oargs + def->nb_cargs + 1;
1892c896fe29Sbellard }
1893c896fe29Sbellard 
1894c896fe29Sbellard #ifdef CONFIG_PROFILER
1895c896fe29Sbellard 
1896c896fe29Sbellard static int64_t dyngen_table_op_count[NB_OPS];
1897c896fe29Sbellard 
1898c896fe29Sbellard void dump_op_count(void)
1899c896fe29Sbellard {
1900c896fe29Sbellard     int i;
1901c896fe29Sbellard     FILE *f;
1902c896fe29Sbellard     f = fopen("/tmp/op1.log", "w");
1903c896fe29Sbellard     for(i = 0; i < INDEX_op_end; i++) {
1904c896fe29Sbellard         fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, dyngen_table_op_count[i]);
1905c896fe29Sbellard     }
1906c896fe29Sbellard     fclose(f);
1907c896fe29Sbellard     f = fopen("/tmp/op2.log", "w");
1908c896fe29Sbellard     for(i = INDEX_op_end; i < NB_OPS; i++) {
1909c896fe29Sbellard         fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, dyngen_table_op_count[i]);
1910c896fe29Sbellard     }
1911c896fe29Sbellard     fclose(f);
1912c896fe29Sbellard }
1913c896fe29Sbellard #endif
1914c896fe29Sbellard 
1915c896fe29Sbellard 
1916c896fe29Sbellard static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
19172ba1eeb6Spbrook                                       long search_pc)
1918c896fe29Sbellard {
1919b314f270Sbellard     int opc, op_index;
1920c896fe29Sbellard     const TCGOpDef *def;
1921c896fe29Sbellard     unsigned int dead_iargs;
1922c896fe29Sbellard     const TCGArg *args;
1923c896fe29Sbellard 
1924c896fe29Sbellard #ifdef DEBUG_DISAS
1925c896fe29Sbellard     if (unlikely(loglevel & CPU_LOG_TB_OP)) {
1926c896fe29Sbellard         fprintf(logfile, "OP:\n");
1927c896fe29Sbellard         tcg_dump_ops(s, logfile);
1928c896fe29Sbellard         fprintf(logfile, "\n");
1929c896fe29Sbellard     }
1930c896fe29Sbellard #endif
1931c896fe29Sbellard 
1932a23a9ec6Sbellard #ifdef CONFIG_PROFILER
1933a23a9ec6Sbellard     s->la_time -= profile_getclock();
1934a23a9ec6Sbellard #endif
1935c896fe29Sbellard     tcg_liveness_analysis(s);
1936a23a9ec6Sbellard #ifdef CONFIG_PROFILER
1937a23a9ec6Sbellard     s->la_time += profile_getclock();
1938a23a9ec6Sbellard #endif
1939c896fe29Sbellard 
1940c896fe29Sbellard #ifdef DEBUG_DISAS
1941c896fe29Sbellard     if (unlikely(loglevel & CPU_LOG_TB_OP_OPT)) {
1942c896fe29Sbellard         fprintf(logfile, "OP after la:\n");
1943c896fe29Sbellard         tcg_dump_ops(s, logfile);
1944c896fe29Sbellard         fprintf(logfile, "\n");
1945c896fe29Sbellard     }
1946c896fe29Sbellard #endif
1947c896fe29Sbellard 
1948c896fe29Sbellard     tcg_reg_alloc_start(s);
1949c896fe29Sbellard 
1950c896fe29Sbellard     s->code_buf = gen_code_buf;
1951c896fe29Sbellard     s->code_ptr = gen_code_buf;
1952c896fe29Sbellard 
1953c896fe29Sbellard     args = gen_opparam_buf;
1954c896fe29Sbellard     op_index = 0;
1955b3db8758Sblueswir1 
1956c896fe29Sbellard     for(;;) {
1957c896fe29Sbellard         opc = gen_opc_buf[op_index];
1958c896fe29Sbellard #ifdef CONFIG_PROFILER
1959c896fe29Sbellard         dyngen_table_op_count[opc]++;
1960c896fe29Sbellard #endif
1961c896fe29Sbellard         def = &tcg_op_defs[opc];
1962c896fe29Sbellard #if 0
1963c896fe29Sbellard         printf("%s: %d %d %d\n", def->name,
1964c896fe29Sbellard                def->nb_oargs, def->nb_iargs, def->nb_cargs);
1965c896fe29Sbellard         //        dump_regs(s);
1966c896fe29Sbellard #endif
1967c896fe29Sbellard         switch(opc) {
1968c896fe29Sbellard         case INDEX_op_mov_i32:
1969c896fe29Sbellard #if TCG_TARGET_REG_BITS == 64
1970c896fe29Sbellard         case INDEX_op_mov_i64:
1971c896fe29Sbellard #endif
1972c896fe29Sbellard             dead_iargs = s->op_dead_iargs[op_index];
1973c896fe29Sbellard             tcg_reg_alloc_mov(s, def, args, dead_iargs);
1974c896fe29Sbellard             break;
1975e8996ee0Sbellard         case INDEX_op_movi_i32:
1976e8996ee0Sbellard #if TCG_TARGET_REG_BITS == 64
1977e8996ee0Sbellard         case INDEX_op_movi_i64:
1978e8996ee0Sbellard #endif
1979e8996ee0Sbellard             tcg_reg_alloc_movi(s, args);
1980e8996ee0Sbellard             break;
19817e4597d7Sbellard         case INDEX_op_debug_insn_start:
19827e4597d7Sbellard             /* debug instruction */
19837e4597d7Sbellard             break;
1984c896fe29Sbellard         case INDEX_op_nop:
1985c896fe29Sbellard         case INDEX_op_nop1:
1986c896fe29Sbellard         case INDEX_op_nop2:
1987c896fe29Sbellard         case INDEX_op_nop3:
1988c896fe29Sbellard             break;
1989c896fe29Sbellard         case INDEX_op_nopn:
1990c896fe29Sbellard             args += args[0];
1991c896fe29Sbellard             goto next;
19925ff9d6a4Sbellard         case INDEX_op_discard:
19935ff9d6a4Sbellard             {
19945ff9d6a4Sbellard                 TCGTemp *ts;
19955ff9d6a4Sbellard                 ts = &s->temps[args[0]];
19965ff9d6a4Sbellard                 /* mark the temporary as dead */
1997e8996ee0Sbellard                 if (!ts->fixed_reg) {
19985ff9d6a4Sbellard                     if (ts->val_type == TEMP_VAL_REG)
19995ff9d6a4Sbellard                         s->reg_to_temp[ts->reg] = -1;
20005ff9d6a4Sbellard                     ts->val_type = TEMP_VAL_DEAD;
20015ff9d6a4Sbellard                 }
20025ff9d6a4Sbellard             }
20035ff9d6a4Sbellard             break;
2004c896fe29Sbellard         case INDEX_op_set_label:
2005e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
2006c896fe29Sbellard             tcg_out_label(s, args[0], (long)s->code_ptr);
2007c896fe29Sbellard             break;
2008c896fe29Sbellard         case INDEX_op_call:
2009c896fe29Sbellard             dead_iargs = s->op_dead_iargs[op_index];
2010c896fe29Sbellard             args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs);
2011c896fe29Sbellard             goto next;
2012c896fe29Sbellard         case INDEX_op_end:
2013c896fe29Sbellard             goto the_end;
2014cf2be984Sblueswir1 
2015bf6247fbSblueswir1 #ifdef CONFIG_DYNGEN_OP
2016c896fe29Sbellard         case 0 ... INDEX_op_end - 1:
2017c896fe29Sbellard             /* legacy dyngen ops */
2018c896fe29Sbellard #ifdef CONFIG_PROFILER
2019a23a9ec6Sbellard             s->old_op_count++;
2020c896fe29Sbellard #endif
2021e8996ee0Sbellard             tcg_reg_alloc_bb_end(s, s->reserved_regs);
20222ba1eeb6Spbrook             if (search_pc >= 0) {
2023c896fe29Sbellard                 s->code_ptr += def->copy_size;
2024c896fe29Sbellard                 args += def->nb_args;
2025c896fe29Sbellard             } else {
2026c896fe29Sbellard                 args = dyngen_op(s, opc, args);
2027c896fe29Sbellard             }
2028c896fe29Sbellard             goto next;
2029cf2be984Sblueswir1 #endif
2030c896fe29Sbellard         default:
2031c896fe29Sbellard             /* Note: in order to speed up the code, it would be much
2032c896fe29Sbellard                faster to have specialized register allocator functions for
2033c896fe29Sbellard                some common argument patterns */
2034c896fe29Sbellard             dead_iargs = s->op_dead_iargs[op_index];
2035c896fe29Sbellard             tcg_reg_alloc_op(s, def, opc, args, dead_iargs);
2036c896fe29Sbellard             break;
2037c896fe29Sbellard         }
2038c896fe29Sbellard         args += def->nb_args;
20398df1ca4bSths     next:
20402ba1eeb6Spbrook         if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) {
2041c896fe29Sbellard             return op_index;
2042c896fe29Sbellard         }
2043c896fe29Sbellard         op_index++;
2044c896fe29Sbellard #ifndef NDEBUG
2045c896fe29Sbellard         check_regs(s);
2046c896fe29Sbellard #endif
2047c896fe29Sbellard     }
2048c896fe29Sbellard  the_end:
2049c896fe29Sbellard     return -1;
2050c896fe29Sbellard }
2051c896fe29Sbellard 
2052c896fe29Sbellard int dyngen_code(TCGContext *s, uint8_t *gen_code_buf)
2053c896fe29Sbellard {
2054c896fe29Sbellard #ifdef CONFIG_PROFILER
2055c896fe29Sbellard     {
2056c896fe29Sbellard         int n;
2057c896fe29Sbellard         n = (gen_opc_ptr - gen_opc_buf);
2058a23a9ec6Sbellard         s->op_count += n;
2059a23a9ec6Sbellard         if (n > s->op_count_max)
2060a23a9ec6Sbellard             s->op_count_max = n;
2061a23a9ec6Sbellard 
2062a23a9ec6Sbellard         s->temp_count += s->nb_temps;
2063a23a9ec6Sbellard         if (s->nb_temps > s->temp_count_max)
2064a23a9ec6Sbellard             s->temp_count_max = s->nb_temps;
2065c896fe29Sbellard     }
2066c896fe29Sbellard #endif
2067c896fe29Sbellard 
20682ba1eeb6Spbrook     tcg_gen_code_common(s, gen_code_buf, -1);
2069c896fe29Sbellard 
2070c896fe29Sbellard     /* flush instruction cache */
2071c896fe29Sbellard     flush_icache_range((unsigned long)gen_code_buf,
2072c896fe29Sbellard                        (unsigned long)s->code_ptr);
2073c896fe29Sbellard     return s->code_ptr -  gen_code_buf;
2074c896fe29Sbellard }
2075c896fe29Sbellard 
20762ba1eeb6Spbrook /* Return the index of the micro operation such as the pc after is <
2077623e265cSpbrook    offset bytes from the start of the TB.  The contents of gen_code_buf must
2078623e265cSpbrook    not be changed, though writing the same values is ok.
2079623e265cSpbrook    Return -1 if not found. */
2080623e265cSpbrook int dyngen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset)
2081c896fe29Sbellard {
2082623e265cSpbrook     return tcg_gen_code_common(s, gen_code_buf, offset);
2083c896fe29Sbellard }
2084a23a9ec6Sbellard 
2085a23a9ec6Sbellard #ifdef CONFIG_PROFILER
2086a23a9ec6Sbellard void tcg_dump_info(FILE *f,
2087a23a9ec6Sbellard                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2088a23a9ec6Sbellard {
2089a23a9ec6Sbellard     TCGContext *s = &tcg_ctx;
2090a23a9ec6Sbellard     int64_t tot;
2091a23a9ec6Sbellard 
2092a23a9ec6Sbellard     tot = s->interm_time + s->code_time;
2093a23a9ec6Sbellard     cpu_fprintf(f, "JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
2094a23a9ec6Sbellard                 tot, tot / 2.4e9);
2095a23a9ec6Sbellard     cpu_fprintf(f, "translated TBs      %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n",
2096a23a9ec6Sbellard                 s->tb_count,
2097a23a9ec6Sbellard                 s->tb_count1 - s->tb_count,
2098a23a9ec6Sbellard                 s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0);
2099a23a9ec6Sbellard     cpu_fprintf(f, "avg ops/TB          %0.1f max=%d\n",
2100a23a9ec6Sbellard                 s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max);
2101a23a9ec6Sbellard     cpu_fprintf(f, "old ops/total ops   %0.1f%%\n",
2102a23a9ec6Sbellard                 s->op_count ? (double)s->old_op_count / s->op_count * 100.0 : 0);
2103a23a9ec6Sbellard     cpu_fprintf(f, "deleted ops/TB      %0.2f\n",
2104a23a9ec6Sbellard                 s->tb_count ?
2105a23a9ec6Sbellard                 (double)s->del_op_count / s->tb_count : 0);
2106a23a9ec6Sbellard     cpu_fprintf(f, "avg temps/TB        %0.2f max=%d\n",
2107a23a9ec6Sbellard                 s->tb_count ?
2108a23a9ec6Sbellard                 (double)s->temp_count / s->tb_count : 0,
2109a23a9ec6Sbellard                 s->temp_count_max);
2110a23a9ec6Sbellard 
2111a23a9ec6Sbellard     cpu_fprintf(f, "cycles/op           %0.1f\n",
2112a23a9ec6Sbellard                 s->op_count ? (double)tot / s->op_count : 0);
2113a23a9ec6Sbellard     cpu_fprintf(f, "cycles/in byte      %0.1f\n",
2114a23a9ec6Sbellard                 s->code_in_len ? (double)tot / s->code_in_len : 0);
2115a23a9ec6Sbellard     cpu_fprintf(f, "cycles/out byte     %0.1f\n",
2116a23a9ec6Sbellard                 s->code_out_len ? (double)tot / s->code_out_len : 0);
2117a23a9ec6Sbellard     if (tot == 0)
2118a23a9ec6Sbellard         tot = 1;
2119a23a9ec6Sbellard     cpu_fprintf(f, "  gen_interm time   %0.1f%%\n",
2120a23a9ec6Sbellard                 (double)s->interm_time / tot * 100.0);
2121a23a9ec6Sbellard     cpu_fprintf(f, "  gen_code time     %0.1f%%\n",
2122a23a9ec6Sbellard                 (double)s->code_time / tot * 100.0);
2123a23a9ec6Sbellard     cpu_fprintf(f, "liveness/code time  %0.1f%%\n",
2124a23a9ec6Sbellard                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
2125a23a9ec6Sbellard     cpu_fprintf(f, "cpu_restore count   %" PRId64 "\n",
2126a23a9ec6Sbellard                 s->restore_count);
2127a23a9ec6Sbellard     cpu_fprintf(f, "  avg cycles        %0.1f\n",
2128a23a9ec6Sbellard                 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
2129a23a9ec6Sbellard     {
2130a23a9ec6Sbellard         extern void dump_op_count(void);
2131a23a9ec6Sbellard         dump_op_count();
2132a23a9ec6Sbellard     }
2133a23a9ec6Sbellard }
2134a23a9ec6Sbellard #else
213524bf7b3aSbellard void tcg_dump_info(FILE *f,
2136a23a9ec6Sbellard                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2137a23a9ec6Sbellard {
213824bf7b3aSbellard     cpu_fprintf(f, "[TCG profiler not compiled]\n");
2139a23a9ec6Sbellard }
2140a23a9ec6Sbellard #endif
2141