]> Git Repo - qemu.git/blob - tcg/tcg.c
debug output: write helper names
[qemu.git] / tcg / tcg.c
1 /*
2  * Tiny Code Generator for QEMU
3  *
4  * Copyright (c) 2008 Fabrice Bellard
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24
25 /* define it to suppress various consistency checks (faster) */
26 #define NDEBUG
27
28 /* define it to use liveness analysis (better code) */
29 #define USE_LIVENESS_ANALYSIS
30
31 #include <assert.h>
32 #include <stdarg.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <inttypes.h>
37 #ifdef _WIN32
38 #include <malloc.h>
39 #endif
40
41 #include "config.h"
42 #include "qemu-common.h"
43
44 /* Note: the long term plan is to reduce the dependancies on the QEMU
45    CPU definitions. Currently they are used for qemu_ld/st
46    instructions */
47 #define NO_CPU_IO_DEFS
48 #include "cpu.h"
49 #include "exec-all.h"
50
51 #include "tcg-op.h"
52 #include "elf.h"
53
54
55 static void patch_reloc(uint8_t *code_ptr, int type, 
56                         tcg_target_long value, tcg_target_long addend);
57
58 TCGOpDef tcg_op_defs[] = {
59 #define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size },
60 #define DEF2(s, iargs, oargs, cargs, flags) { #s, iargs, oargs, cargs, iargs + oargs + cargs, flags, 0 },
61 #include "tcg-opc.h"
62 #undef DEF
63 #undef DEF2
64 };
65
66 TCGRegSet tcg_target_available_regs[2];
67 TCGRegSet tcg_target_call_clobber_regs;
68
69 /* XXX: move that inside the context */
70 uint16_t *gen_opc_ptr;
71 TCGArg *gen_opparam_ptr;
72
73 static inline void tcg_out8(TCGContext *s, uint8_t v)
74 {
75     *s->code_ptr++ = v;
76 }
77
78 static inline void tcg_out16(TCGContext *s, uint16_t v)
79 {
80     *(uint16_t *)s->code_ptr = v;
81     s->code_ptr += 2;
82 }
83
84 static inline void tcg_out32(TCGContext *s, uint32_t v)
85 {
86     *(uint32_t *)s->code_ptr = v;
87     s->code_ptr += 4;
88 }
89
90 /* label relocation processing */
91
92 void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type, 
93                    int label_index, long addend)
94 {
95     TCGLabel *l;
96     TCGRelocation *r;
97
98     l = &s->labels[label_index];
99     if (l->has_value) {
100         /* FIXME: This may break relocations on RISC targets that
101            modify instruction fields in place.  The caller may not have 
102            written the initial value.  */
103         patch_reloc(code_ptr, type, l->u.value, addend);
104     } else {
105         /* add a new relocation entry */
106         r = tcg_malloc(sizeof(TCGRelocation));
107         r->type = type;
108         r->ptr = code_ptr;
109         r->addend = addend;
110         r->next = l->u.first_reloc;
111         l->u.first_reloc = r;
112     }
113 }
114
115 static void tcg_out_label(TCGContext *s, int label_index, 
116                           tcg_target_long value)
117 {
118     TCGLabel *l;
119     TCGRelocation *r;
120
121     l = &s->labels[label_index];
122     if (l->has_value)
123         tcg_abort();
124     r = l->u.first_reloc;
125     while (r != NULL) {
126         patch_reloc(r->ptr, r->type, value, r->addend);
127         r = r->next;
128     }
129     l->has_value = 1;
130     l->u.value = value;
131 }
132
133 int gen_new_label(void)
134 {
135     TCGContext *s = &tcg_ctx;
136     int idx;
137     TCGLabel *l;
138
139     if (s->nb_labels >= TCG_MAX_LABELS)
140         tcg_abort();
141     idx = s->nb_labels++;
142     l = &s->labels[idx];
143     l->has_value = 0;
144     l->u.first_reloc = NULL;
145     return idx;
146 }
147
148 #include "tcg-target.c"
149
150 /* pool based memory allocation */
151 void *tcg_malloc_internal(TCGContext *s, int size)
152 {
153     TCGPool *p;
154     int pool_size;
155     
156     if (size > TCG_POOL_CHUNK_SIZE) {
157         /* big malloc: insert a new pool (XXX: could optimize) */
158         p = qemu_malloc(sizeof(TCGPool) + size);
159         p->size = size;
160         if (s->pool_current)
161             s->pool_current->next = p;
162         else
163             s->pool_first = p;
164         p->next = s->pool_current;
165     } else {
166         p = s->pool_current;
167         if (!p) {
168             p = s->pool_first;
169             if (!p)
170                 goto new_pool;
171         } else {
172             if (!p->next) {
173             new_pool:
174                 pool_size = TCG_POOL_CHUNK_SIZE;
175                 p = qemu_malloc(sizeof(TCGPool) + pool_size);
176                 p->size = pool_size;
177                 p->next = NULL;
178                 if (s->pool_current) 
179                     s->pool_current->next = p;
180                 else
181                     s->pool_first = p;
182             } else {
183                 p = p->next;
184             }
185         }
186     }
187     s->pool_current = p;
188     s->pool_cur = p->data + size;
189     s->pool_end = p->data + p->size;
190     return p->data;
191 }
192
193 void tcg_pool_reset(TCGContext *s)
194 {
195     s->pool_cur = s->pool_end = NULL;
196     s->pool_current = NULL;
197 }
198
199 /* free all the pool */
200 void tcg_pool_free(TCGContext *s)
201 {
202     TCGPool *p, *p1;
203
204     for(p = s->pool_first; p != NULL; p = p1) {
205         p1 = p->next;
206         qemu_free(p);
207     }
208     s->pool_first = NULL;
209     s->pool_cur = s->pool_end = NULL;
210 }
211
212 void tcg_context_init(TCGContext *s)
213 {
214     int op, total_args, n;
215     TCGOpDef *def;
216     TCGArgConstraint *args_ct;
217     int *sorted_args;
218
219     memset(s, 0, sizeof(*s));
220     s->temps = s->static_temps;
221     s->nb_globals = 0;
222     
223     /* Count total number of arguments and allocate the corresponding
224        space */
225     total_args = 0;
226     for(op = 0; op < NB_OPS; op++) {
227         def = &tcg_op_defs[op];
228         n = def->nb_iargs + def->nb_oargs;
229         total_args += n;
230     }
231
232     args_ct = qemu_malloc(sizeof(TCGArgConstraint) * total_args);
233     sorted_args = qemu_malloc(sizeof(int) * total_args);
234
235     for(op = 0; op < NB_OPS; op++) {
236         def = &tcg_op_defs[op];
237         def->args_ct = args_ct;
238         def->sorted_args = sorted_args;
239         n = def->nb_iargs + def->nb_oargs;
240         sorted_args += n;
241         args_ct += n;
242     }
243     
244     tcg_target_init(s);
245
246     /* init global prologue and epilogue */
247     s->code_buf = code_gen_prologue;
248     s->code_ptr = s->code_buf;
249     tcg_target_qemu_prologue(s);
250     flush_icache_range((unsigned long)s->code_buf, 
251                        (unsigned long)s->code_ptr);
252 }
253
254 void tcg_set_frame(TCGContext *s, int reg,
255                    tcg_target_long start, tcg_target_long size)
256 {
257     s->frame_start = start;
258     s->frame_end = start + size;
259     s->frame_reg = reg;
260 }
261
262 void tcg_set_macro_func(TCGContext *s, TCGMacroFunc *func)
263 {
264     s->macro_func = func;
265 }
266
267 void tcg_func_start(TCGContext *s)
268 {
269     tcg_pool_reset(s);
270     s->nb_temps = s->nb_globals;
271     s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS);
272     s->nb_labels = 0;
273     s->current_frame_offset = s->frame_start;
274
275     gen_opc_ptr = gen_opc_buf;
276     gen_opparam_ptr = gen_opparam_buf;
277 }
278
279 static inline void tcg_temp_alloc(TCGContext *s, int n)
280 {
281     if (n > TCG_MAX_TEMPS)
282         tcg_abort();
283 }
284
285 TCGv tcg_global_reg_new(TCGType type, int reg, const char *name)
286 {
287     TCGContext *s = &tcg_ctx;
288     TCGTemp *ts;
289     int idx;
290
291 #if TCG_TARGET_REG_BITS == 32
292     if (type != TCG_TYPE_I32)
293         tcg_abort();
294 #endif
295     if (tcg_regset_test_reg(s->reserved_regs, reg))
296         tcg_abort();
297     idx = s->nb_globals;
298     tcg_temp_alloc(s, s->nb_globals + 1);
299     ts = &s->temps[s->nb_globals];
300     ts->base_type = type;
301     ts->type = type;
302     ts->fixed_reg = 1;
303     ts->reg = reg;
304     ts->val_type = TEMP_VAL_REG;
305     ts->name = name;
306     s->nb_globals++;
307     tcg_regset_set_reg(s->reserved_regs, reg);
308     return MAKE_TCGV(idx);
309 }
310
311 #if TCG_TARGET_REG_BITS == 32
312 /* temporary hack to avoid register shortage for tcg_qemu_st64() */
313 TCGv tcg_global_reg2_new_hack(TCGType type, int reg1, int reg2, 
314                               const char *name)
315 {
316     TCGContext *s = &tcg_ctx;
317     TCGTemp *ts;
318     int idx;
319     char buf[64];
320
321     if (type != TCG_TYPE_I64)
322         tcg_abort();
323     idx = s->nb_globals;
324     tcg_temp_alloc(s, s->nb_globals + 2);
325     ts = &s->temps[s->nb_globals];
326     ts->base_type = type;
327     ts->type = TCG_TYPE_I32;
328     ts->fixed_reg = 1;
329     ts->reg = reg1;
330     ts->val_type = TEMP_VAL_REG;
331     pstrcpy(buf, sizeof(buf), name);
332     pstrcat(buf, sizeof(buf), "_0");
333     ts->name = strdup(buf);
334
335     ts++;
336     ts->base_type = type;
337     ts->type = TCG_TYPE_I32;
338     ts->fixed_reg = 1;
339     ts->reg = reg2;
340     ts->val_type = TEMP_VAL_REG;
341     pstrcpy(buf, sizeof(buf), name);
342     pstrcat(buf, sizeof(buf), "_1");
343     ts->name = strdup(buf);
344
345     s->nb_globals += 2;
346     return MAKE_TCGV(idx);
347 }
348 #endif
349
350 TCGv tcg_global_mem_new(TCGType type, int reg, tcg_target_long offset,
351                         const char *name)
352 {
353     TCGContext *s = &tcg_ctx;
354     TCGTemp *ts;
355     int idx;
356
357     idx = s->nb_globals;
358 #if TCG_TARGET_REG_BITS == 32
359     if (type == TCG_TYPE_I64) {
360         char buf[64];
361         tcg_temp_alloc(s, s->nb_globals + 1);
362         ts = &s->temps[s->nb_globals];
363         ts->base_type = type;
364         ts->type = TCG_TYPE_I32;
365         ts->fixed_reg = 0;
366         ts->mem_allocated = 1;
367         ts->mem_reg = reg;
368 #ifdef TCG_TARGET_WORDS_BIGENDIAN
369         ts->mem_offset = offset + 4;
370 #else
371         ts->mem_offset = offset;
372 #endif
373         ts->val_type = TEMP_VAL_MEM;
374         pstrcpy(buf, sizeof(buf), name);
375         pstrcat(buf, sizeof(buf), "_0");
376         ts->name = strdup(buf);
377         ts++;
378
379         ts->base_type = type;
380         ts->type = TCG_TYPE_I32;
381         ts->fixed_reg = 0;
382         ts->mem_allocated = 1;
383         ts->mem_reg = reg;
384 #ifdef TCG_TARGET_WORDS_BIGENDIAN
385         ts->mem_offset = offset;
386 #else
387         ts->mem_offset = offset + 4;
388 #endif
389         ts->val_type = TEMP_VAL_MEM;
390         pstrcpy(buf, sizeof(buf), name);
391         pstrcat(buf, sizeof(buf), "_1");
392         ts->name = strdup(buf);
393
394         s->nb_globals += 2;
395     } else
396 #endif
397     {
398         tcg_temp_alloc(s, s->nb_globals + 1);
399         ts = &s->temps[s->nb_globals];
400         ts->base_type = type;
401         ts->type = type;
402         ts->fixed_reg = 0;
403         ts->mem_allocated = 1;
404         ts->mem_reg = reg;
405         ts->mem_offset = offset;
406         ts->val_type = TEMP_VAL_MEM;
407         ts->name = name;
408         s->nb_globals++;
409     }
410     return MAKE_TCGV(idx);
411 }
412
413 TCGv tcg_temp_new(TCGType type)
414 {
415     TCGContext *s = &tcg_ctx;
416     TCGTemp *ts;
417     int idx;
418
419     idx = s->nb_temps;
420 #if TCG_TARGET_REG_BITS == 32
421     if (type == TCG_TYPE_I64) {
422         tcg_temp_alloc(s, s->nb_temps + 1);
423         ts = &s->temps[s->nb_temps];
424         ts->base_type = type;
425         ts->type = TCG_TYPE_I32;
426         ts->fixed_reg = 0;
427         ts->val_type = TEMP_VAL_DEAD;
428         ts->mem_allocated = 0;
429         ts->name = NULL;
430         ts++;
431         ts->base_type = TCG_TYPE_I32;
432         ts->type = TCG_TYPE_I32;
433         ts->val_type = TEMP_VAL_DEAD;
434         ts->fixed_reg = 0;
435         ts->mem_allocated = 0;
436         ts->name = NULL;
437         s->nb_temps += 2;
438     } else
439 #endif
440     {
441         tcg_temp_alloc(s, s->nb_temps + 1);
442         ts = &s->temps[s->nb_temps];
443         ts->base_type = type;
444         ts->type = type;
445         ts->fixed_reg = 0;
446         ts->val_type = TEMP_VAL_DEAD;
447         ts->mem_allocated = 0;
448         ts->name = NULL;
449         s->nb_temps++;
450     }
451     return MAKE_TCGV(idx);
452 }
453
454 TCGv tcg_const_i32(int32_t val)
455 {
456     TCGContext *s = &tcg_ctx;
457     TCGTemp *ts;
458     int idx;
459
460     idx = s->nb_temps;
461     tcg_temp_alloc(s, idx + 1);
462     ts = &s->temps[idx];
463     ts->base_type = ts->type = TCG_TYPE_I32;
464     ts->val_type = TEMP_VAL_CONST;
465     ts->name = NULL;
466     ts->val = val;
467     s->nb_temps++;
468     return MAKE_TCGV(idx);
469 }
470
471 TCGv tcg_const_i64(int64_t val)
472 {
473     TCGContext *s = &tcg_ctx;
474     TCGTemp *ts;
475     int idx;
476
477     idx = s->nb_temps;
478 #if TCG_TARGET_REG_BITS == 32
479     tcg_temp_alloc(s, idx + 2);
480     ts = &s->temps[idx];
481     ts->base_type = TCG_TYPE_I64;
482     ts->type = TCG_TYPE_I32;
483     ts->val_type = TEMP_VAL_CONST;
484     ts->name = NULL;
485     ts->val = val;
486     ts++;
487     ts->base_type = TCG_TYPE_I32;
488     ts->type = TCG_TYPE_I32;
489     ts->val_type = TEMP_VAL_CONST;
490     ts->name = NULL;
491     ts->val = val >> 32;
492     s->nb_temps += 2;
493 #else
494     tcg_temp_alloc(s, idx + 1);
495     ts = &s->temps[idx];
496     ts->base_type = ts->type = TCG_TYPE_I64;
497     ts->val_type = TEMP_VAL_CONST;
498     ts->name = NULL;
499     ts->val = val;
500     s->nb_temps++;
501 #endif    
502     return MAKE_TCGV(idx);
503 }
504
505 void tcg_register_helper(void *func, const char *name)
506 {
507     TCGContext *s = &tcg_ctx;
508     int n;
509     if ((s->nb_helpers + 1) > s->allocated_helpers) {
510         n = s->allocated_helpers;
511         if (n == 0) {
512             n = 4;
513         } else {
514             n *= 2;
515         }
516         s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo));
517         s->allocated_helpers = n;
518     }
519     s->helpers[s->nb_helpers].func = (tcg_target_ulong)func;
520     s->helpers[s->nb_helpers].name = name;
521     s->nb_helpers++;
522 }
523
524 static inline TCGType tcg_get_base_type(TCGContext *s, TCGv arg)
525 {
526     return s->temps[GET_TCGV(arg)].base_type;
527 }
528
529 static void tcg_gen_call_internal(TCGContext *s, TCGv func, 
530                                   unsigned int flags,
531                                   unsigned int nb_rets, const TCGv *rets,
532                                   unsigned int nb_params, const TCGv *params)
533 {
534     int i;
535     *gen_opc_ptr++ = INDEX_op_call;
536     *gen_opparam_ptr++ = (nb_rets << 16) | (nb_params + 1);
537     for(i = 0; i < nb_rets; i++) {
538         *gen_opparam_ptr++ = GET_TCGV(rets[i]);
539     }
540     for(i = 0; i < nb_params; i++) {
541         *gen_opparam_ptr++ = GET_TCGV(params[i]);
542     }
543     *gen_opparam_ptr++ = GET_TCGV(func);
544
545     *gen_opparam_ptr++ = flags;
546     /* total parameters, needed to go backward in the instruction stream */
547     *gen_opparam_ptr++ = 1 + nb_rets + nb_params + 3;
548 }
549
550
551 #if TCG_TARGET_REG_BITS < 64
552 /* Note: we convert the 64 bit args to 32 bit and do some alignment
553    and endian swap. Maybe it would be better to do the alignment
554    and endian swap in tcg_reg_alloc_call(). */
555 void tcg_gen_call(TCGContext *s, TCGv func, unsigned int flags,
556                   unsigned int nb_rets, const TCGv *rets,
557                   unsigned int nb_params, const TCGv *args1)
558 {
559     TCGv ret, *args2, rets_2[2], arg;
560     int j, i, call_type;
561
562     if (nb_rets == 1) {
563         ret = rets[0];
564         if (tcg_get_base_type(s, ret) == TCG_TYPE_I64) {
565             nb_rets = 2;
566 #ifdef TCG_TARGET_WORDS_BIGENDIAN
567             rets_2[0] = TCGV_HIGH(ret);
568             rets_2[1] = ret;
569 #else
570             rets_2[0] = ret;
571             rets_2[1] = TCGV_HIGH(ret);
572 #endif
573             rets = rets_2;
574         }
575     }
576     args2 = alloca((nb_params * 3) * sizeof(TCGv));
577     j = 0;
578     call_type = (flags & TCG_CALL_TYPE_MASK);
579     for(i = 0; i < nb_params; i++) {
580         arg = args1[i];
581         if (tcg_get_base_type(s, arg) == TCG_TYPE_I64) {
582 #ifdef TCG_TARGET_I386
583             /* REGPARM case: if the third parameter is 64 bit, it is
584                allocated on the stack */
585             if (j == 2 && call_type == TCG_CALL_TYPE_REGPARM) {
586                 call_type = TCG_CALL_TYPE_REGPARM_2;
587                 flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type;
588             }
589             args2[j++] = arg;
590             args2[j++] = TCGV_HIGH(arg);
591 #else
592 #ifdef TCG_TARGET_CALL_ALIGN_ARGS
593             /* some targets want aligned 64 bit args */
594             if (j & 1) {
595                 args2[j++] = TCG_CALL_DUMMY_ARG;
596             }
597 #endif
598 #ifdef TCG_TARGET_WORDS_BIGENDIAN
599             args2[j++] = TCGV_HIGH(arg);
600             args2[j++] = arg;
601 #else
602             args2[j++] = arg;
603             args2[j++] = TCGV_HIGH(arg);
604 #endif
605 #endif
606         } else {
607             args2[j++] = arg;
608         }
609     }
610     tcg_gen_call_internal(s, func, flags, 
611                           nb_rets, rets, j, args2);
612 }
613 #else
614 void tcg_gen_call(TCGContext *s, TCGv func, unsigned int flags,
615                   unsigned int nb_rets, const TCGv *rets,
616                   unsigned int nb_params, const TCGv *args1)
617 {
618     tcg_gen_call_internal(s, func, flags, 
619                           nb_rets, rets, nb_params, args1);
620 }
621 #endif
622
623 #if TCG_TARGET_REG_BITS == 32
624 void tcg_gen_shifti_i64(TCGv ret, TCGv arg1, 
625                         int c, int right, int arith)
626 {
627     if (c == 0) {
628         tcg_gen_mov_i32(ret, arg1);
629         tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
630     } else if (c >= 32) {
631         c -= 32;
632         if (right) {
633             if (arith) {
634                 tcg_gen_sari_i32(ret, TCGV_HIGH(arg1), c);
635                 tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31);
636             } else {
637                 tcg_gen_shri_i32(ret, TCGV_HIGH(arg1), c);
638                 tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
639             }
640         } else {
641             tcg_gen_shli_i32(TCGV_HIGH(ret), arg1, c);
642             tcg_gen_movi_i32(ret, 0);
643         }
644     } else {
645         TCGv t0, t1;
646
647         t0 = tcg_temp_new(TCG_TYPE_I32);
648         t1 = tcg_temp_new(TCG_TYPE_I32);
649         if (right) {
650             tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c);
651             if (arith)
652                 tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c);
653             else 
654                 tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c);
655             tcg_gen_shri_i32(ret, arg1, c); 
656             tcg_gen_or_i32(ret, ret, t0);
657             tcg_gen_mov_i32(TCGV_HIGH(ret), t1);
658         } else {
659             tcg_gen_shri_i32(t0, arg1, 32 - c);
660             /* Note: ret can be the same as arg1, so we use t1 */
661             tcg_gen_shli_i32(t1, arg1, c); 
662             tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c);
663             tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0);
664             tcg_gen_mov_i32(ret, t1);
665         }
666     }
667 }
668 #endif
669
670 void tcg_reg_alloc_start(TCGContext *s)
671 {
672     int i;
673     TCGTemp *ts;
674     for(i = 0; i < s->nb_globals; i++) {
675         ts = &s->temps[i];
676         if (ts->fixed_reg) {
677             ts->val_type = TEMP_VAL_REG;
678         } else {
679             ts->val_type = TEMP_VAL_MEM;
680         }
681     }
682     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
683         s->reg_to_temp[i] = -1;
684     }
685 }
686
687 static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size,
688                                  int idx)
689 {
690     TCGTemp *ts;
691
692     ts = &s->temps[idx];
693     if (idx < s->nb_globals) {
694         pstrcpy(buf, buf_size, ts->name);
695     } else {
696         if (ts->val_type == TEMP_VAL_CONST) {
697             snprintf(buf, buf_size, "$0x%" TCG_PRIlx , ts->val);
698         } else {
699             snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
700         }
701     }
702     return buf;
703 }
704
705 char *tcg_get_arg_str(TCGContext *s, char *buf, int buf_size, TCGv arg)
706 {
707     return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV(arg));
708 }
709
710 /* find helper definition (XXX: inefficient) */
711 static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val)
712 {
713     int i;
714     for(i = 0; i < s->nb_helpers; i++) {
715         if (s->helpers[i].func == val) 
716             return &s->helpers[i];
717     }
718     return NULL;
719 }
720
721 static const char *tcg_get_helper_str_idx(TCGContext *s, char *buf, int buf_size,
722                                           int idx)
723 {
724     TCGTemp *ts;
725     TCGHelperInfo *th;
726
727     ts = &s->temps[idx];
728     if (ts->val_type == TEMP_VAL_CONST) {
729         /* find helper name (XXX: inefficient) */
730         th = tcg_find_helper(s, ts->val);
731         if (th) {
732             pstrcpy(buf, buf_size, "$");
733             pstrcat(buf, buf_size, th->name);
734             return buf;
735         }
736     }
737     return tcg_get_arg_str_idx(s, buf, buf_size, idx);
738 }
739
740
741 void tcg_dump_ops(TCGContext *s, FILE *outfile)
742 {
743     const uint16_t *opc_ptr;
744     const TCGArg *args;
745     TCGArg arg;
746     int c, i, k, nb_oargs, nb_iargs, nb_cargs;
747     const TCGOpDef *def;
748     char buf[128];
749
750     opc_ptr = gen_opc_buf;
751     args = gen_opparam_buf;
752     while (opc_ptr < gen_opc_ptr) {
753         c = *opc_ptr++;
754         def = &tcg_op_defs[c];
755         fprintf(outfile, " %s ", def->name);
756         if (c == INDEX_op_call) {
757             TCGArg arg;
758
759             /* variable number of arguments */
760             arg = *args++;
761             nb_oargs = arg >> 16;
762             nb_iargs = arg & 0xffff;
763             nb_cargs = def->nb_cargs;
764
765             /* function name */
766             fprintf(outfile, "%s",
767                     tcg_get_helper_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1]));
768             /* flags */
769             fprintf(outfile, ",$0x%" TCG_PRIlx,
770                     args[nb_oargs + nb_iargs]);
771             /* nb out args */
772             fprintf(outfile, ",$%d", nb_oargs);
773             for(i = 0; i < nb_oargs; i++) {
774                 fprintf(outfile, ",");
775                 fprintf(outfile, "%s",
776                         tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i]));
777             }
778             for(i = 0; i < (nb_iargs - 1); i++) {
779                 fprintf(outfile, ",");
780                 if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) {
781                     fprintf(outfile, "<dummy>");
782                 } else {
783                     fprintf(outfile, "%s",
784                             tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i]));
785                 }
786             }
787         } else {
788             if (c == INDEX_op_nopn) {
789                 /* variable number of arguments */
790                 nb_cargs = *args;
791                 nb_oargs = 0;
792                 nb_iargs = 0;
793             } else {
794                 nb_oargs = def->nb_oargs;
795                 nb_iargs = def->nb_iargs;
796                 nb_cargs = def->nb_cargs;
797             }
798             
799             k = 0;
800             for(i = 0; i < nb_oargs; i++) {
801                 if (k != 0)
802                     fprintf(outfile, ",");
803                 fprintf(outfile, "%s",
804                         tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
805             }
806             for(i = 0; i < nb_iargs; i++) {
807                 if (k != 0)
808                     fprintf(outfile, ",");
809                 fprintf(outfile, "%s",
810                         tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
811             }
812             for(i = 0; i < nb_cargs; i++) {
813                 if (k != 0)
814                     fprintf(outfile, ",");
815                 arg = args[k++];
816                 fprintf(outfile, "$0x%" TCG_PRIlx, arg);
817             }
818         }
819         fprintf(outfile, "\n");
820         args += nb_iargs + nb_oargs + nb_cargs;
821     }
822 }
823
824 /* we give more priority to constraints with less registers */
825 static int get_constraint_priority(const TCGOpDef *def, int k)
826 {
827     const TCGArgConstraint *arg_ct;
828
829     int i, n;
830     arg_ct = &def->args_ct[k];
831     if (arg_ct->ct & TCG_CT_ALIAS) {
832         /* an alias is equivalent to a single register */
833         n = 1;
834     } else {
835         if (!(arg_ct->ct & TCG_CT_REG))
836             return 0;
837         n = 0;
838         for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
839             if (tcg_regset_test_reg(arg_ct->u.regs, i))
840                 n++;
841         }
842     }
843     return TCG_TARGET_NB_REGS - n + 1;
844 }
845
846 /* sort from highest priority to lowest */
847 static void sort_constraints(TCGOpDef *def, int start, int n)
848 {
849     int i, j, p1, p2, tmp;
850
851     for(i = 0; i < n; i++)
852         def->sorted_args[start + i] = start + i;
853     if (n <= 1)
854         return;
855     for(i = 0; i < n - 1; i++) {
856         for(j = i + 1; j < n; j++) {
857             p1 = get_constraint_priority(def, def->sorted_args[start + i]);
858             p2 = get_constraint_priority(def, def->sorted_args[start + j]);
859             if (p1 < p2) {
860                 tmp = def->sorted_args[start + i];
861                 def->sorted_args[start + i] = def->sorted_args[start + j];
862                 def->sorted_args[start + j] = tmp;
863             }
864         }
865     }
866 }
867
868 void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
869 {
870     int op;
871     TCGOpDef *def;
872     const char *ct_str;
873     int i, nb_args;
874
875     for(;;) {
876         if (tdefs->op < 0)
877             break;
878         op = tdefs->op;
879         assert(op >= 0 && op < NB_OPS);
880         def = &tcg_op_defs[op];
881         nb_args = def->nb_iargs + def->nb_oargs;
882         for(i = 0; i < nb_args; i++) {
883             ct_str = tdefs->args_ct_str[i];
884             tcg_regset_clear(def->args_ct[i].u.regs);
885             def->args_ct[i].ct = 0;
886             if (ct_str[0] >= '0' && ct_str[0] <= '9') {
887                 int oarg;
888                 oarg = ct_str[0] - '0';
889                 assert(oarg < def->nb_oargs);
890                 assert(def->args_ct[oarg].ct & TCG_CT_REG);
891                 /* TCG_CT_ALIAS is for the output arguments. The input
892                    argument is tagged with TCG_CT_IALIAS. */
893                 def->args_ct[i] = def->args_ct[oarg];
894                 def->args_ct[oarg].ct = TCG_CT_ALIAS;
895                 def->args_ct[oarg].alias_index = i;
896                 def->args_ct[i].ct |= TCG_CT_IALIAS;
897                 def->args_ct[i].alias_index = oarg;
898             } else {
899                 for(;;) {
900                     if (*ct_str == '\0')
901                         break;
902                     switch(*ct_str) {
903                     case 'i':
904                         def->args_ct[i].ct |= TCG_CT_CONST;
905                         ct_str++;
906                         break;
907                     default:
908                         if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) {
909                             fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n",
910                                     ct_str, i, def->name);
911                             exit(1);
912                         }
913                     }
914                 }
915             }
916         }
917
918         /* sort the constraints (XXX: this is just an heuristic) */
919         sort_constraints(def, 0, def->nb_oargs);
920         sort_constraints(def, def->nb_oargs, def->nb_iargs);
921
922 #if 0
923         {
924             int i;
925
926             printf("%s: sorted=", def->name);
927             for(i = 0; i < def->nb_oargs + def->nb_iargs; i++)
928                 printf(" %d", def->sorted_args[i]);
929             printf("\n");
930         }
931 #endif
932         tdefs++;
933     }
934
935 }
936
937 #ifdef USE_LIVENESS_ANALYSIS
938
939 /* set a nop for an operation using 'nb_args' */
940 static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr, 
941                                TCGArg *args, int nb_args)
942 {
943     if (nb_args == 0) {
944         *opc_ptr = INDEX_op_nop;
945     } else {
946         *opc_ptr = INDEX_op_nopn;
947         args[0] = nb_args;
948         args[nb_args - 1] = nb_args;
949     }
950 }
951
952 /* liveness analysis: end of basic block: globals are live, temps are dead */
953 static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps)
954 {
955     memset(dead_temps, 0, s->nb_globals);
956     memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals);
957 }
958
959 /* Liveness analysis : update the opc_dead_iargs array to tell if a
960    given input arguments is dead. Instructions updating dead
961    temporaries are removed. */
962 void tcg_liveness_analysis(TCGContext *s)
963 {
964     int i, op_index, op, nb_args, nb_iargs, nb_oargs, arg, nb_ops;
965     TCGArg *args;
966     const TCGOpDef *def;
967     uint8_t *dead_temps;
968     unsigned int dead_iargs;
969     
970     gen_opc_ptr++; /* skip end */
971
972     nb_ops = gen_opc_ptr - gen_opc_buf;
973
974     /* XXX: make it really dynamic */
975     s->op_dead_iargs = tcg_malloc(OPC_BUF_SIZE * sizeof(uint16_t));
976     
977     dead_temps = tcg_malloc(s->nb_temps);
978     memset(dead_temps, 1, s->nb_temps);
979
980     args = gen_opparam_ptr;
981     op_index = nb_ops - 1;
982     while (op_index >= 0) {
983         op = gen_opc_buf[op_index];
984         def = &tcg_op_defs[op];
985         switch(op) {
986         case INDEX_op_call:
987             {
988                 int call_flags;
989
990                 nb_args = args[-1];
991                 args -= nb_args;
992                 nb_iargs = args[0] & 0xffff;
993                 nb_oargs = args[0] >> 16;
994                 args++;
995                 call_flags = args[nb_oargs + nb_iargs];
996
997                 /* pure functions can be removed if their result is not
998                    used */
999                 if (call_flags & TCG_CALL_PURE) {
1000                     for(i = 0; i < nb_oargs; i++) {
1001                         arg = args[i];
1002                         if (!dead_temps[arg])
1003                             goto do_not_remove_call;
1004                     }
1005                     tcg_set_nop(s, gen_opc_buf + op_index, 
1006                                 args - 1, nb_args);
1007                 } else {
1008                 do_not_remove_call:
1009
1010                     /* output args are dead */
1011                     for(i = 0; i < nb_oargs; i++) {
1012                         arg = args[i];
1013                         dead_temps[arg] = 1;
1014                     }
1015                     
1016                     /* globals are live (they may be used by the call) */
1017                     memset(dead_temps, 0, s->nb_globals);
1018                     
1019                     /* input args are live */
1020                     dead_iargs = 0;
1021                     for(i = 0; i < nb_iargs; i++) {
1022                         arg = args[i + nb_oargs];
1023                         if (arg != TCG_CALL_DUMMY_ARG) {
1024                             if (dead_temps[arg]) {
1025                                 dead_iargs |= (1 << i);
1026                             }
1027                             dead_temps[arg] = 0;
1028                         }
1029                     }
1030                     s->op_dead_iargs[op_index] = dead_iargs;
1031                 }
1032                 args--;
1033             }
1034             break;
1035         case INDEX_op_set_label:
1036             args--;
1037             /* mark end of basic block */
1038             tcg_la_bb_end(s, dead_temps);
1039             break;
1040         case INDEX_op_nopn:
1041             nb_args = args[-1];
1042             args -= nb_args;
1043             break;
1044         case INDEX_op_discard:
1045             args--;
1046             /* mark the temporary as dead */
1047             dead_temps[args[0]] = 1;
1048             break;
1049         case INDEX_op_macro_2:
1050             {
1051                 int dead_args[2], macro_id;
1052                 int saved_op_index, saved_arg_index;
1053                 int macro_op_index, macro_arg_index;
1054                 int macro_end_op_index, macro_end_arg_index;
1055                 int last_nb_temps;
1056                 
1057                 nb_args = 3;
1058                 args -= nb_args;
1059                 dead_args[0] = dead_temps[args[0]];
1060                 dead_args[1] = dead_temps[args[1]];
1061                 macro_id = args[2];
1062
1063                 /* call the macro function which generate code
1064                    depending on the live outputs */
1065                 saved_op_index = op_index;
1066                 saved_arg_index = args - gen_opparam_buf;
1067
1068                 /* add a macro start instruction */
1069                 *gen_opc_ptr++ = INDEX_op_macro_start;
1070                 *gen_opparam_ptr++ = saved_op_index;
1071                 *gen_opparam_ptr++ = saved_arg_index;
1072
1073                 macro_op_index = gen_opc_ptr - gen_opc_buf;
1074                 macro_arg_index = gen_opparam_ptr -  gen_opparam_buf;
1075
1076                 last_nb_temps = s->nb_temps;
1077
1078                 s->macro_func(s, macro_id, dead_args);
1079
1080                 /* realloc temp info (XXX: make it faster) */
1081                 if (s->nb_temps > last_nb_temps) {
1082                     uint8_t *new_dead_temps;
1083
1084                     new_dead_temps = tcg_malloc(s->nb_temps);
1085                     memcpy(new_dead_temps, dead_temps, last_nb_temps);
1086                     memset(new_dead_temps + last_nb_temps, 1, 
1087                            s->nb_temps - last_nb_temps);
1088                     dead_temps = new_dead_temps;
1089                 }
1090
1091                 macro_end_op_index = gen_opc_ptr - gen_opc_buf;
1092                 macro_end_arg_index = gen_opparam_ptr - gen_opparam_buf;
1093
1094                 /* end of macro: add a goto to the next instruction */
1095                 *gen_opc_ptr++ = INDEX_op_macro_end;
1096                 *gen_opparam_ptr++ = op_index + 1;
1097                 *gen_opparam_ptr++ = saved_arg_index + nb_args;
1098
1099                 /* modify the macro operation to be a macro_goto */
1100                 gen_opc_buf[op_index] = INDEX_op_macro_goto;
1101                 args[0] = macro_op_index;
1102                 args[1] = macro_arg_index;
1103                 args[2] = 0; /* dummy third arg to match the 
1104                                 macro parameters */
1105
1106                 /* set the next instruction to the end of the macro */
1107                 op_index = macro_end_op_index;
1108                 args = macro_end_arg_index + gen_opparam_buf;
1109             }
1110             break;
1111         case INDEX_op_macro_start:
1112             args -= 2;
1113             op_index = args[0];
1114             args = gen_opparam_buf + args[1];
1115             break;
1116         case INDEX_op_macro_goto:
1117         case INDEX_op_macro_end:
1118             tcg_abort(); /* should never happen in liveness analysis */
1119         case INDEX_op_end:
1120             break;
1121             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1122         default:
1123             if (op > INDEX_op_end) {
1124                 args -= def->nb_args;
1125                 nb_iargs = def->nb_iargs;
1126                 nb_oargs = def->nb_oargs;
1127
1128                 /* Test if the operation can be removed because all
1129                    its outputs are dead. We assume that nb_oargs == 0
1130                    implies side effects */
1131                 if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
1132                     for(i = 0; i < nb_oargs; i++) {
1133                         arg = args[i];
1134                         if (!dead_temps[arg])
1135                             goto do_not_remove;
1136                     }
1137                     tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args);
1138 #ifdef CONFIG_PROFILER
1139                     {
1140                         extern int64_t dyngen_tcg_del_op_count;
1141                         dyngen_tcg_del_op_count++;
1142                     }
1143 #endif
1144                 } else {
1145                 do_not_remove:
1146
1147                     /* output args are dead */
1148                     for(i = 0; i < nb_oargs; i++) {
1149                         arg = args[i];
1150                         dead_temps[arg] = 1;
1151                     }
1152                     
1153                     /* if end of basic block, update */
1154                     if (def->flags & TCG_OPF_BB_END) {
1155                         tcg_la_bb_end(s, dead_temps);
1156                     } else if (def->flags & TCG_OPF_CALL_CLOBBER) {
1157                         /* globals are live */
1158                         memset(dead_temps, 0, s->nb_globals);
1159                     }
1160                     
1161                     /* input args are live */
1162                     dead_iargs = 0;
1163                     for(i = 0; i < nb_iargs; i++) {
1164                         arg = args[i + nb_oargs];
1165                         if (dead_temps[arg]) {
1166                             dead_iargs |= (1 << i);
1167                         }
1168                         dead_temps[arg] = 0;
1169                     }
1170                     s->op_dead_iargs[op_index] = dead_iargs;
1171                 }
1172             } else {
1173                 /* legacy dyngen operations */
1174                 args -= def->nb_args;
1175                 /* mark end of basic block */
1176                 tcg_la_bb_end(s, dead_temps);
1177             }
1178             break;
1179         }
1180         op_index--;
1181     }
1182
1183     if (args != gen_opparam_buf)
1184         tcg_abort();
1185 }
1186 #else
1187 /* dummy liveness analysis */
1188 void tcg_liveness_analysis(TCGContext *s)
1189 {
1190     int nb_ops;
1191     nb_ops = gen_opc_ptr - gen_opc_buf;
1192
1193     s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
1194     memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t));
1195 }
1196 #endif
1197
1198 #ifndef NDEBUG
1199 static void dump_regs(TCGContext *s)
1200 {
1201     TCGTemp *ts;
1202     int i;
1203     char buf[64];
1204
1205     for(i = 0; i < s->nb_temps; i++) {
1206         ts = &s->temps[i];
1207         printf("  %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i));
1208         switch(ts->val_type) {
1209         case TEMP_VAL_REG:
1210             printf("%s", tcg_target_reg_names[ts->reg]);
1211             break;
1212         case TEMP_VAL_MEM:
1213             printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]);
1214             break;
1215         case TEMP_VAL_CONST:
1216             printf("$0x%" TCG_PRIlx, ts->val);
1217             break;
1218         case TEMP_VAL_DEAD:
1219             printf("D");
1220             break;
1221         default:
1222             printf("???");
1223             break;
1224         }
1225         printf("\n");
1226     }
1227
1228     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
1229         if (s->reg_to_temp[i] >= 0) {
1230             printf("%s: %s\n", 
1231                    tcg_target_reg_names[i], 
1232                    tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i]));
1233         }
1234     }
1235 }
1236
1237 static void check_regs(TCGContext *s)
1238 {
1239     int reg, k;
1240     TCGTemp *ts;
1241     char buf[64];
1242
1243     for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1244         k = s->reg_to_temp[reg];
1245         if (k >= 0) {
1246             ts = &s->temps[k];
1247             if (ts->val_type != TEMP_VAL_REG ||
1248                 ts->reg != reg) {
1249                 printf("Inconsistency for register %s:\n", 
1250                        tcg_target_reg_names[reg]);
1251                 goto fail;
1252             }
1253         }
1254     }
1255     for(k = 0; k < s->nb_temps; k++) {
1256         ts = &s->temps[k];
1257         if (ts->val_type == TEMP_VAL_REG &&
1258             !ts->fixed_reg &&
1259             s->reg_to_temp[ts->reg] != k) {
1260                 printf("Inconsistency for temp %s:\n", 
1261                        tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
1262         fail:
1263                 printf("reg state:\n");
1264                 dump_regs(s);
1265                 tcg_abort();
1266         }
1267         if (ts->val_type == TEMP_VAL_CONST && k < s->nb_globals) {
1268             printf("constant forbidden in global %s\n",
1269                    tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
1270             goto fail;
1271         }
1272     }
1273 }
1274 #endif
1275
1276 static void temp_allocate_frame(TCGContext *s, int temp)
1277 {
1278     TCGTemp *ts;
1279     ts = &s->temps[temp];
1280     s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1);
1281     if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end)
1282         tcg_abort();
1283     ts->mem_offset = s->current_frame_offset;
1284     ts->mem_reg = s->frame_reg;
1285     ts->mem_allocated = 1;
1286     s->current_frame_offset += sizeof(tcg_target_long);
1287 }
1288
1289 /* free register 'reg' by spilling the corresponding temporary if necessary */
1290 static void tcg_reg_free(TCGContext *s, int reg)
1291 {
1292     TCGTemp *ts;
1293     int temp;
1294
1295     temp = s->reg_to_temp[reg];
1296     if (temp != -1) {
1297         ts = &s->temps[temp];
1298         assert(ts->val_type == TEMP_VAL_REG);
1299         if (!ts->mem_coherent) {
1300             if (!ts->mem_allocated) 
1301                 temp_allocate_frame(s, temp);
1302             tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1303         }
1304         ts->val_type = TEMP_VAL_MEM;
1305         s->reg_to_temp[reg] = -1;
1306     }
1307 }
1308
1309 /* Allocate a register belonging to reg1 & ~reg2 */
1310 static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2)
1311 {
1312     int i, reg;
1313     TCGRegSet reg_ct;
1314
1315     tcg_regset_andnot(reg_ct, reg1, reg2);
1316
1317     /* first try free registers */
1318     for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
1319         reg = tcg_target_reg_alloc_order[i];
1320         if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1)
1321             return reg;
1322     }
1323
1324     /* XXX: do better spill choice */
1325     for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
1326         reg = tcg_target_reg_alloc_order[i];
1327         if (tcg_regset_test_reg(reg_ct, reg)) {
1328             tcg_reg_free(s, reg);
1329             return reg;
1330         }
1331     }
1332
1333     tcg_abort();
1334 }
1335
1336 /* save globals to their cannonical location and assume they can be
1337    modified be the following code. */
1338 static void save_globals(TCGContext *s)
1339 {
1340     TCGTemp *ts;
1341     int i;
1342
1343     for(i = 0; i < s->nb_globals; i++) {
1344         ts = &s->temps[i];
1345         if (!ts->fixed_reg) {
1346             if (ts->val_type == TEMP_VAL_REG) {
1347                 tcg_reg_free(s, ts->reg);
1348             } else if (ts->val_type == TEMP_VAL_DEAD) {
1349                 ts->val_type = TEMP_VAL_MEM;
1350             }
1351         }
1352     }
1353 }
1354
1355 /* at the end of a basic block, we assume all temporaries are dead and
1356    all globals are stored at their canonical location */
1357 /* XXX: optimize by handling constants in another array ? */
1358 void tcg_reg_alloc_bb_end(TCGContext *s)
1359 {
1360     TCGTemp *ts;
1361     int i;
1362
1363     save_globals(s);
1364
1365     for(i = s->nb_globals; i < s->nb_temps; i++) {
1366         ts = &s->temps[i];
1367         if (ts->val_type != TEMP_VAL_CONST) {
1368             if (ts->val_type == TEMP_VAL_REG) {
1369                 s->reg_to_temp[ts->reg] = -1;
1370             }
1371             ts->val_type = TEMP_VAL_DEAD;
1372         }
1373     }
1374 }
1375
1376 #define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
1377
1378 static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
1379                               const TCGArg *args,
1380                               unsigned int dead_iargs)
1381 {
1382     TCGTemp *ts, *ots;
1383     int reg;
1384     const TCGArgConstraint *arg_ct;
1385
1386     ots = &s->temps[args[0]];
1387     ts = &s->temps[args[1]];
1388     arg_ct = &def->args_ct[0];
1389
1390     if (ts->val_type == TEMP_VAL_REG) {
1391         if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) {
1392             /* the mov can be suppressed */
1393             if (ots->val_type == TEMP_VAL_REG)
1394                 s->reg_to_temp[ots->reg] = -1;
1395             reg = ts->reg;
1396             s->reg_to_temp[reg] = -1;
1397             ts->val_type = TEMP_VAL_DEAD;
1398         } else {
1399             if (ots->val_type == TEMP_VAL_REG) {
1400                 reg = ots->reg;
1401             } else {
1402                 reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
1403             }
1404             if (ts->reg != reg) {
1405                 tcg_out_mov(s, reg, ts->reg);
1406             }
1407         }
1408     } else if (ts->val_type == TEMP_VAL_MEM) {
1409         if (ots->val_type == TEMP_VAL_REG) {
1410             reg = ots->reg;
1411         } else {
1412             reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
1413         }
1414         tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1415     } else if (ts->val_type == TEMP_VAL_CONST) {
1416         if (ots->val_type == TEMP_VAL_REG) {
1417             reg = ots->reg;
1418         } else {
1419             reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
1420         }
1421         tcg_out_movi(s, ots->type, reg, ts->val);
1422     } else {
1423         tcg_abort();
1424     }
1425     s->reg_to_temp[reg] = args[0];
1426     ots->reg = reg;
1427     ots->val_type = TEMP_VAL_REG;
1428     ots->mem_coherent = 0;
1429 }
1430
1431 static void tcg_reg_alloc_op(TCGContext *s, 
1432                              const TCGOpDef *def, int opc,
1433                              const TCGArg *args,
1434                              unsigned int dead_iargs)
1435 {
1436     TCGRegSet allocated_regs;
1437     int i, k, nb_iargs, nb_oargs, reg;
1438     TCGArg arg;
1439     const TCGArgConstraint *arg_ct;
1440     TCGTemp *ts;
1441     TCGArg new_args[TCG_MAX_OP_ARGS];
1442     int const_args[TCG_MAX_OP_ARGS];
1443
1444     nb_oargs = def->nb_oargs;
1445     nb_iargs = def->nb_iargs;
1446
1447     /* copy constants */
1448     memcpy(new_args + nb_oargs + nb_iargs, 
1449            args + nb_oargs + nb_iargs, 
1450            sizeof(TCGArg) * def->nb_cargs);
1451
1452     /* satisfy input constraints */ 
1453     tcg_regset_set(allocated_regs, s->reserved_regs);
1454     for(k = 0; k < nb_iargs; k++) {
1455         i = def->sorted_args[nb_oargs + k];
1456         arg = args[i];
1457         arg_ct = &def->args_ct[i];
1458         ts = &s->temps[arg];
1459         if (ts->val_type == TEMP_VAL_MEM) {
1460             reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1461             tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1462             ts->val_type = TEMP_VAL_REG;
1463             ts->reg = reg;
1464             ts->mem_coherent = 1;
1465             s->reg_to_temp[reg] = arg;
1466         } else if (ts->val_type == TEMP_VAL_CONST) {
1467             if (tcg_target_const_match(ts->val, arg_ct)) {
1468                 /* constant is OK for instruction */
1469                 const_args[i] = 1;
1470                 new_args[i] = ts->val;
1471                 goto iarg_end;
1472             } else {
1473                 /* need to move to a register*/
1474                 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1475                 tcg_out_movi(s, ts->type, reg, ts->val);
1476                 goto iarg_end1;
1477             }
1478         }
1479         assert(ts->val_type == TEMP_VAL_REG);
1480         if (arg_ct->ct & TCG_CT_IALIAS) {
1481             if (ts->fixed_reg) {
1482                 /* if fixed register, we must allocate a new register
1483                    if the alias is not the same register */
1484                 if (arg != args[arg_ct->alias_index])
1485                     goto allocate_in_reg;
1486             } else {
1487                 /* if the input is aliased to an output and if it is
1488                    not dead after the instruction, we must allocate
1489                    a new register and move it */
1490                 if (!IS_DEAD_IARG(i - nb_oargs)) 
1491                     goto allocate_in_reg;
1492             }
1493         }
1494         reg = ts->reg;
1495         if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1496             /* nothing to do : the constraint is satisfied */
1497         } else {
1498         allocate_in_reg:
1499             /* allocate a new register matching the constraint 
1500                and move the temporary register into it */
1501             reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1502             tcg_out_mov(s, reg, ts->reg);
1503         }
1504     iarg_end1:
1505         new_args[i] = reg;
1506         const_args[i] = 0;
1507         tcg_regset_set_reg(allocated_regs, reg);
1508     iarg_end: ;
1509     }
1510     
1511     /* mark dead temporaries and free the associated registers */
1512     for(i = 0; i < nb_iargs; i++) {
1513         arg = args[nb_oargs + i];
1514         if (IS_DEAD_IARG(i)) {
1515             ts = &s->temps[arg];
1516             if (ts->val_type != TEMP_VAL_CONST && !ts->fixed_reg) {
1517                 if (ts->val_type == TEMP_VAL_REG)
1518                     s->reg_to_temp[ts->reg] = -1;
1519                 ts->val_type = TEMP_VAL_DEAD;
1520             }
1521         }
1522     }
1523
1524     if (def->flags & TCG_OPF_CALL_CLOBBER) {
1525         /* XXX: permit generic clobber register list ? */ 
1526         for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1527             if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
1528                 tcg_reg_free(s, reg);
1529             }
1530         }
1531         /* XXX: for load/store we could do that only for the slow path
1532            (i.e. when a memory callback is called) */
1533
1534         /* store globals and free associated registers (we assume the insn
1535            can modify any global. */
1536         save_globals(s);
1537     }
1538
1539     /* satisfy the output constraints */
1540     tcg_regset_set(allocated_regs, s->reserved_regs);
1541     for(k = 0; k < nb_oargs; k++) {
1542         i = def->sorted_args[k];
1543         arg = args[i];
1544         arg_ct = &def->args_ct[i];
1545         ts = &s->temps[arg];
1546         if (arg_ct->ct & TCG_CT_ALIAS) {
1547             reg = new_args[arg_ct->alias_index];
1548         } else {
1549             /* if fixed register, we try to use it */
1550             reg = ts->reg;
1551             if (ts->fixed_reg &&
1552                 tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1553                 goto oarg_end;
1554             }
1555             reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1556         }
1557         tcg_regset_set_reg(allocated_regs, reg);
1558         /* if a fixed register is used, then a move will be done afterwards */
1559         if (!ts->fixed_reg) {
1560             if (ts->val_type == TEMP_VAL_REG)
1561                 s->reg_to_temp[ts->reg] = -1;
1562             ts->val_type = TEMP_VAL_REG;
1563             ts->reg = reg;
1564             /* temp value is modified, so the value kept in memory is
1565                potentially not the same */
1566             ts->mem_coherent = 0; 
1567             s->reg_to_temp[reg] = arg;
1568         }
1569     oarg_end:
1570         new_args[i] = reg;
1571     }
1572
1573     if (def->flags & TCG_OPF_BB_END)
1574         tcg_reg_alloc_bb_end(s);
1575
1576     /* emit instruction */
1577     tcg_out_op(s, opc, new_args, const_args);
1578     
1579     /* move the outputs in the correct register if needed */
1580     for(i = 0; i < nb_oargs; i++) {
1581         ts = &s->temps[args[i]];
1582         reg = new_args[i];
1583         if (ts->fixed_reg && ts->reg != reg) {
1584             tcg_out_mov(s, ts->reg, reg);
1585         }
1586     }
1587 }
1588
1589 #ifdef TCG_TARGET_STACK_GROWSUP
1590 #define STACK_DIR(x) (-(x))
1591 #else
1592 #define STACK_DIR(x) (x)
1593 #endif
1594
1595 static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
1596                               int opc, const TCGArg *args,
1597                               unsigned int dead_iargs)
1598 {
1599     int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params;
1600     TCGArg arg, func_arg;
1601     TCGTemp *ts;
1602     tcg_target_long stack_offset, call_stack_size, func_addr;
1603     int const_func_arg, allocate_args;
1604     TCGRegSet allocated_regs;
1605     const TCGArgConstraint *arg_ct;
1606
1607     arg = *args++;
1608
1609     nb_oargs = arg >> 16;
1610     nb_iargs = arg & 0xffff;
1611     nb_params = nb_iargs - 1;
1612
1613     flags = args[nb_oargs + nb_iargs];
1614
1615     nb_regs = tcg_target_get_call_iarg_regs_count(flags);
1616     if (nb_regs > nb_params)
1617         nb_regs = nb_params;
1618
1619     /* assign stack slots first */
1620     /* XXX: preallocate call stack */
1621     call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);
1622     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & 
1623         ~(TCG_TARGET_STACK_ALIGN - 1);
1624     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
1625     if (allocate_args) {
1626         tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size));
1627     }
1628
1629     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
1630     for(i = nb_regs; i < nb_params; i++) {
1631         arg = args[nb_oargs + i];
1632 #ifdef TCG_TARGET_STACK_GROWSUP
1633         stack_offset -= sizeof(tcg_target_long);
1634 #endif
1635         if (arg != TCG_CALL_DUMMY_ARG) {
1636             ts = &s->temps[arg];
1637             if (ts->val_type == TEMP_VAL_REG) {
1638                 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
1639             } else if (ts->val_type == TEMP_VAL_MEM) {
1640                 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 
1641                                     s->reserved_regs);
1642                 /* XXX: not correct if reading values from the stack */
1643                 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1644                 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
1645             } else if (ts->val_type == TEMP_VAL_CONST) {
1646                 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 
1647                                     s->reserved_regs);
1648                 /* XXX: sign extend may be needed on some targets */
1649                 tcg_out_movi(s, ts->type, reg, ts->val);
1650                 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
1651             } else {
1652                 tcg_abort();
1653             }
1654         }
1655 #ifndef TCG_TARGET_STACK_GROWSUP
1656         stack_offset += sizeof(tcg_target_long);
1657 #endif
1658     }
1659     
1660     /* assign input registers */
1661     tcg_regset_set(allocated_regs, s->reserved_regs);
1662     for(i = 0; i < nb_regs; i++) {
1663         arg = args[nb_oargs + i];
1664         if (arg != TCG_CALL_DUMMY_ARG) {
1665             ts = &s->temps[arg];
1666             reg = tcg_target_call_iarg_regs[i];
1667             tcg_reg_free(s, reg);
1668             if (ts->val_type == TEMP_VAL_REG) {
1669                 if (ts->reg != reg) {
1670                     tcg_out_mov(s, reg, ts->reg);
1671                 }
1672             } else if (ts->val_type == TEMP_VAL_MEM) {
1673                 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1674             } else if (ts->val_type == TEMP_VAL_CONST) {
1675                 /* XXX: sign extend ? */
1676                 tcg_out_movi(s, ts->type, reg, ts->val);
1677             } else {
1678                 tcg_abort();
1679             }
1680             tcg_regset_set_reg(allocated_regs, reg);
1681         }
1682     }
1683     
1684     /* assign function address */
1685     func_arg = args[nb_oargs + nb_iargs - 1];
1686     arg_ct = &def->args_ct[0];
1687     ts = &s->temps[func_arg];
1688     func_addr = ts->val;
1689     const_func_arg = 0;
1690     if (ts->val_type == TEMP_VAL_MEM) {
1691         reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1692         tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1693         func_arg = reg;
1694     } else if (ts->val_type == TEMP_VAL_REG) {
1695         reg = ts->reg;
1696         if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1697             reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1698             tcg_out_mov(s, reg, ts->reg);
1699         }
1700         func_arg = reg;
1701     } else if (ts->val_type == TEMP_VAL_CONST) {
1702         if (tcg_target_const_match(func_addr, arg_ct)) {
1703             const_func_arg = 1;
1704             func_arg = func_addr;
1705         } else {
1706             reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1707             tcg_out_movi(s, ts->type, reg, func_addr);
1708             func_arg = reg;
1709         }
1710     } else {
1711         tcg_abort();
1712     }
1713     
1714     /* mark dead temporaries and free the associated registers */
1715     for(i = 0; i < nb_iargs; i++) {
1716         arg = args[nb_oargs + i];
1717         if (IS_DEAD_IARG(i)) {
1718             ts = &s->temps[arg];
1719             if (ts->val_type != TEMP_VAL_CONST && !ts->fixed_reg) {
1720                 if (ts->val_type == TEMP_VAL_REG)
1721                     s->reg_to_temp[ts->reg] = -1;
1722                 ts->val_type = TEMP_VAL_DEAD;
1723             }
1724         }
1725     }
1726     
1727     /* clobber call registers */
1728     for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1729         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
1730             tcg_reg_free(s, reg);
1731         }
1732     }
1733     
1734     /* store globals and free associated registers (we assume the call
1735        can modify any global. */
1736     save_globals(s);
1737
1738     tcg_out_op(s, opc, &func_arg, &const_func_arg);
1739     
1740     if (allocate_args) {
1741         tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size));
1742     }
1743
1744     /* assign output registers and emit moves if needed */
1745     for(i = 0; i < nb_oargs; i++) {
1746         arg = args[i];
1747         ts = &s->temps[arg];
1748         reg = tcg_target_call_oarg_regs[i];
1749         tcg_reg_free(s, reg);
1750         if (ts->fixed_reg) {
1751             if (ts->reg != reg) {
1752                 tcg_out_mov(s, ts->reg, reg);
1753             }
1754         } else {
1755             if (ts->val_type == TEMP_VAL_REG)
1756                 s->reg_to_temp[ts->reg] = -1;
1757             ts->val_type = TEMP_VAL_REG;
1758             ts->reg = reg;
1759             ts->mem_coherent = 0; 
1760             s->reg_to_temp[reg] = arg;
1761         }
1762     }
1763     
1764     return nb_iargs + nb_oargs + def->nb_cargs + 1;
1765 }
1766
1767 #ifdef CONFIG_PROFILER
1768
1769 static int64_t dyngen_table_op_count[NB_OPS];
1770
1771 void dump_op_count(void)
1772 {
1773     int i;
1774     FILE *f;
1775     f = fopen("/tmp/op1.log", "w");
1776     for(i = 0; i < INDEX_op_end; i++) {
1777         fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, dyngen_table_op_count[i]);
1778     }
1779     fclose(f);
1780     f = fopen("/tmp/op2.log", "w");
1781     for(i = INDEX_op_end; i < NB_OPS; i++) {
1782         fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, dyngen_table_op_count[i]);
1783     }
1784     fclose(f);
1785 }
1786 #endif
1787
1788
1789 static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
1790                                       long search_pc)
1791 {
1792     int opc, op_index, macro_op_index;
1793     const TCGOpDef *def;
1794     unsigned int dead_iargs;
1795     const TCGArg *args;
1796
1797 #ifdef DEBUG_DISAS
1798     if (unlikely(loglevel & CPU_LOG_TB_OP)) {
1799         fprintf(logfile, "OP:\n");
1800         tcg_dump_ops(s, logfile);
1801         fprintf(logfile, "\n");
1802     }
1803 #endif
1804
1805     tcg_liveness_analysis(s);
1806
1807 #ifdef DEBUG_DISAS
1808     if (unlikely(loglevel & CPU_LOG_TB_OP_OPT)) {
1809         fprintf(logfile, "OP after la:\n");
1810         tcg_dump_ops(s, logfile);
1811         fprintf(logfile, "\n");
1812     }
1813 #endif
1814
1815     tcg_reg_alloc_start(s);
1816
1817     s->code_buf = gen_code_buf;
1818     s->code_ptr = gen_code_buf;
1819
1820     macro_op_index = -1;
1821     args = gen_opparam_buf;
1822     op_index = 0;
1823
1824     for(;;) {
1825         opc = gen_opc_buf[op_index];
1826 #ifdef CONFIG_PROFILER
1827         dyngen_table_op_count[opc]++;
1828 #endif
1829         def = &tcg_op_defs[opc];
1830 #if 0
1831         printf("%s: %d %d %d\n", def->name,
1832                def->nb_oargs, def->nb_iargs, def->nb_cargs);
1833         //        dump_regs(s);
1834 #endif
1835         switch(opc) {
1836         case INDEX_op_mov_i32:
1837 #if TCG_TARGET_REG_BITS == 64
1838         case INDEX_op_mov_i64:
1839 #endif
1840             dead_iargs = s->op_dead_iargs[op_index];
1841             tcg_reg_alloc_mov(s, def, args, dead_iargs);
1842             break;
1843         case INDEX_op_nop:
1844         case INDEX_op_nop1:
1845         case INDEX_op_nop2:
1846         case INDEX_op_nop3:
1847             break;
1848         case INDEX_op_nopn:
1849             args += args[0];
1850             goto next;
1851         case INDEX_op_discard:
1852             {
1853                 TCGTemp *ts;
1854                 ts = &s->temps[args[0]];
1855                 /* mark the temporary as dead */
1856                 if (ts->val_type != TEMP_VAL_CONST && !ts->fixed_reg) {
1857                     if (ts->val_type == TEMP_VAL_REG)
1858                         s->reg_to_temp[ts->reg] = -1;
1859                     ts->val_type = TEMP_VAL_DEAD;
1860                 }
1861             }
1862             break;
1863         case INDEX_op_macro_goto:
1864             macro_op_index = op_index; /* only used for exceptions */
1865             op_index = args[0] - 1;
1866             args = gen_opparam_buf + args[1];
1867             goto next;
1868         case INDEX_op_macro_end:
1869             macro_op_index = -1; /* only used for exceptions */
1870             op_index = args[0] - 1;
1871             args = gen_opparam_buf + args[1];
1872             goto next;
1873         case INDEX_op_macro_start:
1874             /* must never happen here */
1875             tcg_abort();
1876         case INDEX_op_set_label:
1877             tcg_reg_alloc_bb_end(s);
1878             tcg_out_label(s, args[0], (long)s->code_ptr);
1879             break;
1880         case INDEX_op_call:
1881             dead_iargs = s->op_dead_iargs[op_index];
1882             args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs);
1883             goto next;
1884         case INDEX_op_end:
1885             goto the_end;
1886
1887 #ifdef CONFIG_DYNGEN_OP
1888         case 0 ... INDEX_op_end - 1:
1889             /* legacy dyngen ops */
1890 #ifdef CONFIG_PROFILER
1891             {
1892                 extern int64_t dyngen_old_op_count;
1893                 dyngen_old_op_count++;
1894             }
1895 #endif
1896             tcg_reg_alloc_bb_end(s);
1897             if (search_pc >= 0) {
1898                 s->code_ptr += def->copy_size;
1899                 args += def->nb_args;
1900             } else {
1901                 args = dyngen_op(s, opc, args);
1902             }
1903             goto next;
1904 #endif
1905         default:
1906             /* Note: in order to speed up the code, it would be much
1907                faster to have specialized register allocator functions for
1908                some common argument patterns */
1909             dead_iargs = s->op_dead_iargs[op_index];
1910             tcg_reg_alloc_op(s, def, opc, args, dead_iargs);
1911             break;
1912         }
1913         args += def->nb_args;
1914     next: ;
1915         if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) {
1916             if (macro_op_index >= 0)
1917                 return macro_op_index;
1918             else
1919                 return op_index;
1920         }
1921         op_index++;
1922 #ifndef NDEBUG
1923         check_regs(s);
1924 #endif
1925     }
1926  the_end:
1927     return -1;
1928 }
1929
1930 int dyngen_code(TCGContext *s, uint8_t *gen_code_buf)
1931 {
1932 #ifdef CONFIG_PROFILER
1933     {
1934         extern int64_t dyngen_op_count;
1935         extern int dyngen_op_count_max;
1936         int n;
1937         n = (gen_opc_ptr - gen_opc_buf);
1938         dyngen_op_count += n;
1939         if (n > dyngen_op_count_max)
1940             dyngen_op_count_max = n;
1941     }
1942 #endif
1943
1944     tcg_gen_code_common(s, gen_code_buf, -1);
1945
1946     /* flush instruction cache */
1947     flush_icache_range((unsigned long)gen_code_buf, 
1948                        (unsigned long)s->code_ptr);
1949     return s->code_ptr -  gen_code_buf;
1950 }
1951
1952 /* Return the index of the micro operation such as the pc after is <
1953    offset bytes from the start of the TB.  The contents of gen_code_buf must
1954    not be changed, though writing the same values is ok.
1955    Return -1 if not found. */
1956 int dyngen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset)
1957 {
1958     return tcg_gen_code_common(s, gen_code_buf, offset);
1959 }
This page took 0.130438 seconds and 4 git commands to generate.