configure: dyngen is long time gone
[qemu.git] / tcg / tcg.c
blob30b5106e19d9debd0809e4c14b1d3f274159a32c
1 /*
2 * Tiny Code Generator for QEMU
4 * Copyright (c) 2008 Fabrice Bellard
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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.
25 /* define it to use liveness analysis (better code) */
26 #define USE_LIVENESS_ANALYSIS
28 #include "config.h"
30 #if !defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG)
31 /* define it to suppress various consistency checks (faster) */
32 #define NDEBUG
33 #endif
35 #include <stdarg.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <inttypes.h>
40 #ifdef _WIN32
41 #include <malloc.h>
42 #endif
43 #ifdef _AIX
44 #include <alloca.h>
45 #endif
47 #include "qemu-common.h"
48 #include "cache-utils.h"
49 #include "host-utils.h"
50 #include "qemu-timer.h"
52 /* Note: the long term plan is to reduce the dependancies on the QEMU
53 CPU definitions. Currently they are used for qemu_ld/st
54 instructions */
55 #define NO_CPU_IO_DEFS
56 #include "cpu.h"
57 #include "exec-all.h"
59 #include "tcg-op.h"
60 #include "elf.h"
62 #if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
63 #error GUEST_BASE not supported on this host.
64 #endif
66 static void tcg_target_init(TCGContext *s);
67 static void tcg_target_qemu_prologue(TCGContext *s);
68 static void patch_reloc(uint8_t *code_ptr, int type,
69 tcg_target_long value, tcg_target_long addend);
71 static TCGOpDef tcg_op_defs[] = {
72 #define DEF(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags, 0 },
73 #include "tcg-opc.h"
74 #undef DEF
77 static TCGRegSet tcg_target_available_regs[2];
78 static TCGRegSet tcg_target_call_clobber_regs;
80 /* XXX: move that inside the context */
81 uint16_t *gen_opc_ptr;
82 TCGArg *gen_opparam_ptr;
84 static inline void tcg_out8(TCGContext *s, uint8_t v)
86 *s->code_ptr++ = v;
89 static inline void tcg_out16(TCGContext *s, uint16_t v)
91 *(uint16_t *)s->code_ptr = v;
92 s->code_ptr += 2;
95 static inline void tcg_out32(TCGContext *s, uint32_t v)
97 *(uint32_t *)s->code_ptr = v;
98 s->code_ptr += 4;
101 /* label relocation processing */
103 static void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type,
104 int label_index, long addend)
106 TCGLabel *l;
107 TCGRelocation *r;
109 l = &s->labels[label_index];
110 if (l->has_value) {
111 /* FIXME: This may break relocations on RISC targets that
112 modify instruction fields in place. The caller may not have
113 written the initial value. */
114 patch_reloc(code_ptr, type, l->u.value, addend);
115 } else {
116 /* add a new relocation entry */
117 r = tcg_malloc(sizeof(TCGRelocation));
118 r->type = type;
119 r->ptr = code_ptr;
120 r->addend = addend;
121 r->next = l->u.first_reloc;
122 l->u.first_reloc = r;
126 static void tcg_out_label(TCGContext *s, int label_index,
127 tcg_target_long value)
129 TCGLabel *l;
130 TCGRelocation *r;
132 l = &s->labels[label_index];
133 if (l->has_value)
134 tcg_abort();
135 r = l->u.first_reloc;
136 while (r != NULL) {
137 patch_reloc(r->ptr, r->type, value, r->addend);
138 r = r->next;
140 l->has_value = 1;
141 l->u.value = value;
144 int gen_new_label(void)
146 TCGContext *s = &tcg_ctx;
147 int idx;
148 TCGLabel *l;
150 if (s->nb_labels >= TCG_MAX_LABELS)
151 tcg_abort();
152 idx = s->nb_labels++;
153 l = &s->labels[idx];
154 l->has_value = 0;
155 l->u.first_reloc = NULL;
156 return idx;
159 #include "tcg-target.c"
161 /* pool based memory allocation */
162 void *tcg_malloc_internal(TCGContext *s, int size)
164 TCGPool *p;
165 int pool_size;
167 if (size > TCG_POOL_CHUNK_SIZE) {
168 /* big malloc: insert a new pool (XXX: could optimize) */
169 p = qemu_malloc(sizeof(TCGPool) + size);
170 p->size = size;
171 if (s->pool_current)
172 s->pool_current->next = p;
173 else
174 s->pool_first = p;
175 p->next = s->pool_current;
176 } else {
177 p = s->pool_current;
178 if (!p) {
179 p = s->pool_first;
180 if (!p)
181 goto new_pool;
182 } else {
183 if (!p->next) {
184 new_pool:
185 pool_size = TCG_POOL_CHUNK_SIZE;
186 p = qemu_malloc(sizeof(TCGPool) + pool_size);
187 p->size = pool_size;
188 p->next = NULL;
189 if (s->pool_current)
190 s->pool_current->next = p;
191 else
192 s->pool_first = p;
193 } else {
194 p = p->next;
198 s->pool_current = p;
199 s->pool_cur = p->data + size;
200 s->pool_end = p->data + p->size;
201 return p->data;
204 void tcg_pool_reset(TCGContext *s)
206 s->pool_cur = s->pool_end = NULL;
207 s->pool_current = NULL;
210 void tcg_context_init(TCGContext *s)
212 int op, total_args, n;
213 TCGOpDef *def;
214 TCGArgConstraint *args_ct;
215 int *sorted_args;
217 memset(s, 0, sizeof(*s));
218 s->temps = s->static_temps;
219 s->nb_globals = 0;
221 /* Count total number of arguments and allocate the corresponding
222 space */
223 total_args = 0;
224 for(op = 0; op < NB_OPS; op++) {
225 def = &tcg_op_defs[op];
226 n = def->nb_iargs + def->nb_oargs;
227 total_args += n;
230 args_ct = qemu_malloc(sizeof(TCGArgConstraint) * total_args);
231 sorted_args = qemu_malloc(sizeof(int) * total_args);
233 for(op = 0; op < NB_OPS; op++) {
234 def = &tcg_op_defs[op];
235 def->args_ct = args_ct;
236 def->sorted_args = sorted_args;
237 n = def->nb_iargs + def->nb_oargs;
238 sorted_args += n;
239 args_ct += n;
242 tcg_target_init(s);
245 void tcg_prologue_init(TCGContext *s)
247 /* init global prologue and epilogue */
248 s->code_buf = code_gen_prologue;
249 s->code_ptr = s->code_buf;
250 tcg_target_qemu_prologue(s);
251 flush_icache_range((unsigned long)s->code_buf,
252 (unsigned long)s->code_ptr);
255 void tcg_set_frame(TCGContext *s, int reg,
256 tcg_target_long start, tcg_target_long size)
258 s->frame_start = start;
259 s->frame_end = start + size;
260 s->frame_reg = reg;
263 void tcg_func_start(TCGContext *s)
265 int i;
266 tcg_pool_reset(s);
267 s->nb_temps = s->nb_globals;
268 for(i = 0; i < (TCG_TYPE_COUNT * 2); i++)
269 s->first_free_temp[i] = -1;
270 s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS);
271 s->nb_labels = 0;
272 s->current_frame_offset = s->frame_start;
274 gen_opc_ptr = gen_opc_buf;
275 gen_opparam_ptr = gen_opparam_buf;
278 static inline void tcg_temp_alloc(TCGContext *s, int n)
280 if (n > TCG_MAX_TEMPS)
281 tcg_abort();
284 static inline int tcg_global_reg_new_internal(TCGType type, int reg,
285 const char *name)
287 TCGContext *s = &tcg_ctx;
288 TCGTemp *ts;
289 int idx;
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->name = name;
305 s->nb_globals++;
306 tcg_regset_set_reg(s->reserved_regs, reg);
307 return idx;
310 TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name)
312 int idx;
314 idx = tcg_global_reg_new_internal(TCG_TYPE_I32, reg, name);
315 return MAKE_TCGV_I32(idx);
318 TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name)
320 int idx;
322 idx = tcg_global_reg_new_internal(TCG_TYPE_I64, reg, name);
323 return MAKE_TCGV_I64(idx);
326 static inline int tcg_global_mem_new_internal(TCGType type, int reg,
327 tcg_target_long offset,
328 const char *name)
330 TCGContext *s = &tcg_ctx;
331 TCGTemp *ts;
332 int idx;
334 idx = s->nb_globals;
335 #if TCG_TARGET_REG_BITS == 32
336 if (type == TCG_TYPE_I64) {
337 char buf[64];
338 tcg_temp_alloc(s, s->nb_globals + 2);
339 ts = &s->temps[s->nb_globals];
340 ts->base_type = type;
341 ts->type = TCG_TYPE_I32;
342 ts->fixed_reg = 0;
343 ts->mem_allocated = 1;
344 ts->mem_reg = reg;
345 #ifdef TCG_TARGET_WORDS_BIGENDIAN
346 ts->mem_offset = offset + 4;
347 #else
348 ts->mem_offset = offset;
349 #endif
350 pstrcpy(buf, sizeof(buf), name);
351 pstrcat(buf, sizeof(buf), "_0");
352 ts->name = strdup(buf);
353 ts++;
355 ts->base_type = type;
356 ts->type = TCG_TYPE_I32;
357 ts->fixed_reg = 0;
358 ts->mem_allocated = 1;
359 ts->mem_reg = reg;
360 #ifdef TCG_TARGET_WORDS_BIGENDIAN
361 ts->mem_offset = offset;
362 #else
363 ts->mem_offset = offset + 4;
364 #endif
365 pstrcpy(buf, sizeof(buf), name);
366 pstrcat(buf, sizeof(buf), "_1");
367 ts->name = strdup(buf);
369 s->nb_globals += 2;
370 } else
371 #endif
373 tcg_temp_alloc(s, s->nb_globals + 1);
374 ts = &s->temps[s->nb_globals];
375 ts->base_type = type;
376 ts->type = type;
377 ts->fixed_reg = 0;
378 ts->mem_allocated = 1;
379 ts->mem_reg = reg;
380 ts->mem_offset = offset;
381 ts->name = name;
382 s->nb_globals++;
384 return idx;
387 TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset,
388 const char *name)
390 int idx;
392 idx = tcg_global_mem_new_internal(TCG_TYPE_I32, reg, offset, name);
393 return MAKE_TCGV_I32(idx);
396 TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset,
397 const char *name)
399 int idx;
401 idx = tcg_global_mem_new_internal(TCG_TYPE_I64, reg, offset, name);
402 return MAKE_TCGV_I64(idx);
405 static inline int tcg_temp_new_internal(TCGType type, int temp_local)
407 TCGContext *s = &tcg_ctx;
408 TCGTemp *ts;
409 int idx, k;
411 k = type;
412 if (temp_local)
413 k += TCG_TYPE_COUNT;
414 idx = s->first_free_temp[k];
415 if (idx != -1) {
416 /* There is already an available temp with the
417 right type */
418 ts = &s->temps[idx];
419 s->first_free_temp[k] = ts->next_free_temp;
420 ts->temp_allocated = 1;
421 assert(ts->temp_local == temp_local);
422 } else {
423 idx = s->nb_temps;
424 #if TCG_TARGET_REG_BITS == 32
425 if (type == TCG_TYPE_I64) {
426 tcg_temp_alloc(s, s->nb_temps + 2);
427 ts = &s->temps[s->nb_temps];
428 ts->base_type = type;
429 ts->type = TCG_TYPE_I32;
430 ts->temp_allocated = 1;
431 ts->temp_local = temp_local;
432 ts->name = NULL;
433 ts++;
434 ts->base_type = TCG_TYPE_I32;
435 ts->type = TCG_TYPE_I32;
436 ts->temp_allocated = 1;
437 ts->temp_local = temp_local;
438 ts->name = NULL;
439 s->nb_temps += 2;
440 } else
441 #endif
443 tcg_temp_alloc(s, s->nb_temps + 1);
444 ts = &s->temps[s->nb_temps];
445 ts->base_type = type;
446 ts->type = type;
447 ts->temp_allocated = 1;
448 ts->temp_local = temp_local;
449 ts->name = NULL;
450 s->nb_temps++;
453 return idx;
456 TCGv_i32 tcg_temp_new_internal_i32(int temp_local)
458 int idx;
460 idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local);
461 return MAKE_TCGV_I32(idx);
464 TCGv_i64 tcg_temp_new_internal_i64(int temp_local)
466 int idx;
468 idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local);
469 return MAKE_TCGV_I64(idx);
472 static inline void tcg_temp_free_internal(int idx)
474 TCGContext *s = &tcg_ctx;
475 TCGTemp *ts;
476 int k;
478 assert(idx >= s->nb_globals && idx < s->nb_temps);
479 ts = &s->temps[idx];
480 assert(ts->temp_allocated != 0);
481 ts->temp_allocated = 0;
482 k = ts->base_type;
483 if (ts->temp_local)
484 k += TCG_TYPE_COUNT;
485 ts->next_free_temp = s->first_free_temp[k];
486 s->first_free_temp[k] = idx;
489 void tcg_temp_free_i32(TCGv_i32 arg)
491 tcg_temp_free_internal(GET_TCGV_I32(arg));
494 void tcg_temp_free_i64(TCGv_i64 arg)
496 tcg_temp_free_internal(GET_TCGV_I64(arg));
499 TCGv_i32 tcg_const_i32(int32_t val)
501 TCGv_i32 t0;
502 t0 = tcg_temp_new_i32();
503 tcg_gen_movi_i32(t0, val);
504 return t0;
507 TCGv_i64 tcg_const_i64(int64_t val)
509 TCGv_i64 t0;
510 t0 = tcg_temp_new_i64();
511 tcg_gen_movi_i64(t0, val);
512 return t0;
515 TCGv_i32 tcg_const_local_i32(int32_t val)
517 TCGv_i32 t0;
518 t0 = tcg_temp_local_new_i32();
519 tcg_gen_movi_i32(t0, val);
520 return t0;
523 TCGv_i64 tcg_const_local_i64(int64_t val)
525 TCGv_i64 t0;
526 t0 = tcg_temp_local_new_i64();
527 tcg_gen_movi_i64(t0, val);
528 return t0;
531 void tcg_register_helper(void *func, const char *name)
533 TCGContext *s = &tcg_ctx;
534 int n;
535 if ((s->nb_helpers + 1) > s->allocated_helpers) {
536 n = s->allocated_helpers;
537 if (n == 0) {
538 n = 4;
539 } else {
540 n *= 2;
542 s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo));
543 s->allocated_helpers = n;
545 s->helpers[s->nb_helpers].func = (tcg_target_ulong)func;
546 s->helpers[s->nb_helpers].name = name;
547 s->nb_helpers++;
550 /* Note: we convert the 64 bit args to 32 bit and do some alignment
551 and endian swap. Maybe it would be better to do the alignment
552 and endian swap in tcg_reg_alloc_call(). */
553 void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
554 int sizemask, TCGArg ret, int nargs, TCGArg *args)
556 #ifdef TCG_TARGET_I386
557 int call_type;
558 #endif
559 int i;
560 int real_args;
561 int nb_rets;
562 TCGArg *nparam;
563 *gen_opc_ptr++ = INDEX_op_call;
564 nparam = gen_opparam_ptr++;
565 #ifdef TCG_TARGET_I386
566 call_type = (flags & TCG_CALL_TYPE_MASK);
567 #endif
568 if (ret != TCG_CALL_DUMMY_ARG) {
569 #if TCG_TARGET_REG_BITS < 64
570 if (sizemask & 1) {
571 #ifdef TCG_TARGET_WORDS_BIGENDIAN
572 *gen_opparam_ptr++ = ret + 1;
573 *gen_opparam_ptr++ = ret;
574 #else
575 *gen_opparam_ptr++ = ret;
576 *gen_opparam_ptr++ = ret + 1;
577 #endif
578 nb_rets = 2;
579 } else
580 #endif
582 *gen_opparam_ptr++ = ret;
583 nb_rets = 1;
585 } else {
586 nb_rets = 0;
588 real_args = 0;
589 for (i = 0; i < nargs; i++) {
590 #if TCG_TARGET_REG_BITS < 64
591 if (sizemask & (2 << i)) {
592 #ifdef TCG_TARGET_I386
593 /* REGPARM case: if the third parameter is 64 bit, it is
594 allocated on the stack */
595 if (i == 2 && call_type == TCG_CALL_TYPE_REGPARM) {
596 call_type = TCG_CALL_TYPE_REGPARM_2;
597 flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type;
599 #endif
600 #ifdef TCG_TARGET_CALL_ALIGN_ARGS
601 /* some targets want aligned 64 bit args */
602 if (real_args & 1) {
603 *gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG;
604 real_args++;
606 #endif
607 /* If stack grows up, then we will be placing successive
608 arguments at lower addresses, which means we need to
609 reverse the order compared to how we would normally
610 treat either big or little-endian. For those arguments
611 that will wind up in registers, this still works for
612 HPPA (the only current STACK_GROWSUP target) since the
613 argument registers are *also* allocated in decreasing
614 order. If another such target is added, this logic may
615 have to get more complicated to differentiate between
616 stack arguments and register arguments. */
617 #if defined(TCG_TARGET_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
618 *gen_opparam_ptr++ = args[i] + 1;
619 *gen_opparam_ptr++ = args[i];
620 #else
621 *gen_opparam_ptr++ = args[i];
622 *gen_opparam_ptr++ = args[i] + 1;
623 #endif
624 real_args += 2;
625 } else
626 #endif
628 *gen_opparam_ptr++ = args[i];
629 real_args++;
632 *gen_opparam_ptr++ = GET_TCGV_PTR(func);
634 *gen_opparam_ptr++ = flags;
636 *nparam = (nb_rets << 16) | (real_args + 1);
638 /* total parameters, needed to go backward in the instruction stream */
639 *gen_opparam_ptr++ = 1 + nb_rets + real_args + 3;
642 #if TCG_TARGET_REG_BITS == 32
643 void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
644 int c, int right, int arith)
646 if (c == 0) {
647 tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
648 tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
649 } else if (c >= 32) {
650 c -= 32;
651 if (right) {
652 if (arith) {
653 tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
654 tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31);
655 } else {
656 tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
657 tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
659 } else {
660 tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c);
661 tcg_gen_movi_i32(TCGV_LOW(ret), 0);
663 } else {
664 TCGv_i32 t0, t1;
666 t0 = tcg_temp_new_i32();
667 t1 = tcg_temp_new_i32();
668 if (right) {
669 tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c);
670 if (arith)
671 tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c);
672 else
673 tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c);
674 tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c);
675 tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0);
676 tcg_gen_mov_i32(TCGV_HIGH(ret), t1);
677 } else {
678 tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c);
679 /* Note: ret can be the same as arg1, so we use t1 */
680 tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c);
681 tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c);
682 tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0);
683 tcg_gen_mov_i32(TCGV_LOW(ret), t1);
685 tcg_temp_free_i32(t0);
686 tcg_temp_free_i32(t1);
689 #endif
692 static void tcg_reg_alloc_start(TCGContext *s)
694 int i;
695 TCGTemp *ts;
696 for(i = 0; i < s->nb_globals; i++) {
697 ts = &s->temps[i];
698 if (ts->fixed_reg) {
699 ts->val_type = TEMP_VAL_REG;
700 } else {
701 ts->val_type = TEMP_VAL_MEM;
704 for(i = s->nb_globals; i < s->nb_temps; i++) {
705 ts = &s->temps[i];
706 ts->val_type = TEMP_VAL_DEAD;
707 ts->mem_allocated = 0;
708 ts->fixed_reg = 0;
710 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
711 s->reg_to_temp[i] = -1;
715 static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size,
716 int idx)
718 TCGTemp *ts;
720 ts = &s->temps[idx];
721 if (idx < s->nb_globals) {
722 pstrcpy(buf, buf_size, ts->name);
723 } else {
724 if (ts->temp_local)
725 snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
726 else
727 snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
729 return buf;
732 char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg)
734 return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I32(arg));
737 char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg)
739 return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I64(arg));
742 static int helper_cmp(const void *p1, const void *p2)
744 const TCGHelperInfo *th1 = p1;
745 const TCGHelperInfo *th2 = p2;
746 if (th1->func < th2->func)
747 return -1;
748 else if (th1->func == th2->func)
749 return 0;
750 else
751 return 1;
754 /* find helper definition (Note: A hash table would be better) */
755 static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val)
757 int m, m_min, m_max;
758 TCGHelperInfo *th;
759 tcg_target_ulong v;
761 if (unlikely(!s->helpers_sorted)) {
762 qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo),
763 helper_cmp);
764 s->helpers_sorted = 1;
767 /* binary search */
768 m_min = 0;
769 m_max = s->nb_helpers - 1;
770 while (m_min <= m_max) {
771 m = (m_min + m_max) >> 1;
772 th = &s->helpers[m];
773 v = th->func;
774 if (v == val)
775 return th;
776 else if (val < v) {
777 m_max = m - 1;
778 } else {
779 m_min = m + 1;
782 return NULL;
785 static const char * const cond_name[] =
787 [TCG_COND_EQ] = "eq",
788 [TCG_COND_NE] = "ne",
789 [TCG_COND_LT] = "lt",
790 [TCG_COND_GE] = "ge",
791 [TCG_COND_LE] = "le",
792 [TCG_COND_GT] = "gt",
793 [TCG_COND_LTU] = "ltu",
794 [TCG_COND_GEU] = "geu",
795 [TCG_COND_LEU] = "leu",
796 [TCG_COND_GTU] = "gtu"
799 void tcg_dump_ops(TCGContext *s, FILE *outfile)
801 const uint16_t *opc_ptr;
802 const TCGArg *args;
803 TCGArg arg;
804 TCGOpcode c;
805 int i, k, nb_oargs, nb_iargs, nb_cargs, first_insn;
806 const TCGOpDef *def;
807 char buf[128];
809 first_insn = 1;
810 opc_ptr = gen_opc_buf;
811 args = gen_opparam_buf;
812 while (opc_ptr < gen_opc_ptr) {
813 c = *opc_ptr++;
814 def = &tcg_op_defs[c];
815 if (c == INDEX_op_debug_insn_start) {
816 uint64_t pc;
817 #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
818 pc = ((uint64_t)args[1] << 32) | args[0];
819 #else
820 pc = args[0];
821 #endif
822 if (!first_insn)
823 fprintf(outfile, "\n");
824 fprintf(outfile, " ---- 0x%" PRIx64, pc);
825 first_insn = 0;
826 nb_oargs = def->nb_oargs;
827 nb_iargs = def->nb_iargs;
828 nb_cargs = def->nb_cargs;
829 } else if (c == INDEX_op_call) {
830 TCGArg arg;
832 /* variable number of arguments */
833 arg = *args++;
834 nb_oargs = arg >> 16;
835 nb_iargs = arg & 0xffff;
836 nb_cargs = def->nb_cargs;
838 fprintf(outfile, " %s ", def->name);
840 /* function name */
841 fprintf(outfile, "%s",
842 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1]));
843 /* flags */
844 fprintf(outfile, ",$0x%" TCG_PRIlx,
845 args[nb_oargs + nb_iargs]);
846 /* nb out args */
847 fprintf(outfile, ",$%d", nb_oargs);
848 for(i = 0; i < nb_oargs; i++) {
849 fprintf(outfile, ",");
850 fprintf(outfile, "%s",
851 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i]));
853 for(i = 0; i < (nb_iargs - 1); i++) {
854 fprintf(outfile, ",");
855 if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) {
856 fprintf(outfile, "<dummy>");
857 } else {
858 fprintf(outfile, "%s",
859 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i]));
862 } else if (c == INDEX_op_movi_i32
863 #if TCG_TARGET_REG_BITS == 64
864 || c == INDEX_op_movi_i64
865 #endif
867 tcg_target_ulong val;
868 TCGHelperInfo *th;
870 nb_oargs = def->nb_oargs;
871 nb_iargs = def->nb_iargs;
872 nb_cargs = def->nb_cargs;
873 fprintf(outfile, " %s %s,$", def->name,
874 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0]));
875 val = args[1];
876 th = tcg_find_helper(s, val);
877 if (th) {
878 fprintf(outfile, "%s", th->name);
879 } else {
880 if (c == INDEX_op_movi_i32)
881 fprintf(outfile, "0x%x", (uint32_t)val);
882 else
883 fprintf(outfile, "0x%" PRIx64 , (uint64_t)val);
885 } else {
886 fprintf(outfile, " %s ", def->name);
887 if (c == INDEX_op_nopn) {
888 /* variable number of arguments */
889 nb_cargs = *args;
890 nb_oargs = 0;
891 nb_iargs = 0;
892 } else {
893 nb_oargs = def->nb_oargs;
894 nb_iargs = def->nb_iargs;
895 nb_cargs = def->nb_cargs;
898 k = 0;
899 for(i = 0; i < nb_oargs; i++) {
900 if (k != 0)
901 fprintf(outfile, ",");
902 fprintf(outfile, "%s",
903 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
905 for(i = 0; i < nb_iargs; i++) {
906 if (k != 0)
907 fprintf(outfile, ",");
908 fprintf(outfile, "%s",
909 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
911 switch (c) {
912 case INDEX_op_brcond_i32:
913 #if TCG_TARGET_REG_BITS == 32
914 case INDEX_op_brcond2_i32:
915 #elif TCG_TARGET_REG_BITS == 64
916 case INDEX_op_brcond_i64:
917 #endif
918 case INDEX_op_setcond_i32:
919 #if TCG_TARGET_REG_BITS == 32
920 case INDEX_op_setcond2_i32:
921 #elif TCG_TARGET_REG_BITS == 64
922 case INDEX_op_setcond_i64:
923 #endif
924 if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]])
925 fprintf(outfile, ",%s", cond_name[args[k++]]);
926 else
927 fprintf(outfile, ",$0x%" TCG_PRIlx, args[k++]);
928 i = 1;
929 break;
930 default:
931 i = 0;
932 break;
934 for(; i < nb_cargs; i++) {
935 if (k != 0)
936 fprintf(outfile, ",");
937 arg = args[k++];
938 fprintf(outfile, "$0x%" TCG_PRIlx, arg);
941 fprintf(outfile, "\n");
942 args += nb_iargs + nb_oargs + nb_cargs;
946 /* we give more priority to constraints with less registers */
947 static int get_constraint_priority(const TCGOpDef *def, int k)
949 const TCGArgConstraint *arg_ct;
951 int i, n;
952 arg_ct = &def->args_ct[k];
953 if (arg_ct->ct & TCG_CT_ALIAS) {
954 /* an alias is equivalent to a single register */
955 n = 1;
956 } else {
957 if (!(arg_ct->ct & TCG_CT_REG))
958 return 0;
959 n = 0;
960 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
961 if (tcg_regset_test_reg(arg_ct->u.regs, i))
962 n++;
965 return TCG_TARGET_NB_REGS - n + 1;
968 /* sort from highest priority to lowest */
969 static void sort_constraints(TCGOpDef *def, int start, int n)
971 int i, j, p1, p2, tmp;
973 for(i = 0; i < n; i++)
974 def->sorted_args[start + i] = start + i;
975 if (n <= 1)
976 return;
977 for(i = 0; i < n - 1; i++) {
978 for(j = i + 1; j < n; j++) {
979 p1 = get_constraint_priority(def, def->sorted_args[start + i]);
980 p2 = get_constraint_priority(def, def->sorted_args[start + j]);
981 if (p1 < p2) {
982 tmp = def->sorted_args[start + i];
983 def->sorted_args[start + i] = def->sorted_args[start + j];
984 def->sorted_args[start + j] = tmp;
990 void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
992 TCGOpcode op;
993 TCGOpDef *def;
994 const char *ct_str;
995 int i, nb_args;
997 for(;;) {
998 if (tdefs->op == (TCGOpcode)-1)
999 break;
1000 op = tdefs->op;
1001 assert(op >= 0 && op < NB_OPS);
1002 def = &tcg_op_defs[op];
1003 #if defined(CONFIG_DEBUG_TCG)
1004 /* Duplicate entry in op definitions? */
1005 assert(!def->used);
1006 def->used = 1;
1007 #endif
1008 nb_args = def->nb_iargs + def->nb_oargs;
1009 for(i = 0; i < nb_args; i++) {
1010 ct_str = tdefs->args_ct_str[i];
1011 /* Incomplete TCGTargetOpDef entry? */
1012 assert(ct_str != NULL);
1013 tcg_regset_clear(def->args_ct[i].u.regs);
1014 def->args_ct[i].ct = 0;
1015 if (ct_str[0] >= '0' && ct_str[0] <= '9') {
1016 int oarg;
1017 oarg = ct_str[0] - '0';
1018 assert(oarg < def->nb_oargs);
1019 assert(def->args_ct[oarg].ct & TCG_CT_REG);
1020 /* TCG_CT_ALIAS is for the output arguments. The input
1021 argument is tagged with TCG_CT_IALIAS. */
1022 def->args_ct[i] = def->args_ct[oarg];
1023 def->args_ct[oarg].ct = TCG_CT_ALIAS;
1024 def->args_ct[oarg].alias_index = i;
1025 def->args_ct[i].ct |= TCG_CT_IALIAS;
1026 def->args_ct[i].alias_index = oarg;
1027 } else {
1028 for(;;) {
1029 if (*ct_str == '\0')
1030 break;
1031 switch(*ct_str) {
1032 case 'i':
1033 def->args_ct[i].ct |= TCG_CT_CONST;
1034 ct_str++;
1035 break;
1036 default:
1037 if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) {
1038 fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n",
1039 ct_str, i, def->name);
1040 exit(1);
1047 /* TCGTargetOpDef entry with too much information? */
1048 assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
1050 /* sort the constraints (XXX: this is just an heuristic) */
1051 sort_constraints(def, 0, def->nb_oargs);
1052 sort_constraints(def, def->nb_oargs, def->nb_iargs);
1054 #if 0
1056 int i;
1058 printf("%s: sorted=", def->name);
1059 for(i = 0; i < def->nb_oargs + def->nb_iargs; i++)
1060 printf(" %d", def->sorted_args[i]);
1061 printf("\n");
1063 #endif
1064 tdefs++;
1067 #if defined(CONFIG_DEBUG_TCG)
1068 i = 0;
1069 for (op = 0; op < ARRAY_SIZE(tcg_op_defs); op++) {
1070 if (op < INDEX_op_call || op == INDEX_op_debug_insn_start) {
1071 /* Wrong entry in op definitions? */
1072 if (tcg_op_defs[op].used) {
1073 fprintf(stderr, "Invalid op definition for %s\n",
1074 tcg_op_defs[op].name);
1075 i = 1;
1077 } else {
1078 /* Missing entry in op definitions? */
1079 if (!tcg_op_defs[op].used) {
1080 fprintf(stderr, "Missing op definition for %s\n",
1081 tcg_op_defs[op].name);
1082 i = 1;
1086 if (i == 1) {
1087 tcg_abort();
1089 #endif
1092 #ifdef USE_LIVENESS_ANALYSIS
1094 /* set a nop for an operation using 'nb_args' */
1095 static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr,
1096 TCGArg *args, int nb_args)
1098 if (nb_args == 0) {
1099 *opc_ptr = INDEX_op_nop;
1100 } else {
1101 *opc_ptr = INDEX_op_nopn;
1102 args[0] = nb_args;
1103 args[nb_args - 1] = nb_args;
1107 /* liveness analysis: end of function: globals are live, temps are
1108 dead. */
1109 /* XXX: at this stage, not used as there would be little gains because
1110 most TBs end with a conditional jump. */
1111 static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps)
1113 memset(dead_temps, 0, s->nb_globals);
1114 memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals);
1117 /* liveness analysis: end of basic block: globals are live, temps are
1118 dead, local temps are live. */
1119 static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps)
1121 int i;
1122 TCGTemp *ts;
1124 memset(dead_temps, 0, s->nb_globals);
1125 ts = &s->temps[s->nb_globals];
1126 for(i = s->nb_globals; i < s->nb_temps; i++) {
1127 if (ts->temp_local)
1128 dead_temps[i] = 0;
1129 else
1130 dead_temps[i] = 1;
1131 ts++;
1135 /* Liveness analysis : update the opc_dead_iargs array to tell if a
1136 given input arguments is dead. Instructions updating dead
1137 temporaries are removed. */
1138 static void tcg_liveness_analysis(TCGContext *s)
1140 int i, op_index, nb_args, nb_iargs, nb_oargs, arg, nb_ops;
1141 TCGOpcode op;
1142 TCGArg *args;
1143 const TCGOpDef *def;
1144 uint8_t *dead_temps;
1145 unsigned int dead_iargs;
1147 gen_opc_ptr++; /* skip end */
1149 nb_ops = gen_opc_ptr - gen_opc_buf;
1151 s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
1153 dead_temps = tcg_malloc(s->nb_temps);
1154 memset(dead_temps, 1, s->nb_temps);
1156 args = gen_opparam_ptr;
1157 op_index = nb_ops - 1;
1158 while (op_index >= 0) {
1159 op = gen_opc_buf[op_index];
1160 def = &tcg_op_defs[op];
1161 switch(op) {
1162 case INDEX_op_call:
1164 int call_flags;
1166 nb_args = args[-1];
1167 args -= nb_args;
1168 nb_iargs = args[0] & 0xffff;
1169 nb_oargs = args[0] >> 16;
1170 args++;
1171 call_flags = args[nb_oargs + nb_iargs];
1173 /* pure functions can be removed if their result is not
1174 used */
1175 if (call_flags & TCG_CALL_PURE) {
1176 for(i = 0; i < nb_oargs; i++) {
1177 arg = args[i];
1178 if (!dead_temps[arg])
1179 goto do_not_remove_call;
1181 tcg_set_nop(s, gen_opc_buf + op_index,
1182 args - 1, nb_args);
1183 } else {
1184 do_not_remove_call:
1186 /* output args are dead */
1187 for(i = 0; i < nb_oargs; i++) {
1188 arg = args[i];
1189 dead_temps[arg] = 1;
1192 if (!(call_flags & TCG_CALL_CONST)) {
1193 /* globals are live (they may be used by the call) */
1194 memset(dead_temps, 0, s->nb_globals);
1197 /* input args are live */
1198 dead_iargs = 0;
1199 for(i = 0; i < nb_iargs; i++) {
1200 arg = args[i + nb_oargs];
1201 if (arg != TCG_CALL_DUMMY_ARG) {
1202 if (dead_temps[arg]) {
1203 dead_iargs |= (1 << i);
1205 dead_temps[arg] = 0;
1208 s->op_dead_iargs[op_index] = dead_iargs;
1210 args--;
1212 break;
1213 case INDEX_op_set_label:
1214 args--;
1215 /* mark end of basic block */
1216 tcg_la_bb_end(s, dead_temps);
1217 break;
1218 case INDEX_op_debug_insn_start:
1219 args -= def->nb_args;
1220 break;
1221 case INDEX_op_nopn:
1222 nb_args = args[-1];
1223 args -= nb_args;
1224 break;
1225 case INDEX_op_discard:
1226 args--;
1227 /* mark the temporary as dead */
1228 dead_temps[args[0]] = 1;
1229 break;
1230 case INDEX_op_end:
1231 break;
1232 /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1233 default:
1234 args -= def->nb_args;
1235 nb_iargs = def->nb_iargs;
1236 nb_oargs = def->nb_oargs;
1238 /* Test if the operation can be removed because all
1239 its outputs are dead. We assume that nb_oargs == 0
1240 implies side effects */
1241 if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
1242 for(i = 0; i < nb_oargs; i++) {
1243 arg = args[i];
1244 if (!dead_temps[arg])
1245 goto do_not_remove;
1247 tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args);
1248 #ifdef CONFIG_PROFILER
1249 s->del_op_count++;
1250 #endif
1251 } else {
1252 do_not_remove:
1254 /* output args are dead */
1255 for(i = 0; i < nb_oargs; i++) {
1256 arg = args[i];
1257 dead_temps[arg] = 1;
1260 /* if end of basic block, update */
1261 if (def->flags & TCG_OPF_BB_END) {
1262 tcg_la_bb_end(s, dead_temps);
1263 } else if (def->flags & TCG_OPF_CALL_CLOBBER) {
1264 /* globals are live */
1265 memset(dead_temps, 0, s->nb_globals);
1268 /* input args are live */
1269 dead_iargs = 0;
1270 for(i = 0; i < nb_iargs; i++) {
1271 arg = args[i + nb_oargs];
1272 if (dead_temps[arg]) {
1273 dead_iargs |= (1 << i);
1275 dead_temps[arg] = 0;
1277 s->op_dead_iargs[op_index] = dead_iargs;
1279 break;
1281 op_index--;
1284 if (args != gen_opparam_buf)
1285 tcg_abort();
1287 #else
1288 /* dummy liveness analysis */
1289 static void tcg_liveness_analysis(TCGContext *s)
1291 int nb_ops;
1292 nb_ops = gen_opc_ptr - gen_opc_buf;
1294 s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
1295 memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t));
1297 #endif
1299 #ifndef NDEBUG
1300 static void dump_regs(TCGContext *s)
1302 TCGTemp *ts;
1303 int i;
1304 char buf[64];
1306 for(i = 0; i < s->nb_temps; i++) {
1307 ts = &s->temps[i];
1308 printf(" %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i));
1309 switch(ts->val_type) {
1310 case TEMP_VAL_REG:
1311 printf("%s", tcg_target_reg_names[ts->reg]);
1312 break;
1313 case TEMP_VAL_MEM:
1314 printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]);
1315 break;
1316 case TEMP_VAL_CONST:
1317 printf("$0x%" TCG_PRIlx, ts->val);
1318 break;
1319 case TEMP_VAL_DEAD:
1320 printf("D");
1321 break;
1322 default:
1323 printf("???");
1324 break;
1326 printf("\n");
1329 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
1330 if (s->reg_to_temp[i] >= 0) {
1331 printf("%s: %s\n",
1332 tcg_target_reg_names[i],
1333 tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i]));
1338 static void check_regs(TCGContext *s)
1340 int reg, k;
1341 TCGTemp *ts;
1342 char buf[64];
1344 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1345 k = s->reg_to_temp[reg];
1346 if (k >= 0) {
1347 ts = &s->temps[k];
1348 if (ts->val_type != TEMP_VAL_REG ||
1349 ts->reg != reg) {
1350 printf("Inconsistency for register %s:\n",
1351 tcg_target_reg_names[reg]);
1352 goto fail;
1356 for(k = 0; k < s->nb_temps; k++) {
1357 ts = &s->temps[k];
1358 if (ts->val_type == TEMP_VAL_REG &&
1359 !ts->fixed_reg &&
1360 s->reg_to_temp[ts->reg] != k) {
1361 printf("Inconsistency for temp %s:\n",
1362 tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
1363 fail:
1364 printf("reg state:\n");
1365 dump_regs(s);
1366 tcg_abort();
1370 #endif
1372 static void temp_allocate_frame(TCGContext *s, int temp)
1374 TCGTemp *ts;
1375 ts = &s->temps[temp];
1376 s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1);
1377 if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end)
1378 tcg_abort();
1379 ts->mem_offset = s->current_frame_offset;
1380 ts->mem_reg = s->frame_reg;
1381 ts->mem_allocated = 1;
1382 s->current_frame_offset += sizeof(tcg_target_long);
1385 /* free register 'reg' by spilling the corresponding temporary if necessary */
1386 static void tcg_reg_free(TCGContext *s, int reg)
1388 TCGTemp *ts;
1389 int temp;
1391 temp = s->reg_to_temp[reg];
1392 if (temp != -1) {
1393 ts = &s->temps[temp];
1394 assert(ts->val_type == TEMP_VAL_REG);
1395 if (!ts->mem_coherent) {
1396 if (!ts->mem_allocated)
1397 temp_allocate_frame(s, temp);
1398 tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1400 ts->val_type = TEMP_VAL_MEM;
1401 s->reg_to_temp[reg] = -1;
1405 /* Allocate a register belonging to reg1 & ~reg2 */
1406 static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2)
1408 int i, reg;
1409 TCGRegSet reg_ct;
1411 tcg_regset_andnot(reg_ct, reg1, reg2);
1413 /* first try free registers */
1414 for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
1415 reg = tcg_target_reg_alloc_order[i];
1416 if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1)
1417 return reg;
1420 /* XXX: do better spill choice */
1421 for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
1422 reg = tcg_target_reg_alloc_order[i];
1423 if (tcg_regset_test_reg(reg_ct, reg)) {
1424 tcg_reg_free(s, reg);
1425 return reg;
1429 tcg_abort();
1432 /* save a temporary to memory. 'allocated_regs' is used in case a
1433 temporary registers needs to be allocated to store a constant. */
1434 static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs)
1436 TCGTemp *ts;
1437 int reg;
1439 ts = &s->temps[temp];
1440 if (!ts->fixed_reg) {
1441 switch(ts->val_type) {
1442 case TEMP_VAL_REG:
1443 tcg_reg_free(s, ts->reg);
1444 break;
1445 case TEMP_VAL_DEAD:
1446 ts->val_type = TEMP_VAL_MEM;
1447 break;
1448 case TEMP_VAL_CONST:
1449 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1450 allocated_regs);
1451 if (!ts->mem_allocated)
1452 temp_allocate_frame(s, temp);
1453 tcg_out_movi(s, ts->type, reg, ts->val);
1454 tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1455 ts->val_type = TEMP_VAL_MEM;
1456 break;
1457 case TEMP_VAL_MEM:
1458 break;
1459 default:
1460 tcg_abort();
1465 /* save globals to their cannonical location and assume they can be
1466 modified be the following code. 'allocated_regs' is used in case a
1467 temporary registers needs to be allocated to store a constant. */
1468 static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
1470 int i;
1472 for(i = 0; i < s->nb_globals; i++) {
1473 temp_save(s, i, allocated_regs);
1477 /* at the end of a basic block, we assume all temporaries are dead and
1478 all globals are stored at their canonical location. */
1479 static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
1481 TCGTemp *ts;
1482 int i;
1484 for(i = s->nb_globals; i < s->nb_temps; i++) {
1485 ts = &s->temps[i];
1486 if (ts->temp_local) {
1487 temp_save(s, i, allocated_regs);
1488 } else {
1489 if (ts->val_type == TEMP_VAL_REG) {
1490 s->reg_to_temp[ts->reg] = -1;
1492 ts->val_type = TEMP_VAL_DEAD;
1496 save_globals(s, allocated_regs);
1499 #define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
1501 static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args)
1503 TCGTemp *ots;
1504 tcg_target_ulong val;
1506 ots = &s->temps[args[0]];
1507 val = args[1];
1509 if (ots->fixed_reg) {
1510 /* for fixed registers, we do not do any constant
1511 propagation */
1512 tcg_out_movi(s, ots->type, ots->reg, val);
1513 } else {
1514 /* The movi is not explicitly generated here */
1515 if (ots->val_type == TEMP_VAL_REG)
1516 s->reg_to_temp[ots->reg] = -1;
1517 ots->val_type = TEMP_VAL_CONST;
1518 ots->val = val;
1522 static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
1523 const TCGArg *args,
1524 unsigned int dead_iargs)
1526 TCGTemp *ts, *ots;
1527 int reg;
1528 const TCGArgConstraint *arg_ct;
1530 ots = &s->temps[args[0]];
1531 ts = &s->temps[args[1]];
1532 arg_ct = &def->args_ct[0];
1534 /* XXX: always mark arg dead if IS_DEAD_IARG(0) */
1535 if (ts->val_type == TEMP_VAL_REG) {
1536 if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) {
1537 /* the mov can be suppressed */
1538 if (ots->val_type == TEMP_VAL_REG)
1539 s->reg_to_temp[ots->reg] = -1;
1540 reg = ts->reg;
1541 s->reg_to_temp[reg] = -1;
1542 ts->val_type = TEMP_VAL_DEAD;
1543 } else {
1544 if (ots->val_type == TEMP_VAL_REG) {
1545 reg = ots->reg;
1546 } else {
1547 reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
1549 if (ts->reg != reg) {
1550 tcg_out_mov(s, ots->type, reg, ts->reg);
1553 } else if (ts->val_type == TEMP_VAL_MEM) {
1554 if (ots->val_type == TEMP_VAL_REG) {
1555 reg = ots->reg;
1556 } else {
1557 reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
1559 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1560 } else if (ts->val_type == TEMP_VAL_CONST) {
1561 if (ots->fixed_reg) {
1562 reg = ots->reg;
1563 tcg_out_movi(s, ots->type, reg, ts->val);
1564 } else {
1565 /* propagate constant */
1566 if (ots->val_type == TEMP_VAL_REG)
1567 s->reg_to_temp[ots->reg] = -1;
1568 ots->val_type = TEMP_VAL_CONST;
1569 ots->val = ts->val;
1570 return;
1572 } else {
1573 tcg_abort();
1575 s->reg_to_temp[reg] = args[0];
1576 ots->reg = reg;
1577 ots->val_type = TEMP_VAL_REG;
1578 ots->mem_coherent = 0;
1581 static void tcg_reg_alloc_op(TCGContext *s,
1582 const TCGOpDef *def, TCGOpcode opc,
1583 const TCGArg *args,
1584 unsigned int dead_iargs)
1586 TCGRegSet allocated_regs;
1587 int i, k, nb_iargs, nb_oargs, reg;
1588 TCGArg arg;
1589 const TCGArgConstraint *arg_ct;
1590 TCGTemp *ts;
1591 TCGArg new_args[TCG_MAX_OP_ARGS];
1592 int const_args[TCG_MAX_OP_ARGS];
1594 nb_oargs = def->nb_oargs;
1595 nb_iargs = def->nb_iargs;
1597 /* copy constants */
1598 memcpy(new_args + nb_oargs + nb_iargs,
1599 args + nb_oargs + nb_iargs,
1600 sizeof(TCGArg) * def->nb_cargs);
1602 /* satisfy input constraints */
1603 tcg_regset_set(allocated_regs, s->reserved_regs);
1604 for(k = 0; k < nb_iargs; k++) {
1605 i = def->sorted_args[nb_oargs + k];
1606 arg = args[i];
1607 arg_ct = &def->args_ct[i];
1608 ts = &s->temps[arg];
1609 if (ts->val_type == TEMP_VAL_MEM) {
1610 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1611 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1612 ts->val_type = TEMP_VAL_REG;
1613 ts->reg = reg;
1614 ts->mem_coherent = 1;
1615 s->reg_to_temp[reg] = arg;
1616 } else if (ts->val_type == TEMP_VAL_CONST) {
1617 if (tcg_target_const_match(ts->val, arg_ct)) {
1618 /* constant is OK for instruction */
1619 const_args[i] = 1;
1620 new_args[i] = ts->val;
1621 goto iarg_end;
1622 } else {
1623 /* need to move to a register */
1624 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1625 tcg_out_movi(s, ts->type, reg, ts->val);
1626 ts->val_type = TEMP_VAL_REG;
1627 ts->reg = reg;
1628 ts->mem_coherent = 0;
1629 s->reg_to_temp[reg] = arg;
1632 assert(ts->val_type == TEMP_VAL_REG);
1633 if (arg_ct->ct & TCG_CT_IALIAS) {
1634 if (ts->fixed_reg) {
1635 /* if fixed register, we must allocate a new register
1636 if the alias is not the same register */
1637 if (arg != args[arg_ct->alias_index])
1638 goto allocate_in_reg;
1639 } else {
1640 /* if the input is aliased to an output and if it is
1641 not dead after the instruction, we must allocate
1642 a new register and move it */
1643 if (!IS_DEAD_IARG(i - nb_oargs))
1644 goto allocate_in_reg;
1647 reg = ts->reg;
1648 if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1649 /* nothing to do : the constraint is satisfied */
1650 } else {
1651 allocate_in_reg:
1652 /* allocate a new register matching the constraint
1653 and move the temporary register into it */
1654 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1655 tcg_out_mov(s, ts->type, reg, ts->reg);
1657 new_args[i] = reg;
1658 const_args[i] = 0;
1659 tcg_regset_set_reg(allocated_regs, reg);
1660 iarg_end: ;
1663 if (def->flags & TCG_OPF_BB_END) {
1664 tcg_reg_alloc_bb_end(s, allocated_regs);
1665 } else {
1666 /* mark dead temporaries and free the associated registers */
1667 for(i = 0; i < nb_iargs; i++) {
1668 arg = args[nb_oargs + i];
1669 if (IS_DEAD_IARG(i)) {
1670 ts = &s->temps[arg];
1671 if (!ts->fixed_reg) {
1672 if (ts->val_type == TEMP_VAL_REG)
1673 s->reg_to_temp[ts->reg] = -1;
1674 ts->val_type = TEMP_VAL_DEAD;
1679 if (def->flags & TCG_OPF_CALL_CLOBBER) {
1680 /* XXX: permit generic clobber register list ? */
1681 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1682 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
1683 tcg_reg_free(s, reg);
1686 /* XXX: for load/store we could do that only for the slow path
1687 (i.e. when a memory callback is called) */
1689 /* store globals and free associated registers (we assume the insn
1690 can modify any global. */
1691 save_globals(s, allocated_regs);
1694 /* satisfy the output constraints */
1695 tcg_regset_set(allocated_regs, s->reserved_regs);
1696 for(k = 0; k < nb_oargs; k++) {
1697 i = def->sorted_args[k];
1698 arg = args[i];
1699 arg_ct = &def->args_ct[i];
1700 ts = &s->temps[arg];
1701 if (arg_ct->ct & TCG_CT_ALIAS) {
1702 reg = new_args[arg_ct->alias_index];
1703 } else {
1704 /* if fixed register, we try to use it */
1705 reg = ts->reg;
1706 if (ts->fixed_reg &&
1707 tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1708 goto oarg_end;
1710 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1712 tcg_regset_set_reg(allocated_regs, reg);
1713 /* if a fixed register is used, then a move will be done afterwards */
1714 if (!ts->fixed_reg) {
1715 if (ts->val_type == TEMP_VAL_REG)
1716 s->reg_to_temp[ts->reg] = -1;
1717 ts->val_type = TEMP_VAL_REG;
1718 ts->reg = reg;
1719 /* temp value is modified, so the value kept in memory is
1720 potentially not the same */
1721 ts->mem_coherent = 0;
1722 s->reg_to_temp[reg] = arg;
1724 oarg_end:
1725 new_args[i] = reg;
1729 /* emit instruction */
1730 tcg_out_op(s, opc, new_args, const_args);
1732 /* move the outputs in the correct register if needed */
1733 for(i = 0; i < nb_oargs; i++) {
1734 ts = &s->temps[args[i]];
1735 reg = new_args[i];
1736 if (ts->fixed_reg && ts->reg != reg) {
1737 tcg_out_mov(s, ts->type, ts->reg, reg);
1742 #ifdef TCG_TARGET_STACK_GROWSUP
1743 #define STACK_DIR(x) (-(x))
1744 #else
1745 #define STACK_DIR(x) (x)
1746 #endif
1748 static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
1749 TCGOpcode opc, const TCGArg *args,
1750 unsigned int dead_iargs)
1752 int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params;
1753 TCGArg arg, func_arg;
1754 TCGTemp *ts;
1755 tcg_target_long stack_offset, call_stack_size, func_addr;
1756 int const_func_arg, allocate_args;
1757 TCGRegSet allocated_regs;
1758 const TCGArgConstraint *arg_ct;
1760 arg = *args++;
1762 nb_oargs = arg >> 16;
1763 nb_iargs = arg & 0xffff;
1764 nb_params = nb_iargs - 1;
1766 flags = args[nb_oargs + nb_iargs];
1768 nb_regs = tcg_target_get_call_iarg_regs_count(flags);
1769 if (nb_regs > nb_params)
1770 nb_regs = nb_params;
1772 /* assign stack slots first */
1773 /* XXX: preallocate call stack */
1774 call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);
1775 call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
1776 ~(TCG_TARGET_STACK_ALIGN - 1);
1777 allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
1778 if (allocate_args) {
1779 tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size));
1782 stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
1783 for(i = nb_regs; i < nb_params; i++) {
1784 arg = args[nb_oargs + i];
1785 #ifdef TCG_TARGET_STACK_GROWSUP
1786 stack_offset -= sizeof(tcg_target_long);
1787 #endif
1788 if (arg != TCG_CALL_DUMMY_ARG) {
1789 ts = &s->temps[arg];
1790 if (ts->val_type == TEMP_VAL_REG) {
1791 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
1792 } else if (ts->val_type == TEMP_VAL_MEM) {
1793 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1794 s->reserved_regs);
1795 /* XXX: not correct if reading values from the stack */
1796 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1797 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
1798 } else if (ts->val_type == TEMP_VAL_CONST) {
1799 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1800 s->reserved_regs);
1801 /* XXX: sign extend may be needed on some targets */
1802 tcg_out_movi(s, ts->type, reg, ts->val);
1803 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
1804 } else {
1805 tcg_abort();
1808 #ifndef TCG_TARGET_STACK_GROWSUP
1809 stack_offset += sizeof(tcg_target_long);
1810 #endif
1813 /* assign input registers */
1814 tcg_regset_set(allocated_regs, s->reserved_regs);
1815 for(i = 0; i < nb_regs; i++) {
1816 arg = args[nb_oargs + i];
1817 if (arg != TCG_CALL_DUMMY_ARG) {
1818 ts = &s->temps[arg];
1819 reg = tcg_target_call_iarg_regs[i];
1820 tcg_reg_free(s, reg);
1821 if (ts->val_type == TEMP_VAL_REG) {
1822 if (ts->reg != reg) {
1823 tcg_out_mov(s, ts->type, reg, ts->reg);
1825 } else if (ts->val_type == TEMP_VAL_MEM) {
1826 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1827 } else if (ts->val_type == TEMP_VAL_CONST) {
1828 /* XXX: sign extend ? */
1829 tcg_out_movi(s, ts->type, reg, ts->val);
1830 } else {
1831 tcg_abort();
1833 tcg_regset_set_reg(allocated_regs, reg);
1837 /* assign function address */
1838 func_arg = args[nb_oargs + nb_iargs - 1];
1839 arg_ct = &def->args_ct[0];
1840 ts = &s->temps[func_arg];
1841 func_addr = ts->val;
1842 const_func_arg = 0;
1843 if (ts->val_type == TEMP_VAL_MEM) {
1844 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1845 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1846 func_arg = reg;
1847 tcg_regset_set_reg(allocated_regs, reg);
1848 } else if (ts->val_type == TEMP_VAL_REG) {
1849 reg = ts->reg;
1850 if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1851 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1852 tcg_out_mov(s, ts->type, reg, ts->reg);
1854 func_arg = reg;
1855 tcg_regset_set_reg(allocated_regs, reg);
1856 } else if (ts->val_type == TEMP_VAL_CONST) {
1857 if (tcg_target_const_match(func_addr, arg_ct)) {
1858 const_func_arg = 1;
1859 func_arg = func_addr;
1860 } else {
1861 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1862 tcg_out_movi(s, ts->type, reg, func_addr);
1863 func_arg = reg;
1864 tcg_regset_set_reg(allocated_regs, reg);
1866 } else {
1867 tcg_abort();
1871 /* mark dead temporaries and free the associated registers */
1872 for(i = 0; i < nb_iargs; i++) {
1873 arg = args[nb_oargs + i];
1874 if (IS_DEAD_IARG(i)) {
1875 ts = &s->temps[arg];
1876 if (!ts->fixed_reg) {
1877 if (ts->val_type == TEMP_VAL_REG)
1878 s->reg_to_temp[ts->reg] = -1;
1879 ts->val_type = TEMP_VAL_DEAD;
1884 /* clobber call registers */
1885 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1886 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
1887 tcg_reg_free(s, reg);
1891 /* store globals and free associated registers (we assume the call
1892 can modify any global. */
1893 if (!(flags & TCG_CALL_CONST)) {
1894 save_globals(s, allocated_regs);
1897 tcg_out_op(s, opc, &func_arg, &const_func_arg);
1899 if (allocate_args) {
1900 tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size));
1903 /* assign output registers and emit moves if needed */
1904 for(i = 0; i < nb_oargs; i++) {
1905 arg = args[i];
1906 ts = &s->temps[arg];
1907 reg = tcg_target_call_oarg_regs[i];
1908 assert(s->reg_to_temp[reg] == -1);
1909 if (ts->fixed_reg) {
1910 if (ts->reg != reg) {
1911 tcg_out_mov(s, ts->type, ts->reg, reg);
1913 } else {
1914 if (ts->val_type == TEMP_VAL_REG)
1915 s->reg_to_temp[ts->reg] = -1;
1916 ts->val_type = TEMP_VAL_REG;
1917 ts->reg = reg;
1918 ts->mem_coherent = 0;
1919 s->reg_to_temp[reg] = arg;
1923 return nb_iargs + nb_oargs + def->nb_cargs + 1;
1926 #ifdef CONFIG_PROFILER
1928 static int64_t tcg_table_op_count[NB_OPS];
1930 static void dump_op_count(void)
1932 int i;
1933 FILE *f;
1934 f = fopen("/tmp/op.log", "w");
1935 for(i = INDEX_op_end; i < NB_OPS; i++) {
1936 fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, tcg_table_op_count[i]);
1938 fclose(f);
1940 #endif
1943 static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
1944 long search_pc)
1946 TCGOpcode opc;
1947 int op_index;
1948 const TCGOpDef *def;
1949 unsigned int dead_iargs;
1950 const TCGArg *args;
1952 #ifdef DEBUG_DISAS
1953 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
1954 qemu_log("OP:\n");
1955 tcg_dump_ops(s, logfile);
1956 qemu_log("\n");
1958 #endif
1960 #ifdef CONFIG_PROFILER
1961 s->la_time -= profile_getclock();
1962 #endif
1963 tcg_liveness_analysis(s);
1964 #ifdef CONFIG_PROFILER
1965 s->la_time += profile_getclock();
1966 #endif
1968 #ifdef DEBUG_DISAS
1969 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) {
1970 qemu_log("OP after liveness analysis:\n");
1971 tcg_dump_ops(s, logfile);
1972 qemu_log("\n");
1974 #endif
1976 tcg_reg_alloc_start(s);
1978 s->code_buf = gen_code_buf;
1979 s->code_ptr = gen_code_buf;
1981 args = gen_opparam_buf;
1982 op_index = 0;
1984 for(;;) {
1985 opc = gen_opc_buf[op_index];
1986 #ifdef CONFIG_PROFILER
1987 tcg_table_op_count[opc]++;
1988 #endif
1989 def = &tcg_op_defs[opc];
1990 #if 0
1991 printf("%s: %d %d %d\n", def->name,
1992 def->nb_oargs, def->nb_iargs, def->nb_cargs);
1993 // dump_regs(s);
1994 #endif
1995 switch(opc) {
1996 case INDEX_op_mov_i32:
1997 #if TCG_TARGET_REG_BITS == 64
1998 case INDEX_op_mov_i64:
1999 #endif
2000 dead_iargs = s->op_dead_iargs[op_index];
2001 tcg_reg_alloc_mov(s, def, args, dead_iargs);
2002 break;
2003 case INDEX_op_movi_i32:
2004 #if TCG_TARGET_REG_BITS == 64
2005 case INDEX_op_movi_i64:
2006 #endif
2007 tcg_reg_alloc_movi(s, args);
2008 break;
2009 case INDEX_op_debug_insn_start:
2010 /* debug instruction */
2011 break;
2012 case INDEX_op_nop:
2013 case INDEX_op_nop1:
2014 case INDEX_op_nop2:
2015 case INDEX_op_nop3:
2016 break;
2017 case INDEX_op_nopn:
2018 args += args[0];
2019 goto next;
2020 case INDEX_op_discard:
2022 TCGTemp *ts;
2023 ts = &s->temps[args[0]];
2024 /* mark the temporary as dead */
2025 if (!ts->fixed_reg) {
2026 if (ts->val_type == TEMP_VAL_REG)
2027 s->reg_to_temp[ts->reg] = -1;
2028 ts->val_type = TEMP_VAL_DEAD;
2031 break;
2032 case INDEX_op_set_label:
2033 tcg_reg_alloc_bb_end(s, s->reserved_regs);
2034 tcg_out_label(s, args[0], (long)s->code_ptr);
2035 break;
2036 case INDEX_op_call:
2037 dead_iargs = s->op_dead_iargs[op_index];
2038 args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs);
2039 goto next;
2040 case INDEX_op_end:
2041 goto the_end;
2042 default:
2043 /* Note: in order to speed up the code, it would be much
2044 faster to have specialized register allocator functions for
2045 some common argument patterns */
2046 dead_iargs = s->op_dead_iargs[op_index];
2047 tcg_reg_alloc_op(s, def, opc, args, dead_iargs);
2048 break;
2050 args += def->nb_args;
2051 next:
2052 if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) {
2053 return op_index;
2055 op_index++;
2056 #ifndef NDEBUG
2057 check_regs(s);
2058 #endif
2060 the_end:
2061 return -1;
2064 int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf)
2066 #ifdef CONFIG_PROFILER
2068 int n;
2069 n = (gen_opc_ptr - gen_opc_buf);
2070 s->op_count += n;
2071 if (n > s->op_count_max)
2072 s->op_count_max = n;
2074 s->temp_count += s->nb_temps;
2075 if (s->nb_temps > s->temp_count_max)
2076 s->temp_count_max = s->nb_temps;
2078 #endif
2080 tcg_gen_code_common(s, gen_code_buf, -1);
2082 /* flush instruction cache */
2083 flush_icache_range((unsigned long)gen_code_buf,
2084 (unsigned long)s->code_ptr);
2085 return s->code_ptr - gen_code_buf;
2088 /* Return the index of the micro operation such as the pc after is <
2089 offset bytes from the start of the TB. The contents of gen_code_buf must
2090 not be changed, though writing the same values is ok.
2091 Return -1 if not found. */
2092 int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset)
2094 return tcg_gen_code_common(s, gen_code_buf, offset);
2097 #ifdef CONFIG_PROFILER
2098 void tcg_dump_info(FILE *f,
2099 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2101 TCGContext *s = &tcg_ctx;
2102 int64_t tot;
2104 tot = s->interm_time + s->code_time;
2105 cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n",
2106 tot, tot / 2.4e9);
2107 cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n",
2108 s->tb_count,
2109 s->tb_count1 - s->tb_count,
2110 s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0);
2111 cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n",
2112 s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max);
2113 cpu_fprintf(f, "deleted ops/TB %0.2f\n",
2114 s->tb_count ?
2115 (double)s->del_op_count / s->tb_count : 0);
2116 cpu_fprintf(f, "avg temps/TB %0.2f max=%d\n",
2117 s->tb_count ?
2118 (double)s->temp_count / s->tb_count : 0,
2119 s->temp_count_max);
2121 cpu_fprintf(f, "cycles/op %0.1f\n",
2122 s->op_count ? (double)tot / s->op_count : 0);
2123 cpu_fprintf(f, "cycles/in byte %0.1f\n",
2124 s->code_in_len ? (double)tot / s->code_in_len : 0);
2125 cpu_fprintf(f, "cycles/out byte %0.1f\n",
2126 s->code_out_len ? (double)tot / s->code_out_len : 0);
2127 if (tot == 0)
2128 tot = 1;
2129 cpu_fprintf(f, " gen_interm time %0.1f%%\n",
2130 (double)s->interm_time / tot * 100.0);
2131 cpu_fprintf(f, " gen_code time %0.1f%%\n",
2132 (double)s->code_time / tot * 100.0);
2133 cpu_fprintf(f, "liveness/code time %0.1f%%\n",
2134 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
2135 cpu_fprintf(f, "cpu_restore count %" PRId64 "\n",
2136 s->restore_count);
2137 cpu_fprintf(f, " avg cycles %0.1f\n",
2138 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
2140 dump_op_count();
2142 #else
2143 void tcg_dump_info(FILE *f,
2144 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2146 cpu_fprintf(f, "[TCG profiler not compiled]\n");
2148 #endif