target-alpha: Fix load-locked/store-conditional.
[qemu/mdroth.git] / tcg / tcg.c
blobbeceff0c3ce9a55a8c300c5b6bb74848685e0d86
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 patch_reloc(uint8_t *code_ptr, int type,
67 tcg_target_long value, tcg_target_long addend);
69 static TCGOpDef tcg_op_defs[] = {
70 #define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size },
71 #define DEF2(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags, 0 },
72 #include "tcg-opc.h"
73 #undef DEF
74 #undef DEF2
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 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);
244 /* init global prologue and epilogue */
245 s->code_buf = code_gen_prologue;
246 s->code_ptr = s->code_buf;
247 tcg_target_qemu_prologue(s);
248 flush_icache_range((unsigned long)s->code_buf,
249 (unsigned long)s->code_ptr);
252 void tcg_set_frame(TCGContext *s, int reg,
253 tcg_target_long start, tcg_target_long size)
255 s->frame_start = start;
256 s->frame_end = start + size;
257 s->frame_reg = reg;
260 void tcg_func_start(TCGContext *s)
262 int i;
263 tcg_pool_reset(s);
264 s->nb_temps = s->nb_globals;
265 for(i = 0; i < (TCG_TYPE_COUNT * 2); i++)
266 s->first_free_temp[i] = -1;
267 s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS);
268 s->nb_labels = 0;
269 s->current_frame_offset = s->frame_start;
271 gen_opc_ptr = gen_opc_buf;
272 gen_opparam_ptr = gen_opparam_buf;
275 static inline void tcg_temp_alloc(TCGContext *s, int n)
277 if (n > TCG_MAX_TEMPS)
278 tcg_abort();
281 static inline int tcg_global_reg_new_internal(TCGType type, int reg,
282 const char *name)
284 TCGContext *s = &tcg_ctx;
285 TCGTemp *ts;
286 int idx;
288 #if TCG_TARGET_REG_BITS == 32
289 if (type != TCG_TYPE_I32)
290 tcg_abort();
291 #endif
292 if (tcg_regset_test_reg(s->reserved_regs, reg))
293 tcg_abort();
294 idx = s->nb_globals;
295 tcg_temp_alloc(s, s->nb_globals + 1);
296 ts = &s->temps[s->nb_globals];
297 ts->base_type = type;
298 ts->type = type;
299 ts->fixed_reg = 1;
300 ts->reg = reg;
301 ts->name = name;
302 s->nb_globals++;
303 tcg_regset_set_reg(s->reserved_regs, reg);
304 return idx;
307 TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name)
309 int idx;
311 idx = tcg_global_reg_new_internal(TCG_TYPE_I32, reg, name);
312 return MAKE_TCGV_I32(idx);
315 TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name)
317 int idx;
319 idx = tcg_global_reg_new_internal(TCG_TYPE_I64, reg, name);
320 return MAKE_TCGV_I64(idx);
323 static inline int tcg_global_mem_new_internal(TCGType type, int reg,
324 tcg_target_long offset,
325 const char *name)
327 TCGContext *s = &tcg_ctx;
328 TCGTemp *ts;
329 int idx;
331 idx = s->nb_globals;
332 #if TCG_TARGET_REG_BITS == 32
333 if (type == TCG_TYPE_I64) {
334 char buf[64];
335 tcg_temp_alloc(s, s->nb_globals + 2);
336 ts = &s->temps[s->nb_globals];
337 ts->base_type = type;
338 ts->type = TCG_TYPE_I32;
339 ts->fixed_reg = 0;
340 ts->mem_allocated = 1;
341 ts->mem_reg = reg;
342 #ifdef TCG_TARGET_WORDS_BIGENDIAN
343 ts->mem_offset = offset + 4;
344 #else
345 ts->mem_offset = offset;
346 #endif
347 pstrcpy(buf, sizeof(buf), name);
348 pstrcat(buf, sizeof(buf), "_0");
349 ts->name = strdup(buf);
350 ts++;
352 ts->base_type = type;
353 ts->type = TCG_TYPE_I32;
354 ts->fixed_reg = 0;
355 ts->mem_allocated = 1;
356 ts->mem_reg = reg;
357 #ifdef TCG_TARGET_WORDS_BIGENDIAN
358 ts->mem_offset = offset;
359 #else
360 ts->mem_offset = offset + 4;
361 #endif
362 pstrcpy(buf, sizeof(buf), name);
363 pstrcat(buf, sizeof(buf), "_1");
364 ts->name = strdup(buf);
366 s->nb_globals += 2;
367 } else
368 #endif
370 tcg_temp_alloc(s, s->nb_globals + 1);
371 ts = &s->temps[s->nb_globals];
372 ts->base_type = type;
373 ts->type = type;
374 ts->fixed_reg = 0;
375 ts->mem_allocated = 1;
376 ts->mem_reg = reg;
377 ts->mem_offset = offset;
378 ts->name = name;
379 s->nb_globals++;
381 return idx;
384 TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset,
385 const char *name)
387 int idx;
389 idx = tcg_global_mem_new_internal(TCG_TYPE_I32, reg, offset, name);
390 return MAKE_TCGV_I32(idx);
393 TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset,
394 const char *name)
396 int idx;
398 idx = tcg_global_mem_new_internal(TCG_TYPE_I64, reg, offset, name);
399 return MAKE_TCGV_I64(idx);
402 static inline int tcg_temp_new_internal(TCGType type, int temp_local)
404 TCGContext *s = &tcg_ctx;
405 TCGTemp *ts;
406 int idx, k;
408 k = type;
409 if (temp_local)
410 k += TCG_TYPE_COUNT;
411 idx = s->first_free_temp[k];
412 if (idx != -1) {
413 /* There is already an available temp with the
414 right type */
415 ts = &s->temps[idx];
416 s->first_free_temp[k] = ts->next_free_temp;
417 ts->temp_allocated = 1;
418 assert(ts->temp_local == temp_local);
419 } else {
420 idx = s->nb_temps;
421 #if TCG_TARGET_REG_BITS == 32
422 if (type == TCG_TYPE_I64) {
423 tcg_temp_alloc(s, s->nb_temps + 2);
424 ts = &s->temps[s->nb_temps];
425 ts->base_type = type;
426 ts->type = TCG_TYPE_I32;
427 ts->temp_allocated = 1;
428 ts->temp_local = temp_local;
429 ts->name = NULL;
430 ts++;
431 ts->base_type = TCG_TYPE_I32;
432 ts->type = TCG_TYPE_I32;
433 ts->temp_allocated = 1;
434 ts->temp_local = temp_local;
435 ts->name = NULL;
436 s->nb_temps += 2;
437 } else
438 #endif
440 tcg_temp_alloc(s, s->nb_temps + 1);
441 ts = &s->temps[s->nb_temps];
442 ts->base_type = type;
443 ts->type = type;
444 ts->temp_allocated = 1;
445 ts->temp_local = temp_local;
446 ts->name = NULL;
447 s->nb_temps++;
450 return idx;
453 TCGv_i32 tcg_temp_new_internal_i32(int temp_local)
455 int idx;
457 idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local);
458 return MAKE_TCGV_I32(idx);
461 TCGv_i64 tcg_temp_new_internal_i64(int temp_local)
463 int idx;
465 idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local);
466 return MAKE_TCGV_I64(idx);
469 static inline void tcg_temp_free_internal(int idx)
471 TCGContext *s = &tcg_ctx;
472 TCGTemp *ts;
473 int k;
475 assert(idx >= s->nb_globals && idx < s->nb_temps);
476 ts = &s->temps[idx];
477 assert(ts->temp_allocated != 0);
478 ts->temp_allocated = 0;
479 k = ts->base_type;
480 if (ts->temp_local)
481 k += TCG_TYPE_COUNT;
482 ts->next_free_temp = s->first_free_temp[k];
483 s->first_free_temp[k] = idx;
486 void tcg_temp_free_i32(TCGv_i32 arg)
488 tcg_temp_free_internal(GET_TCGV_I32(arg));
491 void tcg_temp_free_i64(TCGv_i64 arg)
493 tcg_temp_free_internal(GET_TCGV_I64(arg));
496 TCGv_i32 tcg_const_i32(int32_t val)
498 TCGv_i32 t0;
499 t0 = tcg_temp_new_i32();
500 tcg_gen_movi_i32(t0, val);
501 return t0;
504 TCGv_i64 tcg_const_i64(int64_t val)
506 TCGv_i64 t0;
507 t0 = tcg_temp_new_i64();
508 tcg_gen_movi_i64(t0, val);
509 return t0;
512 TCGv_i32 tcg_const_local_i32(int32_t val)
514 TCGv_i32 t0;
515 t0 = tcg_temp_local_new_i32();
516 tcg_gen_movi_i32(t0, val);
517 return t0;
520 TCGv_i64 tcg_const_local_i64(int64_t val)
522 TCGv_i64 t0;
523 t0 = tcg_temp_local_new_i64();
524 tcg_gen_movi_i64(t0, val);
525 return t0;
528 void tcg_register_helper(void *func, const char *name)
530 TCGContext *s = &tcg_ctx;
531 int n;
532 if ((s->nb_helpers + 1) > s->allocated_helpers) {
533 n = s->allocated_helpers;
534 if (n == 0) {
535 n = 4;
536 } else {
537 n *= 2;
539 s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo));
540 s->allocated_helpers = n;
542 s->helpers[s->nb_helpers].func = (tcg_target_ulong)func;
543 s->helpers[s->nb_helpers].name = name;
544 s->nb_helpers++;
547 /* Note: we convert the 64 bit args to 32 bit and do some alignment
548 and endian swap. Maybe it would be better to do the alignment
549 and endian swap in tcg_reg_alloc_call(). */
550 void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
551 int sizemask, TCGArg ret, int nargs, TCGArg *args)
553 #ifdef TCG_TARGET_I386
554 int call_type;
555 #endif
556 int i;
557 int real_args;
558 int nb_rets;
559 TCGArg *nparam;
560 *gen_opc_ptr++ = INDEX_op_call;
561 nparam = gen_opparam_ptr++;
562 #ifdef TCG_TARGET_I386
563 call_type = (flags & TCG_CALL_TYPE_MASK);
564 #endif
565 if (ret != TCG_CALL_DUMMY_ARG) {
566 #if TCG_TARGET_REG_BITS < 64
567 if (sizemask & 1) {
568 #ifdef TCG_TARGET_WORDS_BIGENDIAN
569 *gen_opparam_ptr++ = ret + 1;
570 *gen_opparam_ptr++ = ret;
571 #else
572 *gen_opparam_ptr++ = ret;
573 *gen_opparam_ptr++ = ret + 1;
574 #endif
575 nb_rets = 2;
576 } else
577 #endif
579 *gen_opparam_ptr++ = ret;
580 nb_rets = 1;
582 } else {
583 nb_rets = 0;
585 real_args = 0;
586 for (i = 0; i < nargs; i++) {
587 #if TCG_TARGET_REG_BITS < 64
588 if (sizemask & (2 << i)) {
589 #ifdef TCG_TARGET_I386
590 /* REGPARM case: if the third parameter is 64 bit, it is
591 allocated on the stack */
592 if (i == 2 && call_type == TCG_CALL_TYPE_REGPARM) {
593 call_type = TCG_CALL_TYPE_REGPARM_2;
594 flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type;
596 #endif
597 #ifdef TCG_TARGET_CALL_ALIGN_ARGS
598 /* some targets want aligned 64 bit args */
599 if (real_args & 1) {
600 *gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG;
601 real_args++;
603 #endif
604 /* If stack grows up, then we will be placing successive
605 arguments at lower addresses, which means we need to
606 reverse the order compared to how we would normally
607 treat either big or little-endian. For those arguments
608 that will wind up in registers, this still works for
609 HPPA (the only current STACK_GROWSUP target) since the
610 argument registers are *also* allocated in decreasing
611 order. If another such target is added, this logic may
612 have to get more complicated to differentiate between
613 stack arguments and register arguments. */
614 #if defined(TCG_TARGET_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
615 *gen_opparam_ptr++ = args[i] + 1;
616 *gen_opparam_ptr++ = args[i];
617 #else
618 *gen_opparam_ptr++ = args[i];
619 *gen_opparam_ptr++ = args[i] + 1;
620 #endif
621 real_args += 2;
622 } else
623 #endif
625 *gen_opparam_ptr++ = args[i];
626 real_args++;
629 *gen_opparam_ptr++ = GET_TCGV_PTR(func);
631 *gen_opparam_ptr++ = flags;
633 *nparam = (nb_rets << 16) | (real_args + 1);
635 /* total parameters, needed to go backward in the instruction stream */
636 *gen_opparam_ptr++ = 1 + nb_rets + real_args + 3;
639 #if TCG_TARGET_REG_BITS == 32
640 void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
641 int c, int right, int arith)
643 if (c == 0) {
644 tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
645 tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
646 } else if (c >= 32) {
647 c -= 32;
648 if (right) {
649 if (arith) {
650 tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
651 tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31);
652 } else {
653 tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
654 tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
656 } else {
657 tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c);
658 tcg_gen_movi_i32(TCGV_LOW(ret), 0);
660 } else {
661 TCGv_i32 t0, t1;
663 t0 = tcg_temp_new_i32();
664 t1 = tcg_temp_new_i32();
665 if (right) {
666 tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c);
667 if (arith)
668 tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c);
669 else
670 tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c);
671 tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c);
672 tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0);
673 tcg_gen_mov_i32(TCGV_HIGH(ret), t1);
674 } else {
675 tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c);
676 /* Note: ret can be the same as arg1, so we use t1 */
677 tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c);
678 tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c);
679 tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0);
680 tcg_gen_mov_i32(TCGV_LOW(ret), t1);
682 tcg_temp_free_i32(t0);
683 tcg_temp_free_i32(t1);
686 #endif
689 static void tcg_reg_alloc_start(TCGContext *s)
691 int i;
692 TCGTemp *ts;
693 for(i = 0; i < s->nb_globals; i++) {
694 ts = &s->temps[i];
695 if (ts->fixed_reg) {
696 ts->val_type = TEMP_VAL_REG;
697 } else {
698 ts->val_type = TEMP_VAL_MEM;
701 for(i = s->nb_globals; i < s->nb_temps; i++) {
702 ts = &s->temps[i];
703 ts->val_type = TEMP_VAL_DEAD;
704 ts->mem_allocated = 0;
705 ts->fixed_reg = 0;
707 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
708 s->reg_to_temp[i] = -1;
712 static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size,
713 int idx)
715 TCGTemp *ts;
717 ts = &s->temps[idx];
718 if (idx < s->nb_globals) {
719 pstrcpy(buf, buf_size, ts->name);
720 } else {
721 if (ts->temp_local)
722 snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
723 else
724 snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
726 return buf;
729 char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg)
731 return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I32(arg));
734 char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg)
736 return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I64(arg));
739 static int helper_cmp(const void *p1, const void *p2)
741 const TCGHelperInfo *th1 = p1;
742 const TCGHelperInfo *th2 = p2;
743 if (th1->func < th2->func)
744 return -1;
745 else if (th1->func == th2->func)
746 return 0;
747 else
748 return 1;
751 /* find helper definition (Note: A hash table would be better) */
752 static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val)
754 int m, m_min, m_max;
755 TCGHelperInfo *th;
756 tcg_target_ulong v;
758 if (unlikely(!s->helpers_sorted)) {
759 qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo),
760 helper_cmp);
761 s->helpers_sorted = 1;
764 /* binary search */
765 m_min = 0;
766 m_max = s->nb_helpers - 1;
767 while (m_min <= m_max) {
768 m = (m_min + m_max) >> 1;
769 th = &s->helpers[m];
770 v = th->func;
771 if (v == val)
772 return th;
773 else if (val < v) {
774 m_max = m - 1;
775 } else {
776 m_min = m + 1;
779 return NULL;
782 static const char * const cond_name[] =
784 [TCG_COND_EQ] = "eq",
785 [TCG_COND_NE] = "ne",
786 [TCG_COND_LT] = "lt",
787 [TCG_COND_GE] = "ge",
788 [TCG_COND_LE] = "le",
789 [TCG_COND_GT] = "gt",
790 [TCG_COND_LTU] = "ltu",
791 [TCG_COND_GEU] = "geu",
792 [TCG_COND_LEU] = "leu",
793 [TCG_COND_GTU] = "gtu"
796 void tcg_dump_ops(TCGContext *s, FILE *outfile)
798 const uint16_t *opc_ptr;
799 const TCGArg *args;
800 TCGArg arg;
801 TCGOpcode c;
802 int i, k, nb_oargs, nb_iargs, nb_cargs, first_insn;
803 const TCGOpDef *def;
804 char buf[128];
806 first_insn = 1;
807 opc_ptr = gen_opc_buf;
808 args = gen_opparam_buf;
809 while (opc_ptr < gen_opc_ptr) {
810 c = *opc_ptr++;
811 def = &tcg_op_defs[c];
812 if (c == INDEX_op_debug_insn_start) {
813 uint64_t pc;
814 #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
815 pc = ((uint64_t)args[1] << 32) | args[0];
816 #else
817 pc = args[0];
818 #endif
819 if (!first_insn)
820 fprintf(outfile, "\n");
821 fprintf(outfile, " ---- 0x%" PRIx64, pc);
822 first_insn = 0;
823 nb_oargs = def->nb_oargs;
824 nb_iargs = def->nb_iargs;
825 nb_cargs = def->nb_cargs;
826 } else if (c == INDEX_op_call) {
827 TCGArg arg;
829 /* variable number of arguments */
830 arg = *args++;
831 nb_oargs = arg >> 16;
832 nb_iargs = arg & 0xffff;
833 nb_cargs = def->nb_cargs;
835 fprintf(outfile, " %s ", def->name);
837 /* function name */
838 fprintf(outfile, "%s",
839 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1]));
840 /* flags */
841 fprintf(outfile, ",$0x%" TCG_PRIlx,
842 args[nb_oargs + nb_iargs]);
843 /* nb out args */
844 fprintf(outfile, ",$%d", nb_oargs);
845 for(i = 0; i < nb_oargs; i++) {
846 fprintf(outfile, ",");
847 fprintf(outfile, "%s",
848 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i]));
850 for(i = 0; i < (nb_iargs - 1); i++) {
851 fprintf(outfile, ",");
852 if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) {
853 fprintf(outfile, "<dummy>");
854 } else {
855 fprintf(outfile, "%s",
856 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i]));
859 } else if (c == INDEX_op_movi_i32
860 #if TCG_TARGET_REG_BITS == 64
861 || c == INDEX_op_movi_i64
862 #endif
864 tcg_target_ulong val;
865 TCGHelperInfo *th;
867 nb_oargs = def->nb_oargs;
868 nb_iargs = def->nb_iargs;
869 nb_cargs = def->nb_cargs;
870 fprintf(outfile, " %s %s,$", def->name,
871 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0]));
872 val = args[1];
873 th = tcg_find_helper(s, val);
874 if (th) {
875 fprintf(outfile, "%s", th->name);
876 } else {
877 if (c == INDEX_op_movi_i32)
878 fprintf(outfile, "0x%x", (uint32_t)val);
879 else
880 fprintf(outfile, "0x%" PRIx64 , (uint64_t)val);
882 } else {
883 fprintf(outfile, " %s ", def->name);
884 if (c == INDEX_op_nopn) {
885 /* variable number of arguments */
886 nb_cargs = *args;
887 nb_oargs = 0;
888 nb_iargs = 0;
889 } else {
890 nb_oargs = def->nb_oargs;
891 nb_iargs = def->nb_iargs;
892 nb_cargs = def->nb_cargs;
895 k = 0;
896 for(i = 0; i < nb_oargs; i++) {
897 if (k != 0)
898 fprintf(outfile, ",");
899 fprintf(outfile, "%s",
900 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
902 for(i = 0; i < nb_iargs; i++) {
903 if (k != 0)
904 fprintf(outfile, ",");
905 fprintf(outfile, "%s",
906 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
908 switch (c) {
909 case INDEX_op_brcond_i32:
910 #if TCG_TARGET_REG_BITS == 32
911 case INDEX_op_brcond2_i32:
912 #elif TCG_TARGET_REG_BITS == 64
913 case INDEX_op_brcond_i64:
914 #endif
915 case INDEX_op_setcond_i32:
916 #if TCG_TARGET_REG_BITS == 32
917 case INDEX_op_setcond2_i32:
918 #elif TCG_TARGET_REG_BITS == 64
919 case INDEX_op_setcond_i64:
920 #endif
921 if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]])
922 fprintf(outfile, ",%s", cond_name[args[k++]]);
923 else
924 fprintf(outfile, ",$0x%" TCG_PRIlx, args[k++]);
925 i = 1;
926 break;
927 default:
928 i = 0;
929 break;
931 for(; i < nb_cargs; i++) {
932 if (k != 0)
933 fprintf(outfile, ",");
934 arg = args[k++];
935 fprintf(outfile, "$0x%" TCG_PRIlx, arg);
938 fprintf(outfile, "\n");
939 args += nb_iargs + nb_oargs + nb_cargs;
943 /* we give more priority to constraints with less registers */
944 static int get_constraint_priority(const TCGOpDef *def, int k)
946 const TCGArgConstraint *arg_ct;
948 int i, n;
949 arg_ct = &def->args_ct[k];
950 if (arg_ct->ct & TCG_CT_ALIAS) {
951 /* an alias is equivalent to a single register */
952 n = 1;
953 } else {
954 if (!(arg_ct->ct & TCG_CT_REG))
955 return 0;
956 n = 0;
957 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
958 if (tcg_regset_test_reg(arg_ct->u.regs, i))
959 n++;
962 return TCG_TARGET_NB_REGS - n + 1;
965 /* sort from highest priority to lowest */
966 static void sort_constraints(TCGOpDef *def, int start, int n)
968 int i, j, p1, p2, tmp;
970 for(i = 0; i < n; i++)
971 def->sorted_args[start + i] = start + i;
972 if (n <= 1)
973 return;
974 for(i = 0; i < n - 1; i++) {
975 for(j = i + 1; j < n; j++) {
976 p1 = get_constraint_priority(def, def->sorted_args[start + i]);
977 p2 = get_constraint_priority(def, def->sorted_args[start + j]);
978 if (p1 < p2) {
979 tmp = def->sorted_args[start + i];
980 def->sorted_args[start + i] = def->sorted_args[start + j];
981 def->sorted_args[start + j] = tmp;
987 void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
989 TCGOpcode op;
990 TCGOpDef *def;
991 const char *ct_str;
992 int i, nb_args;
994 for(;;) {
995 if (tdefs->op == (TCGOpcode)-1)
996 break;
997 op = tdefs->op;
998 assert(op >= 0 && op < NB_OPS);
999 def = &tcg_op_defs[op];
1000 #if defined(CONFIG_DEBUG_TCG)
1001 /* Duplicate entry in op definitions? */
1002 assert(!def->used);
1003 def->used = 1;
1004 #endif
1005 nb_args = def->nb_iargs + def->nb_oargs;
1006 for(i = 0; i < nb_args; i++) {
1007 ct_str = tdefs->args_ct_str[i];
1008 /* Incomplete TCGTargetOpDef entry? */
1009 assert(ct_str != NULL);
1010 tcg_regset_clear(def->args_ct[i].u.regs);
1011 def->args_ct[i].ct = 0;
1012 if (ct_str[0] >= '0' && ct_str[0] <= '9') {
1013 int oarg;
1014 oarg = ct_str[0] - '0';
1015 assert(oarg < def->nb_oargs);
1016 assert(def->args_ct[oarg].ct & TCG_CT_REG);
1017 /* TCG_CT_ALIAS is for the output arguments. The input
1018 argument is tagged with TCG_CT_IALIAS. */
1019 def->args_ct[i] = def->args_ct[oarg];
1020 def->args_ct[oarg].ct = TCG_CT_ALIAS;
1021 def->args_ct[oarg].alias_index = i;
1022 def->args_ct[i].ct |= TCG_CT_IALIAS;
1023 def->args_ct[i].alias_index = oarg;
1024 } else {
1025 for(;;) {
1026 if (*ct_str == '\0')
1027 break;
1028 switch(*ct_str) {
1029 case 'i':
1030 def->args_ct[i].ct |= TCG_CT_CONST;
1031 ct_str++;
1032 break;
1033 default:
1034 if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) {
1035 fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n",
1036 ct_str, i, def->name);
1037 exit(1);
1044 /* TCGTargetOpDef entry with too much information? */
1045 assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
1047 /* sort the constraints (XXX: this is just an heuristic) */
1048 sort_constraints(def, 0, def->nb_oargs);
1049 sort_constraints(def, def->nb_oargs, def->nb_iargs);
1051 #if 0
1053 int i;
1055 printf("%s: sorted=", def->name);
1056 for(i = 0; i < def->nb_oargs + def->nb_iargs; i++)
1057 printf(" %d", def->sorted_args[i]);
1058 printf("\n");
1060 #endif
1061 tdefs++;
1064 #if defined(CONFIG_DEBUG_TCG)
1065 i = 0;
1066 for (op = 0; op < ARRAY_SIZE(tcg_op_defs); op++) {
1067 if (op < INDEX_op_call || op == INDEX_op_debug_insn_start) {
1068 /* Wrong entry in op definitions? */
1069 if (tcg_op_defs[op].used) {
1070 fprintf(stderr, "Invalid op definition for %s\n",
1071 tcg_op_defs[op].name);
1072 i = 1;
1074 } else {
1075 /* Missing entry in op definitions? */
1076 if (!tcg_op_defs[op].used) {
1077 fprintf(stderr, "Missing op definition for %s\n",
1078 tcg_op_defs[op].name);
1079 i = 1;
1083 if (i == 1) {
1084 tcg_abort();
1086 #endif
1089 #ifdef USE_LIVENESS_ANALYSIS
1091 /* set a nop for an operation using 'nb_args' */
1092 static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr,
1093 TCGArg *args, int nb_args)
1095 if (nb_args == 0) {
1096 *opc_ptr = INDEX_op_nop;
1097 } else {
1098 *opc_ptr = INDEX_op_nopn;
1099 args[0] = nb_args;
1100 args[nb_args - 1] = nb_args;
1104 /* liveness analysis: end of function: globals are live, temps are
1105 dead. */
1106 /* XXX: at this stage, not used as there would be little gains because
1107 most TBs end with a conditional jump. */
1108 static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps)
1110 memset(dead_temps, 0, s->nb_globals);
1111 memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals);
1114 /* liveness analysis: end of basic block: globals are live, temps are
1115 dead, local temps are live. */
1116 static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps)
1118 int i;
1119 TCGTemp *ts;
1121 memset(dead_temps, 0, s->nb_globals);
1122 ts = &s->temps[s->nb_globals];
1123 for(i = s->nb_globals; i < s->nb_temps; i++) {
1124 if (ts->temp_local)
1125 dead_temps[i] = 0;
1126 else
1127 dead_temps[i] = 1;
1128 ts++;
1132 /* Liveness analysis : update the opc_dead_iargs array to tell if a
1133 given input arguments is dead. Instructions updating dead
1134 temporaries are removed. */
1135 static void tcg_liveness_analysis(TCGContext *s)
1137 int i, op_index, nb_args, nb_iargs, nb_oargs, arg, nb_ops;
1138 TCGOpcode op;
1139 TCGArg *args;
1140 const TCGOpDef *def;
1141 uint8_t *dead_temps;
1142 unsigned int dead_iargs;
1144 gen_opc_ptr++; /* skip end */
1146 nb_ops = gen_opc_ptr - gen_opc_buf;
1148 s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
1150 dead_temps = tcg_malloc(s->nb_temps);
1151 memset(dead_temps, 1, s->nb_temps);
1153 args = gen_opparam_ptr;
1154 op_index = nb_ops - 1;
1155 while (op_index >= 0) {
1156 op = gen_opc_buf[op_index];
1157 def = &tcg_op_defs[op];
1158 switch(op) {
1159 case INDEX_op_call:
1161 int call_flags;
1163 nb_args = args[-1];
1164 args -= nb_args;
1165 nb_iargs = args[0] & 0xffff;
1166 nb_oargs = args[0] >> 16;
1167 args++;
1168 call_flags = args[nb_oargs + nb_iargs];
1170 /* pure functions can be removed if their result is not
1171 used */
1172 if (call_flags & TCG_CALL_PURE) {
1173 for(i = 0; i < nb_oargs; i++) {
1174 arg = args[i];
1175 if (!dead_temps[arg])
1176 goto do_not_remove_call;
1178 tcg_set_nop(s, gen_opc_buf + op_index,
1179 args - 1, nb_args);
1180 } else {
1181 do_not_remove_call:
1183 /* output args are dead */
1184 for(i = 0; i < nb_oargs; i++) {
1185 arg = args[i];
1186 dead_temps[arg] = 1;
1189 if (!(call_flags & TCG_CALL_CONST)) {
1190 /* globals are live (they may be used by the call) */
1191 memset(dead_temps, 0, s->nb_globals);
1194 /* input args are live */
1195 dead_iargs = 0;
1196 for(i = 0; i < nb_iargs; i++) {
1197 arg = args[i + nb_oargs];
1198 if (arg != TCG_CALL_DUMMY_ARG) {
1199 if (dead_temps[arg]) {
1200 dead_iargs |= (1 << i);
1202 dead_temps[arg] = 0;
1205 s->op_dead_iargs[op_index] = dead_iargs;
1207 args--;
1209 break;
1210 case INDEX_op_set_label:
1211 args--;
1212 /* mark end of basic block */
1213 tcg_la_bb_end(s, dead_temps);
1214 break;
1215 case INDEX_op_debug_insn_start:
1216 args -= def->nb_args;
1217 break;
1218 case INDEX_op_nopn:
1219 nb_args = args[-1];
1220 args -= nb_args;
1221 break;
1222 case INDEX_op_discard:
1223 args--;
1224 /* mark the temporary as dead */
1225 dead_temps[args[0]] = 1;
1226 break;
1227 case INDEX_op_end:
1228 break;
1229 /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1230 default:
1231 args -= def->nb_args;
1232 nb_iargs = def->nb_iargs;
1233 nb_oargs = def->nb_oargs;
1235 /* Test if the operation can be removed because all
1236 its outputs are dead. We assume that nb_oargs == 0
1237 implies side effects */
1238 if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
1239 for(i = 0; i < nb_oargs; i++) {
1240 arg = args[i];
1241 if (!dead_temps[arg])
1242 goto do_not_remove;
1244 tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args);
1245 #ifdef CONFIG_PROFILER
1246 s->del_op_count++;
1247 #endif
1248 } else {
1249 do_not_remove:
1251 /* output args are dead */
1252 for(i = 0; i < nb_oargs; i++) {
1253 arg = args[i];
1254 dead_temps[arg] = 1;
1257 /* if end of basic block, update */
1258 if (def->flags & TCG_OPF_BB_END) {
1259 tcg_la_bb_end(s, dead_temps);
1260 } else if (def->flags & TCG_OPF_CALL_CLOBBER) {
1261 /* globals are live */
1262 memset(dead_temps, 0, s->nb_globals);
1265 /* input args are live */
1266 dead_iargs = 0;
1267 for(i = 0; i < nb_iargs; i++) {
1268 arg = args[i + nb_oargs];
1269 if (dead_temps[arg]) {
1270 dead_iargs |= (1 << i);
1272 dead_temps[arg] = 0;
1274 s->op_dead_iargs[op_index] = dead_iargs;
1276 break;
1278 op_index--;
1281 if (args != gen_opparam_buf)
1282 tcg_abort();
1284 #else
1285 /* dummy liveness analysis */
1286 static void tcg_liveness_analysis(TCGContext *s)
1288 int nb_ops;
1289 nb_ops = gen_opc_ptr - gen_opc_buf;
1291 s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
1292 memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t));
1294 #endif
1296 #ifndef NDEBUG
1297 static void dump_regs(TCGContext *s)
1299 TCGTemp *ts;
1300 int i;
1301 char buf[64];
1303 for(i = 0; i < s->nb_temps; i++) {
1304 ts = &s->temps[i];
1305 printf(" %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i));
1306 switch(ts->val_type) {
1307 case TEMP_VAL_REG:
1308 printf("%s", tcg_target_reg_names[ts->reg]);
1309 break;
1310 case TEMP_VAL_MEM:
1311 printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]);
1312 break;
1313 case TEMP_VAL_CONST:
1314 printf("$0x%" TCG_PRIlx, ts->val);
1315 break;
1316 case TEMP_VAL_DEAD:
1317 printf("D");
1318 break;
1319 default:
1320 printf("???");
1321 break;
1323 printf("\n");
1326 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
1327 if (s->reg_to_temp[i] >= 0) {
1328 printf("%s: %s\n",
1329 tcg_target_reg_names[i],
1330 tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i]));
1335 static void check_regs(TCGContext *s)
1337 int reg, k;
1338 TCGTemp *ts;
1339 char buf[64];
1341 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1342 k = s->reg_to_temp[reg];
1343 if (k >= 0) {
1344 ts = &s->temps[k];
1345 if (ts->val_type != TEMP_VAL_REG ||
1346 ts->reg != reg) {
1347 printf("Inconsistency for register %s:\n",
1348 tcg_target_reg_names[reg]);
1349 goto fail;
1353 for(k = 0; k < s->nb_temps; k++) {
1354 ts = &s->temps[k];
1355 if (ts->val_type == TEMP_VAL_REG &&
1356 !ts->fixed_reg &&
1357 s->reg_to_temp[ts->reg] != k) {
1358 printf("Inconsistency for temp %s:\n",
1359 tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
1360 fail:
1361 printf("reg state:\n");
1362 dump_regs(s);
1363 tcg_abort();
1367 #endif
1369 static void temp_allocate_frame(TCGContext *s, int temp)
1371 TCGTemp *ts;
1372 ts = &s->temps[temp];
1373 s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1);
1374 if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end)
1375 tcg_abort();
1376 ts->mem_offset = s->current_frame_offset;
1377 ts->mem_reg = s->frame_reg;
1378 ts->mem_allocated = 1;
1379 s->current_frame_offset += sizeof(tcg_target_long);
1382 /* free register 'reg' by spilling the corresponding temporary if necessary */
1383 static void tcg_reg_free(TCGContext *s, int reg)
1385 TCGTemp *ts;
1386 int temp;
1388 temp = s->reg_to_temp[reg];
1389 if (temp != -1) {
1390 ts = &s->temps[temp];
1391 assert(ts->val_type == TEMP_VAL_REG);
1392 if (!ts->mem_coherent) {
1393 if (!ts->mem_allocated)
1394 temp_allocate_frame(s, temp);
1395 tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1397 ts->val_type = TEMP_VAL_MEM;
1398 s->reg_to_temp[reg] = -1;
1402 /* Allocate a register belonging to reg1 & ~reg2 */
1403 static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2)
1405 int i, reg;
1406 TCGRegSet reg_ct;
1408 tcg_regset_andnot(reg_ct, reg1, reg2);
1410 /* first try free registers */
1411 for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
1412 reg = tcg_target_reg_alloc_order[i];
1413 if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1)
1414 return reg;
1417 /* XXX: do better spill choice */
1418 for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
1419 reg = tcg_target_reg_alloc_order[i];
1420 if (tcg_regset_test_reg(reg_ct, reg)) {
1421 tcg_reg_free(s, reg);
1422 return reg;
1426 tcg_abort();
1429 /* save a temporary to memory. 'allocated_regs' is used in case a
1430 temporary registers needs to be allocated to store a constant. */
1431 static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs)
1433 TCGTemp *ts;
1434 int reg;
1436 ts = &s->temps[temp];
1437 if (!ts->fixed_reg) {
1438 switch(ts->val_type) {
1439 case TEMP_VAL_REG:
1440 tcg_reg_free(s, ts->reg);
1441 break;
1442 case TEMP_VAL_DEAD:
1443 ts->val_type = TEMP_VAL_MEM;
1444 break;
1445 case TEMP_VAL_CONST:
1446 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1447 allocated_regs);
1448 if (!ts->mem_allocated)
1449 temp_allocate_frame(s, temp);
1450 tcg_out_movi(s, ts->type, reg, ts->val);
1451 tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1452 ts->val_type = TEMP_VAL_MEM;
1453 break;
1454 case TEMP_VAL_MEM:
1455 break;
1456 default:
1457 tcg_abort();
1462 /* save globals to their cannonical location and assume they can be
1463 modified be the following code. 'allocated_regs' is used in case a
1464 temporary registers needs to be allocated to store a constant. */
1465 static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
1467 int i;
1469 for(i = 0; i < s->nb_globals; i++) {
1470 temp_save(s, i, allocated_regs);
1474 /* at the end of a basic block, we assume all temporaries are dead and
1475 all globals are stored at their canonical location. */
1476 static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
1478 TCGTemp *ts;
1479 int i;
1481 for(i = s->nb_globals; i < s->nb_temps; i++) {
1482 ts = &s->temps[i];
1483 if (ts->temp_local) {
1484 temp_save(s, i, allocated_regs);
1485 } else {
1486 if (ts->val_type == TEMP_VAL_REG) {
1487 s->reg_to_temp[ts->reg] = -1;
1489 ts->val_type = TEMP_VAL_DEAD;
1493 save_globals(s, allocated_regs);
1496 #define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
1498 static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args)
1500 TCGTemp *ots;
1501 tcg_target_ulong val;
1503 ots = &s->temps[args[0]];
1504 val = args[1];
1506 if (ots->fixed_reg) {
1507 /* for fixed registers, we do not do any constant
1508 propagation */
1509 tcg_out_movi(s, ots->type, ots->reg, val);
1510 } else {
1511 /* The movi is not explicitly generated here */
1512 if (ots->val_type == TEMP_VAL_REG)
1513 s->reg_to_temp[ots->reg] = -1;
1514 ots->val_type = TEMP_VAL_CONST;
1515 ots->val = val;
1519 static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
1520 const TCGArg *args,
1521 unsigned int dead_iargs)
1523 TCGTemp *ts, *ots;
1524 int reg;
1525 const TCGArgConstraint *arg_ct;
1527 ots = &s->temps[args[0]];
1528 ts = &s->temps[args[1]];
1529 arg_ct = &def->args_ct[0];
1531 /* XXX: always mark arg dead if IS_DEAD_IARG(0) */
1532 if (ts->val_type == TEMP_VAL_REG) {
1533 if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) {
1534 /* the mov can be suppressed */
1535 if (ots->val_type == TEMP_VAL_REG)
1536 s->reg_to_temp[ots->reg] = -1;
1537 reg = ts->reg;
1538 s->reg_to_temp[reg] = -1;
1539 ts->val_type = TEMP_VAL_DEAD;
1540 } else {
1541 if (ots->val_type == TEMP_VAL_REG) {
1542 reg = ots->reg;
1543 } else {
1544 reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
1546 if (ts->reg != reg) {
1547 tcg_out_mov(s, reg, ts->reg);
1550 } else if (ts->val_type == TEMP_VAL_MEM) {
1551 if (ots->val_type == TEMP_VAL_REG) {
1552 reg = ots->reg;
1553 } else {
1554 reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
1556 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1557 } else if (ts->val_type == TEMP_VAL_CONST) {
1558 if (ots->fixed_reg) {
1559 reg = ots->reg;
1560 tcg_out_movi(s, ots->type, reg, ts->val);
1561 } else {
1562 /* propagate constant */
1563 if (ots->val_type == TEMP_VAL_REG)
1564 s->reg_to_temp[ots->reg] = -1;
1565 ots->val_type = TEMP_VAL_CONST;
1566 ots->val = ts->val;
1567 return;
1569 } else {
1570 tcg_abort();
1572 s->reg_to_temp[reg] = args[0];
1573 ots->reg = reg;
1574 ots->val_type = TEMP_VAL_REG;
1575 ots->mem_coherent = 0;
1578 static void tcg_reg_alloc_op(TCGContext *s,
1579 const TCGOpDef *def, TCGOpcode opc,
1580 const TCGArg *args,
1581 unsigned int dead_iargs)
1583 TCGRegSet allocated_regs;
1584 int i, k, nb_iargs, nb_oargs, reg;
1585 TCGArg arg;
1586 const TCGArgConstraint *arg_ct;
1587 TCGTemp *ts;
1588 TCGArg new_args[TCG_MAX_OP_ARGS];
1589 int const_args[TCG_MAX_OP_ARGS];
1591 nb_oargs = def->nb_oargs;
1592 nb_iargs = def->nb_iargs;
1594 /* copy constants */
1595 memcpy(new_args + nb_oargs + nb_iargs,
1596 args + nb_oargs + nb_iargs,
1597 sizeof(TCGArg) * def->nb_cargs);
1599 /* satisfy input constraints */
1600 tcg_regset_set(allocated_regs, s->reserved_regs);
1601 for(k = 0; k < nb_iargs; k++) {
1602 i = def->sorted_args[nb_oargs + k];
1603 arg = args[i];
1604 arg_ct = &def->args_ct[i];
1605 ts = &s->temps[arg];
1606 if (ts->val_type == TEMP_VAL_MEM) {
1607 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1608 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1609 ts->val_type = TEMP_VAL_REG;
1610 ts->reg = reg;
1611 ts->mem_coherent = 1;
1612 s->reg_to_temp[reg] = arg;
1613 } else if (ts->val_type == TEMP_VAL_CONST) {
1614 if (tcg_target_const_match(ts->val, arg_ct)) {
1615 /* constant is OK for instruction */
1616 const_args[i] = 1;
1617 new_args[i] = ts->val;
1618 goto iarg_end;
1619 } else {
1620 /* need to move to a register */
1621 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1622 tcg_out_movi(s, ts->type, reg, ts->val);
1623 ts->val_type = TEMP_VAL_REG;
1624 ts->reg = reg;
1625 ts->mem_coherent = 0;
1626 s->reg_to_temp[reg] = arg;
1629 assert(ts->val_type == TEMP_VAL_REG);
1630 if (arg_ct->ct & TCG_CT_IALIAS) {
1631 if (ts->fixed_reg) {
1632 /* if fixed register, we must allocate a new register
1633 if the alias is not the same register */
1634 if (arg != args[arg_ct->alias_index])
1635 goto allocate_in_reg;
1636 } else {
1637 /* if the input is aliased to an output and if it is
1638 not dead after the instruction, we must allocate
1639 a new register and move it */
1640 if (!IS_DEAD_IARG(i - nb_oargs))
1641 goto allocate_in_reg;
1644 reg = ts->reg;
1645 if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1646 /* nothing to do : the constraint is satisfied */
1647 } else {
1648 allocate_in_reg:
1649 /* allocate a new register matching the constraint
1650 and move the temporary register into it */
1651 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1652 tcg_out_mov(s, reg, ts->reg);
1654 new_args[i] = reg;
1655 const_args[i] = 0;
1656 tcg_regset_set_reg(allocated_regs, reg);
1657 iarg_end: ;
1660 if (def->flags & TCG_OPF_BB_END) {
1661 tcg_reg_alloc_bb_end(s, allocated_regs);
1662 } else {
1663 /* mark dead temporaries and free the associated registers */
1664 for(i = 0; i < nb_iargs; i++) {
1665 arg = args[nb_oargs + i];
1666 if (IS_DEAD_IARG(i)) {
1667 ts = &s->temps[arg];
1668 if (!ts->fixed_reg) {
1669 if (ts->val_type == TEMP_VAL_REG)
1670 s->reg_to_temp[ts->reg] = -1;
1671 ts->val_type = TEMP_VAL_DEAD;
1676 if (def->flags & TCG_OPF_CALL_CLOBBER) {
1677 /* XXX: permit generic clobber register list ? */
1678 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1679 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
1680 tcg_reg_free(s, reg);
1683 /* XXX: for load/store we could do that only for the slow path
1684 (i.e. when a memory callback is called) */
1686 /* store globals and free associated registers (we assume the insn
1687 can modify any global. */
1688 save_globals(s, allocated_regs);
1691 /* satisfy the output constraints */
1692 tcg_regset_set(allocated_regs, s->reserved_regs);
1693 for(k = 0; k < nb_oargs; k++) {
1694 i = def->sorted_args[k];
1695 arg = args[i];
1696 arg_ct = &def->args_ct[i];
1697 ts = &s->temps[arg];
1698 if (arg_ct->ct & TCG_CT_ALIAS) {
1699 reg = new_args[arg_ct->alias_index];
1700 } else {
1701 /* if fixed register, we try to use it */
1702 reg = ts->reg;
1703 if (ts->fixed_reg &&
1704 tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1705 goto oarg_end;
1707 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1709 tcg_regset_set_reg(allocated_regs, reg);
1710 /* if a fixed register is used, then a move will be done afterwards */
1711 if (!ts->fixed_reg) {
1712 if (ts->val_type == TEMP_VAL_REG)
1713 s->reg_to_temp[ts->reg] = -1;
1714 ts->val_type = TEMP_VAL_REG;
1715 ts->reg = reg;
1716 /* temp value is modified, so the value kept in memory is
1717 potentially not the same */
1718 ts->mem_coherent = 0;
1719 s->reg_to_temp[reg] = arg;
1721 oarg_end:
1722 new_args[i] = reg;
1726 /* emit instruction */
1727 tcg_out_op(s, opc, new_args, const_args);
1729 /* move the outputs in the correct register if needed */
1730 for(i = 0; i < nb_oargs; i++) {
1731 ts = &s->temps[args[i]];
1732 reg = new_args[i];
1733 if (ts->fixed_reg && ts->reg != reg) {
1734 tcg_out_mov(s, ts->reg, reg);
1739 #ifdef TCG_TARGET_STACK_GROWSUP
1740 #define STACK_DIR(x) (-(x))
1741 #else
1742 #define STACK_DIR(x) (x)
1743 #endif
1745 static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
1746 TCGOpcode opc, const TCGArg *args,
1747 unsigned int dead_iargs)
1749 int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params;
1750 TCGArg arg, func_arg;
1751 TCGTemp *ts;
1752 tcg_target_long stack_offset, call_stack_size, func_addr;
1753 int const_func_arg, allocate_args;
1754 TCGRegSet allocated_regs;
1755 const TCGArgConstraint *arg_ct;
1757 arg = *args++;
1759 nb_oargs = arg >> 16;
1760 nb_iargs = arg & 0xffff;
1761 nb_params = nb_iargs - 1;
1763 flags = args[nb_oargs + nb_iargs];
1765 nb_regs = tcg_target_get_call_iarg_regs_count(flags);
1766 if (nb_regs > nb_params)
1767 nb_regs = nb_params;
1769 /* assign stack slots first */
1770 /* XXX: preallocate call stack */
1771 call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);
1772 call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
1773 ~(TCG_TARGET_STACK_ALIGN - 1);
1774 allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
1775 if (allocate_args) {
1776 tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size));
1779 stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
1780 for(i = nb_regs; i < nb_params; i++) {
1781 arg = args[nb_oargs + i];
1782 #ifdef TCG_TARGET_STACK_GROWSUP
1783 stack_offset -= sizeof(tcg_target_long);
1784 #endif
1785 if (arg != TCG_CALL_DUMMY_ARG) {
1786 ts = &s->temps[arg];
1787 if (ts->val_type == TEMP_VAL_REG) {
1788 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
1789 } else if (ts->val_type == TEMP_VAL_MEM) {
1790 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1791 s->reserved_regs);
1792 /* XXX: not correct if reading values from the stack */
1793 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1794 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
1795 } else if (ts->val_type == TEMP_VAL_CONST) {
1796 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1797 s->reserved_regs);
1798 /* XXX: sign extend may be needed on some targets */
1799 tcg_out_movi(s, ts->type, reg, ts->val);
1800 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
1801 } else {
1802 tcg_abort();
1805 #ifndef TCG_TARGET_STACK_GROWSUP
1806 stack_offset += sizeof(tcg_target_long);
1807 #endif
1810 /* assign input registers */
1811 tcg_regset_set(allocated_regs, s->reserved_regs);
1812 for(i = 0; i < nb_regs; i++) {
1813 arg = args[nb_oargs + i];
1814 if (arg != TCG_CALL_DUMMY_ARG) {
1815 ts = &s->temps[arg];
1816 reg = tcg_target_call_iarg_regs[i];
1817 tcg_reg_free(s, reg);
1818 if (ts->val_type == TEMP_VAL_REG) {
1819 if (ts->reg != reg) {
1820 tcg_out_mov(s, reg, ts->reg);
1822 } else if (ts->val_type == TEMP_VAL_MEM) {
1823 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1824 } else if (ts->val_type == TEMP_VAL_CONST) {
1825 /* XXX: sign extend ? */
1826 tcg_out_movi(s, ts->type, reg, ts->val);
1827 } else {
1828 tcg_abort();
1830 tcg_regset_set_reg(allocated_regs, reg);
1834 /* assign function address */
1835 func_arg = args[nb_oargs + nb_iargs - 1];
1836 arg_ct = &def->args_ct[0];
1837 ts = &s->temps[func_arg];
1838 func_addr = ts->val;
1839 const_func_arg = 0;
1840 if (ts->val_type == TEMP_VAL_MEM) {
1841 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1842 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1843 func_arg = reg;
1844 tcg_regset_set_reg(allocated_regs, reg);
1845 } else if (ts->val_type == TEMP_VAL_REG) {
1846 reg = ts->reg;
1847 if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1848 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1849 tcg_out_mov(s, reg, ts->reg);
1851 func_arg = reg;
1852 tcg_regset_set_reg(allocated_regs, reg);
1853 } else if (ts->val_type == TEMP_VAL_CONST) {
1854 if (tcg_target_const_match(func_addr, arg_ct)) {
1855 const_func_arg = 1;
1856 func_arg = func_addr;
1857 } else {
1858 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1859 tcg_out_movi(s, ts->type, reg, func_addr);
1860 func_arg = reg;
1861 tcg_regset_set_reg(allocated_regs, reg);
1863 } else {
1864 tcg_abort();
1868 /* mark dead temporaries and free the associated registers */
1869 for(i = 0; i < nb_iargs; i++) {
1870 arg = args[nb_oargs + i];
1871 if (IS_DEAD_IARG(i)) {
1872 ts = &s->temps[arg];
1873 if (!ts->fixed_reg) {
1874 if (ts->val_type == TEMP_VAL_REG)
1875 s->reg_to_temp[ts->reg] = -1;
1876 ts->val_type = TEMP_VAL_DEAD;
1881 /* clobber call registers */
1882 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1883 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
1884 tcg_reg_free(s, reg);
1888 /* store globals and free associated registers (we assume the call
1889 can modify any global. */
1890 if (!(flags & TCG_CALL_CONST)) {
1891 save_globals(s, allocated_regs);
1894 tcg_out_op(s, opc, &func_arg, &const_func_arg);
1896 if (allocate_args) {
1897 tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size));
1900 /* assign output registers and emit moves if needed */
1901 for(i = 0; i < nb_oargs; i++) {
1902 arg = args[i];
1903 ts = &s->temps[arg];
1904 reg = tcg_target_call_oarg_regs[i];
1905 assert(s->reg_to_temp[reg] == -1);
1906 if (ts->fixed_reg) {
1907 if (ts->reg != reg) {
1908 tcg_out_mov(s, ts->reg, reg);
1910 } else {
1911 if (ts->val_type == TEMP_VAL_REG)
1912 s->reg_to_temp[ts->reg] = -1;
1913 ts->val_type = TEMP_VAL_REG;
1914 ts->reg = reg;
1915 ts->mem_coherent = 0;
1916 s->reg_to_temp[reg] = arg;
1920 return nb_iargs + nb_oargs + def->nb_cargs + 1;
1923 #ifdef CONFIG_PROFILER
1925 static int64_t tcg_table_op_count[NB_OPS];
1927 static void dump_op_count(void)
1929 int i;
1930 FILE *f;
1931 f = fopen("/tmp/op.log", "w");
1932 for(i = INDEX_op_end; i < NB_OPS; i++) {
1933 fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, tcg_table_op_count[i]);
1935 fclose(f);
1937 #endif
1940 static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
1941 long search_pc)
1943 TCGOpcode opc;
1944 int op_index;
1945 const TCGOpDef *def;
1946 unsigned int dead_iargs;
1947 const TCGArg *args;
1949 #ifdef DEBUG_DISAS
1950 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
1951 qemu_log("OP:\n");
1952 tcg_dump_ops(s, logfile);
1953 qemu_log("\n");
1955 #endif
1957 #ifdef CONFIG_PROFILER
1958 s->la_time -= profile_getclock();
1959 #endif
1960 tcg_liveness_analysis(s);
1961 #ifdef CONFIG_PROFILER
1962 s->la_time += profile_getclock();
1963 #endif
1965 #ifdef DEBUG_DISAS
1966 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) {
1967 qemu_log("OP after liveness analysis:\n");
1968 tcg_dump_ops(s, logfile);
1969 qemu_log("\n");
1971 #endif
1973 tcg_reg_alloc_start(s);
1975 s->code_buf = gen_code_buf;
1976 s->code_ptr = gen_code_buf;
1978 args = gen_opparam_buf;
1979 op_index = 0;
1981 for(;;) {
1982 opc = gen_opc_buf[op_index];
1983 #ifdef CONFIG_PROFILER
1984 tcg_table_op_count[opc]++;
1985 #endif
1986 def = &tcg_op_defs[opc];
1987 #if 0
1988 printf("%s: %d %d %d\n", def->name,
1989 def->nb_oargs, def->nb_iargs, def->nb_cargs);
1990 // dump_regs(s);
1991 #endif
1992 switch(opc) {
1993 case INDEX_op_mov_i32:
1994 #if TCG_TARGET_REG_BITS == 64
1995 case INDEX_op_mov_i64:
1996 #endif
1997 dead_iargs = s->op_dead_iargs[op_index];
1998 tcg_reg_alloc_mov(s, def, args, dead_iargs);
1999 break;
2000 case INDEX_op_movi_i32:
2001 #if TCG_TARGET_REG_BITS == 64
2002 case INDEX_op_movi_i64:
2003 #endif
2004 tcg_reg_alloc_movi(s, args);
2005 break;
2006 case INDEX_op_debug_insn_start:
2007 /* debug instruction */
2008 break;
2009 case INDEX_op_nop:
2010 case INDEX_op_nop1:
2011 case INDEX_op_nop2:
2012 case INDEX_op_nop3:
2013 break;
2014 case INDEX_op_nopn:
2015 args += args[0];
2016 goto next;
2017 case INDEX_op_discard:
2019 TCGTemp *ts;
2020 ts = &s->temps[args[0]];
2021 /* mark the temporary as dead */
2022 if (!ts->fixed_reg) {
2023 if (ts->val_type == TEMP_VAL_REG)
2024 s->reg_to_temp[ts->reg] = -1;
2025 ts->val_type = TEMP_VAL_DEAD;
2028 break;
2029 case INDEX_op_set_label:
2030 tcg_reg_alloc_bb_end(s, s->reserved_regs);
2031 tcg_out_label(s, args[0], (long)s->code_ptr);
2032 break;
2033 case INDEX_op_call:
2034 dead_iargs = s->op_dead_iargs[op_index];
2035 args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs);
2036 goto next;
2037 case INDEX_op_end:
2038 goto the_end;
2039 default:
2040 /* Note: in order to speed up the code, it would be much
2041 faster to have specialized register allocator functions for
2042 some common argument patterns */
2043 dead_iargs = s->op_dead_iargs[op_index];
2044 tcg_reg_alloc_op(s, def, opc, args, dead_iargs);
2045 break;
2047 args += def->nb_args;
2048 next:
2049 if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) {
2050 return op_index;
2052 op_index++;
2053 #ifndef NDEBUG
2054 check_regs(s);
2055 #endif
2057 the_end:
2058 return -1;
2061 int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf)
2063 #ifdef CONFIG_PROFILER
2065 int n;
2066 n = (gen_opc_ptr - gen_opc_buf);
2067 s->op_count += n;
2068 if (n > s->op_count_max)
2069 s->op_count_max = n;
2071 s->temp_count += s->nb_temps;
2072 if (s->nb_temps > s->temp_count_max)
2073 s->temp_count_max = s->nb_temps;
2075 #endif
2077 tcg_gen_code_common(s, gen_code_buf, -1);
2079 /* flush instruction cache */
2080 flush_icache_range((unsigned long)gen_code_buf,
2081 (unsigned long)s->code_ptr);
2082 return s->code_ptr - gen_code_buf;
2085 /* Return the index of the micro operation such as the pc after is <
2086 offset bytes from the start of the TB. The contents of gen_code_buf must
2087 not be changed, though writing the same values is ok.
2088 Return -1 if not found. */
2089 int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset)
2091 return tcg_gen_code_common(s, gen_code_buf, offset);
2094 #ifdef CONFIG_PROFILER
2095 void tcg_dump_info(FILE *f,
2096 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2098 TCGContext *s = &tcg_ctx;
2099 int64_t tot;
2101 tot = s->interm_time + s->code_time;
2102 cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n",
2103 tot, tot / 2.4e9);
2104 cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n",
2105 s->tb_count,
2106 s->tb_count1 - s->tb_count,
2107 s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0);
2108 cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n",
2109 s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max);
2110 cpu_fprintf(f, "deleted ops/TB %0.2f\n",
2111 s->tb_count ?
2112 (double)s->del_op_count / s->tb_count : 0);
2113 cpu_fprintf(f, "avg temps/TB %0.2f max=%d\n",
2114 s->tb_count ?
2115 (double)s->temp_count / s->tb_count : 0,
2116 s->temp_count_max);
2118 cpu_fprintf(f, "cycles/op %0.1f\n",
2119 s->op_count ? (double)tot / s->op_count : 0);
2120 cpu_fprintf(f, "cycles/in byte %0.1f\n",
2121 s->code_in_len ? (double)tot / s->code_in_len : 0);
2122 cpu_fprintf(f, "cycles/out byte %0.1f\n",
2123 s->code_out_len ? (double)tot / s->code_out_len : 0);
2124 if (tot == 0)
2125 tot = 1;
2126 cpu_fprintf(f, " gen_interm time %0.1f%%\n",
2127 (double)s->interm_time / tot * 100.0);
2128 cpu_fprintf(f, " gen_code time %0.1f%%\n",
2129 (double)s->code_time / tot * 100.0);
2130 cpu_fprintf(f, "liveness/code time %0.1f%%\n",
2131 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
2132 cpu_fprintf(f, "cpu_restore count %" PRId64 "\n",
2133 s->restore_count);
2134 cpu_fprintf(f, " avg cycles %0.1f\n",
2135 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
2137 dump_op_count();
2139 #else
2140 void tcg_dump_info(FILE *f,
2141 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2143 cpu_fprintf(f, "[TCG profiler not compiled]\n");
2145 #endif