Add kbd_mouse_has_absolute()
[qemu/aliguori-queue.git] / tcg / tcg.c
blob1818868226833d55fd5e90cb999495d9a723b13e
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"
51 /* Note: the long term plan is to reduce the dependancies on the QEMU
52 CPU definitions. Currently they are used for qemu_ld/st
53 instructions */
54 #define NO_CPU_IO_DEFS
55 #include "cpu.h"
56 #include "exec-all.h"
58 #include "tcg-op.h"
59 #include "elf.h"
61 #if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
62 #error GUEST_BASE not supported on this host.
63 #endif
65 static void patch_reloc(uint8_t *code_ptr, int type,
66 tcg_target_long value, tcg_target_long addend);
68 static TCGOpDef tcg_op_defs[] = {
69 #define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size },
70 #define DEF2(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags, 0 },
71 #include "tcg-opc.h"
72 #undef DEF
73 #undef DEF2
76 static TCGRegSet tcg_target_available_regs[2];
77 static TCGRegSet tcg_target_call_clobber_regs;
79 /* XXX: move that inside the context */
80 uint16_t *gen_opc_ptr;
81 TCGArg *gen_opparam_ptr;
83 static inline void tcg_out8(TCGContext *s, uint8_t v)
85 *s->code_ptr++ = v;
88 static inline void tcg_out16(TCGContext *s, uint16_t v)
90 *(uint16_t *)s->code_ptr = v;
91 s->code_ptr += 2;
94 static inline void tcg_out32(TCGContext *s, uint32_t v)
96 *(uint32_t *)s->code_ptr = v;
97 s->code_ptr += 4;
100 /* label relocation processing */
102 void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type,
103 int label_index, long addend)
105 TCGLabel *l;
106 TCGRelocation *r;
108 l = &s->labels[label_index];
109 if (l->has_value) {
110 /* FIXME: This may break relocations on RISC targets that
111 modify instruction fields in place. The caller may not have
112 written the initial value. */
113 patch_reloc(code_ptr, type, l->u.value, addend);
114 } else {
115 /* add a new relocation entry */
116 r = tcg_malloc(sizeof(TCGRelocation));
117 r->type = type;
118 r->ptr = code_ptr;
119 r->addend = addend;
120 r->next = l->u.first_reloc;
121 l->u.first_reloc = r;
125 static void tcg_out_label(TCGContext *s, int label_index,
126 tcg_target_long value)
128 TCGLabel *l;
129 TCGRelocation *r;
131 l = &s->labels[label_index];
132 if (l->has_value)
133 tcg_abort();
134 r = l->u.first_reloc;
135 while (r != NULL) {
136 patch_reloc(r->ptr, r->type, value, r->addend);
137 r = r->next;
139 l->has_value = 1;
140 l->u.value = value;
143 int gen_new_label(void)
145 TCGContext *s = &tcg_ctx;
146 int idx;
147 TCGLabel *l;
149 if (s->nb_labels >= TCG_MAX_LABELS)
150 tcg_abort();
151 idx = s->nb_labels++;
152 l = &s->labels[idx];
153 l->has_value = 0;
154 l->u.first_reloc = NULL;
155 return idx;
158 #include "tcg-target.c"
160 /* pool based memory allocation */
161 void *tcg_malloc_internal(TCGContext *s, int size)
163 TCGPool *p;
164 int pool_size;
166 if (size > TCG_POOL_CHUNK_SIZE) {
167 /* big malloc: insert a new pool (XXX: could optimize) */
168 p = qemu_malloc(sizeof(TCGPool) + size);
169 p->size = size;
170 if (s->pool_current)
171 s->pool_current->next = p;
172 else
173 s->pool_first = p;
174 p->next = s->pool_current;
175 } else {
176 p = s->pool_current;
177 if (!p) {
178 p = s->pool_first;
179 if (!p)
180 goto new_pool;
181 } else {
182 if (!p->next) {
183 new_pool:
184 pool_size = TCG_POOL_CHUNK_SIZE;
185 p = qemu_malloc(sizeof(TCGPool) + pool_size);
186 p->size = pool_size;
187 p->next = NULL;
188 if (s->pool_current)
189 s->pool_current->next = p;
190 else
191 s->pool_first = p;
192 } else {
193 p = p->next;
197 s->pool_current = p;
198 s->pool_cur = p->data + size;
199 s->pool_end = p->data + p->size;
200 return p->data;
203 void tcg_pool_reset(TCGContext *s)
205 s->pool_cur = s->pool_end = NULL;
206 s->pool_current = NULL;
209 void tcg_context_init(TCGContext *s)
211 int op, total_args, n;
212 TCGOpDef *def;
213 TCGArgConstraint *args_ct;
214 int *sorted_args;
216 memset(s, 0, sizeof(*s));
217 s->temps = s->static_temps;
218 s->nb_globals = 0;
220 /* Count total number of arguments and allocate the corresponding
221 space */
222 total_args = 0;
223 for(op = 0; op < NB_OPS; op++) {
224 def = &tcg_op_defs[op];
225 n = def->nb_iargs + def->nb_oargs;
226 total_args += n;
229 args_ct = qemu_malloc(sizeof(TCGArgConstraint) * total_args);
230 sorted_args = qemu_malloc(sizeof(int) * total_args);
232 for(op = 0; op < NB_OPS; op++) {
233 def = &tcg_op_defs[op];
234 def->args_ct = args_ct;
235 def->sorted_args = sorted_args;
236 n = def->nb_iargs + def->nb_oargs;
237 sorted_args += n;
238 args_ct += n;
241 tcg_target_init(s);
243 /* init global prologue and epilogue */
244 s->code_buf = code_gen_prologue;
245 s->code_ptr = s->code_buf;
246 tcg_target_qemu_prologue(s);
247 flush_icache_range((unsigned long)s->code_buf,
248 (unsigned long)s->code_ptr);
251 void tcg_set_frame(TCGContext *s, int reg,
252 tcg_target_long start, tcg_target_long size)
254 s->frame_start = start;
255 s->frame_end = start + size;
256 s->frame_reg = reg;
259 void tcg_func_start(TCGContext *s)
261 int i;
262 tcg_pool_reset(s);
263 s->nb_temps = s->nb_globals;
264 for(i = 0; i < (TCG_TYPE_COUNT * 2); i++)
265 s->first_free_temp[i] = -1;
266 s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS);
267 s->nb_labels = 0;
268 s->current_frame_offset = s->frame_start;
270 gen_opc_ptr = gen_opc_buf;
271 gen_opparam_ptr = gen_opparam_buf;
274 static inline void tcg_temp_alloc(TCGContext *s, int n)
276 if (n > TCG_MAX_TEMPS)
277 tcg_abort();
280 static inline int tcg_global_reg_new_internal(TCGType type, int reg,
281 const char *name)
283 TCGContext *s = &tcg_ctx;
284 TCGTemp *ts;
285 int idx;
287 #if TCG_TARGET_REG_BITS == 32
288 if (type != TCG_TYPE_I32)
289 tcg_abort();
290 #endif
291 if (tcg_regset_test_reg(s->reserved_regs, reg))
292 tcg_abort();
293 idx = s->nb_globals;
294 tcg_temp_alloc(s, s->nb_globals + 1);
295 ts = &s->temps[s->nb_globals];
296 ts->base_type = type;
297 ts->type = type;
298 ts->fixed_reg = 1;
299 ts->reg = reg;
300 ts->name = name;
301 s->nb_globals++;
302 tcg_regset_set_reg(s->reserved_regs, reg);
303 return idx;
306 TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name)
308 int idx;
310 idx = tcg_global_reg_new_internal(TCG_TYPE_I32, reg, name);
311 return MAKE_TCGV_I32(idx);
314 TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name)
316 int idx;
318 idx = tcg_global_reg_new_internal(TCG_TYPE_I64, reg, name);
319 return MAKE_TCGV_I64(idx);
322 static inline int tcg_global_mem_new_internal(TCGType type, int reg,
323 tcg_target_long offset,
324 const char *name)
326 TCGContext *s = &tcg_ctx;
327 TCGTemp *ts;
328 int idx;
330 idx = s->nb_globals;
331 #if TCG_TARGET_REG_BITS == 32
332 if (type == TCG_TYPE_I64) {
333 char buf[64];
334 tcg_temp_alloc(s, s->nb_globals + 2);
335 ts = &s->temps[s->nb_globals];
336 ts->base_type = type;
337 ts->type = TCG_TYPE_I32;
338 ts->fixed_reg = 0;
339 ts->mem_allocated = 1;
340 ts->mem_reg = reg;
341 #ifdef TCG_TARGET_WORDS_BIGENDIAN
342 ts->mem_offset = offset + 4;
343 #else
344 ts->mem_offset = offset;
345 #endif
346 pstrcpy(buf, sizeof(buf), name);
347 pstrcat(buf, sizeof(buf), "_0");
348 ts->name = strdup(buf);
349 ts++;
351 ts->base_type = type;
352 ts->type = TCG_TYPE_I32;
353 ts->fixed_reg = 0;
354 ts->mem_allocated = 1;
355 ts->mem_reg = reg;
356 #ifdef TCG_TARGET_WORDS_BIGENDIAN
357 ts->mem_offset = offset;
358 #else
359 ts->mem_offset = offset + 4;
360 #endif
361 pstrcpy(buf, sizeof(buf), name);
362 pstrcat(buf, sizeof(buf), "_1");
363 ts->name = strdup(buf);
365 s->nb_globals += 2;
366 } else
367 #endif
369 tcg_temp_alloc(s, s->nb_globals + 1);
370 ts = &s->temps[s->nb_globals];
371 ts->base_type = type;
372 ts->type = type;
373 ts->fixed_reg = 0;
374 ts->mem_allocated = 1;
375 ts->mem_reg = reg;
376 ts->mem_offset = offset;
377 ts->name = name;
378 s->nb_globals++;
380 return idx;
383 TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset,
384 const char *name)
386 int idx;
388 idx = tcg_global_mem_new_internal(TCG_TYPE_I32, reg, offset, name);
389 return MAKE_TCGV_I32(idx);
392 TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset,
393 const char *name)
395 int idx;
397 idx = tcg_global_mem_new_internal(TCG_TYPE_I64, reg, offset, name);
398 return MAKE_TCGV_I64(idx);
401 static inline int tcg_temp_new_internal(TCGType type, int temp_local)
403 TCGContext *s = &tcg_ctx;
404 TCGTemp *ts;
405 int idx, k;
407 k = type;
408 if (temp_local)
409 k += TCG_TYPE_COUNT;
410 idx = s->first_free_temp[k];
411 if (idx != -1) {
412 /* There is already an available temp with the
413 right type */
414 ts = &s->temps[idx];
415 s->first_free_temp[k] = ts->next_free_temp;
416 ts->temp_allocated = 1;
417 assert(ts->temp_local == temp_local);
418 } else {
419 idx = s->nb_temps;
420 #if TCG_TARGET_REG_BITS == 32
421 if (type == TCG_TYPE_I64) {
422 tcg_temp_alloc(s, s->nb_temps + 2);
423 ts = &s->temps[s->nb_temps];
424 ts->base_type = type;
425 ts->type = TCG_TYPE_I32;
426 ts->temp_allocated = 1;
427 ts->temp_local = temp_local;
428 ts->name = NULL;
429 ts++;
430 ts->base_type = TCG_TYPE_I32;
431 ts->type = TCG_TYPE_I32;
432 ts->temp_allocated = 1;
433 ts->temp_local = temp_local;
434 ts->name = NULL;
435 s->nb_temps += 2;
436 } else
437 #endif
439 tcg_temp_alloc(s, s->nb_temps + 1);
440 ts = &s->temps[s->nb_temps];
441 ts->base_type = type;
442 ts->type = type;
443 ts->temp_allocated = 1;
444 ts->temp_local = temp_local;
445 ts->name = NULL;
446 s->nb_temps++;
449 return idx;
452 TCGv_i32 tcg_temp_new_internal_i32(int temp_local)
454 int idx;
456 idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local);
457 return MAKE_TCGV_I32(idx);
460 TCGv_i64 tcg_temp_new_internal_i64(int temp_local)
462 int idx;
464 idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local);
465 return MAKE_TCGV_I64(idx);
468 static inline void tcg_temp_free_internal(int idx)
470 TCGContext *s = &tcg_ctx;
471 TCGTemp *ts;
472 int k;
474 assert(idx >= s->nb_globals && idx < s->nb_temps);
475 ts = &s->temps[idx];
476 assert(ts->temp_allocated != 0);
477 ts->temp_allocated = 0;
478 k = ts->base_type;
479 if (ts->temp_local)
480 k += TCG_TYPE_COUNT;
481 ts->next_free_temp = s->first_free_temp[k];
482 s->first_free_temp[k] = idx;
485 void tcg_temp_free_i32(TCGv_i32 arg)
487 tcg_temp_free_internal(GET_TCGV_I32(arg));
490 void tcg_temp_free_i64(TCGv_i64 arg)
492 tcg_temp_free_internal(GET_TCGV_I64(arg));
495 TCGv_i32 tcg_const_i32(int32_t val)
497 TCGv_i32 t0;
498 t0 = tcg_temp_new_i32();
499 tcg_gen_movi_i32(t0, val);
500 return t0;
503 TCGv_i64 tcg_const_i64(int64_t val)
505 TCGv_i64 t0;
506 t0 = tcg_temp_new_i64();
507 tcg_gen_movi_i64(t0, val);
508 return t0;
511 TCGv_i32 tcg_const_local_i32(int32_t val)
513 TCGv_i32 t0;
514 t0 = tcg_temp_local_new_i32();
515 tcg_gen_movi_i32(t0, val);
516 return t0;
519 TCGv_i64 tcg_const_local_i64(int64_t val)
521 TCGv_i64 t0;
522 t0 = tcg_temp_local_new_i64();
523 tcg_gen_movi_i64(t0, val);
524 return t0;
527 void tcg_register_helper(void *func, const char *name)
529 TCGContext *s = &tcg_ctx;
530 int n;
531 if ((s->nb_helpers + 1) > s->allocated_helpers) {
532 n = s->allocated_helpers;
533 if (n == 0) {
534 n = 4;
535 } else {
536 n *= 2;
538 s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo));
539 s->allocated_helpers = n;
541 s->helpers[s->nb_helpers].func = (tcg_target_ulong)func;
542 s->helpers[s->nb_helpers].name = name;
543 s->nb_helpers++;
546 /* Note: we convert the 64 bit args to 32 bit and do some alignment
547 and endian swap. Maybe it would be better to do the alignment
548 and endian swap in tcg_reg_alloc_call(). */
549 void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
550 int sizemask, TCGArg ret, int nargs, TCGArg *args)
552 int call_type;
553 int i;
554 int real_args;
555 int nb_rets;
556 TCGArg *nparam;
557 *gen_opc_ptr++ = INDEX_op_call;
558 nparam = gen_opparam_ptr++;
559 call_type = (flags & TCG_CALL_TYPE_MASK);
560 if (ret != TCG_CALL_DUMMY_ARG) {
561 #if TCG_TARGET_REG_BITS < 64
562 if (sizemask & 1) {
563 #ifdef TCG_TARGET_WORDS_BIGENDIAN
564 *gen_opparam_ptr++ = ret + 1;
565 *gen_opparam_ptr++ = ret;
566 #else
567 *gen_opparam_ptr++ = ret;
568 *gen_opparam_ptr++ = ret + 1;
569 #endif
570 nb_rets = 2;
571 } else
572 #endif
574 *gen_opparam_ptr++ = ret;
575 nb_rets = 1;
577 } else {
578 nb_rets = 0;
580 real_args = 0;
581 for (i = 0; i < nargs; i++) {
582 #if TCG_TARGET_REG_BITS < 64
583 if (sizemask & (2 << i)) {
584 #ifdef TCG_TARGET_I386
585 /* REGPARM case: if the third parameter is 64 bit, it is
586 allocated on the stack */
587 if (i == 2 && call_type == TCG_CALL_TYPE_REGPARM) {
588 call_type = TCG_CALL_TYPE_REGPARM_2;
589 flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type;
591 #endif
592 #ifdef TCG_TARGET_CALL_ALIGN_ARGS
593 /* some targets want aligned 64 bit args */
594 if (real_args & 1) {
595 *gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG;
596 real_args++;
598 #endif
599 #ifdef TCG_TARGET_WORDS_BIGENDIAN
600 *gen_opparam_ptr++ = args[i] + 1;
601 *gen_opparam_ptr++ = args[i];
602 #else
603 *gen_opparam_ptr++ = args[i];
604 *gen_opparam_ptr++ = args[i] + 1;
605 #endif
606 real_args += 2;
607 } else
608 #endif
610 *gen_opparam_ptr++ = args[i];
611 real_args++;
614 *gen_opparam_ptr++ = GET_TCGV_PTR(func);
616 *gen_opparam_ptr++ = flags;
618 *nparam = (nb_rets << 16) | (real_args + 1);
620 /* total parameters, needed to go backward in the instruction stream */
621 *gen_opparam_ptr++ = 1 + nb_rets + real_args + 3;
624 #if TCG_TARGET_REG_BITS == 32
625 void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
626 int c, int right, int arith)
628 if (c == 0) {
629 tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
630 tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
631 } else if (c >= 32) {
632 c -= 32;
633 if (right) {
634 if (arith) {
635 tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
636 tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31);
637 } else {
638 tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
639 tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
641 } else {
642 tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c);
643 tcg_gen_movi_i32(TCGV_LOW(ret), 0);
645 } else {
646 TCGv_i32 t0, t1;
648 t0 = tcg_temp_new_i32();
649 t1 = tcg_temp_new_i32();
650 if (right) {
651 tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c);
652 if (arith)
653 tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c);
654 else
655 tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c);
656 tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c);
657 tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0);
658 tcg_gen_mov_i32(TCGV_HIGH(ret), t1);
659 } else {
660 tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c);
661 /* Note: ret can be the same as arg1, so we use t1 */
662 tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c);
663 tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c);
664 tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0);
665 tcg_gen_mov_i32(TCGV_LOW(ret), t1);
667 tcg_temp_free_i32(t0);
668 tcg_temp_free_i32(t1);
671 #endif
674 static void tcg_reg_alloc_start(TCGContext *s)
676 int i;
677 TCGTemp *ts;
678 for(i = 0; i < s->nb_globals; i++) {
679 ts = &s->temps[i];
680 if (ts->fixed_reg) {
681 ts->val_type = TEMP_VAL_REG;
682 } else {
683 ts->val_type = TEMP_VAL_MEM;
686 for(i = s->nb_globals; i < s->nb_temps; i++) {
687 ts = &s->temps[i];
688 ts->val_type = TEMP_VAL_DEAD;
689 ts->mem_allocated = 0;
690 ts->fixed_reg = 0;
692 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
693 s->reg_to_temp[i] = -1;
697 static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size,
698 int idx)
700 TCGTemp *ts;
702 ts = &s->temps[idx];
703 if (idx < s->nb_globals) {
704 pstrcpy(buf, buf_size, ts->name);
705 } else {
706 if (ts->temp_local)
707 snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
708 else
709 snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
711 return buf;
714 char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg)
716 return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I32(arg));
719 char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg)
721 return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I64(arg));
724 static int helper_cmp(const void *p1, const void *p2)
726 const TCGHelperInfo *th1 = p1;
727 const TCGHelperInfo *th2 = p2;
728 if (th1->func < th2->func)
729 return -1;
730 else if (th1->func == th2->func)
731 return 0;
732 else
733 return 1;
736 /* find helper definition (Note: A hash table would be better) */
737 static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val)
739 int m, m_min, m_max;
740 TCGHelperInfo *th;
741 tcg_target_ulong v;
743 if (unlikely(!s->helpers_sorted)) {
744 qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo),
745 helper_cmp);
746 s->helpers_sorted = 1;
749 /* binary search */
750 m_min = 0;
751 m_max = s->nb_helpers - 1;
752 while (m_min <= m_max) {
753 m = (m_min + m_max) >> 1;
754 th = &s->helpers[m];
755 v = th->func;
756 if (v == val)
757 return th;
758 else if (val < v) {
759 m_max = m - 1;
760 } else {
761 m_min = m + 1;
764 return NULL;
767 static const char * const cond_name[] =
769 [TCG_COND_EQ] = "eq",
770 [TCG_COND_NE] = "ne",
771 [TCG_COND_LT] = "lt",
772 [TCG_COND_GE] = "ge",
773 [TCG_COND_LE] = "le",
774 [TCG_COND_GT] = "gt",
775 [TCG_COND_LTU] = "ltu",
776 [TCG_COND_GEU] = "geu",
777 [TCG_COND_LEU] = "leu",
778 [TCG_COND_GTU] = "gtu"
781 void tcg_dump_ops(TCGContext *s, FILE *outfile)
783 const uint16_t *opc_ptr;
784 const TCGArg *args;
785 TCGArg arg;
786 int c, i, k, nb_oargs, nb_iargs, nb_cargs, first_insn;
787 const TCGOpDef *def;
788 char buf[128];
790 first_insn = 1;
791 opc_ptr = gen_opc_buf;
792 args = gen_opparam_buf;
793 while (opc_ptr < gen_opc_ptr) {
794 c = *opc_ptr++;
795 def = &tcg_op_defs[c];
796 if (c == INDEX_op_debug_insn_start) {
797 uint64_t pc;
798 #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
799 pc = ((uint64_t)args[1] << 32) | args[0];
800 #else
801 pc = args[0];
802 #endif
803 if (!first_insn)
804 fprintf(outfile, "\n");
805 fprintf(outfile, " ---- 0x%" PRIx64, pc);
806 first_insn = 0;
807 nb_oargs = def->nb_oargs;
808 nb_iargs = def->nb_iargs;
809 nb_cargs = def->nb_cargs;
810 } else if (c == INDEX_op_call) {
811 TCGArg arg;
813 /* variable number of arguments */
814 arg = *args++;
815 nb_oargs = arg >> 16;
816 nb_iargs = arg & 0xffff;
817 nb_cargs = def->nb_cargs;
819 fprintf(outfile, " %s ", def->name);
821 /* function name */
822 fprintf(outfile, "%s",
823 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1]));
824 /* flags */
825 fprintf(outfile, ",$0x%" TCG_PRIlx,
826 args[nb_oargs + nb_iargs]);
827 /* nb out args */
828 fprintf(outfile, ",$%d", nb_oargs);
829 for(i = 0; i < nb_oargs; i++) {
830 fprintf(outfile, ",");
831 fprintf(outfile, "%s",
832 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i]));
834 for(i = 0; i < (nb_iargs - 1); i++) {
835 fprintf(outfile, ",");
836 if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) {
837 fprintf(outfile, "<dummy>");
838 } else {
839 fprintf(outfile, "%s",
840 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i]));
843 } else if (c == INDEX_op_movi_i32
844 #if TCG_TARGET_REG_BITS == 64
845 || c == INDEX_op_movi_i64
846 #endif
848 tcg_target_ulong val;
849 TCGHelperInfo *th;
851 nb_oargs = def->nb_oargs;
852 nb_iargs = def->nb_iargs;
853 nb_cargs = def->nb_cargs;
854 fprintf(outfile, " %s %s,$", def->name,
855 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0]));
856 val = args[1];
857 th = tcg_find_helper(s, val);
858 if (th) {
859 fprintf(outfile, "%s", th->name);
860 } else {
861 if (c == INDEX_op_movi_i32)
862 fprintf(outfile, "0x%x", (uint32_t)val);
863 else
864 fprintf(outfile, "0x%" PRIx64 , (uint64_t)val);
866 } else {
867 fprintf(outfile, " %s ", def->name);
868 if (c == INDEX_op_nopn) {
869 /* variable number of arguments */
870 nb_cargs = *args;
871 nb_oargs = 0;
872 nb_iargs = 0;
873 } else {
874 nb_oargs = def->nb_oargs;
875 nb_iargs = def->nb_iargs;
876 nb_cargs = def->nb_cargs;
879 k = 0;
880 for(i = 0; i < nb_oargs; i++) {
881 if (k != 0)
882 fprintf(outfile, ",");
883 fprintf(outfile, "%s",
884 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
886 for(i = 0; i < nb_iargs; i++) {
887 if (k != 0)
888 fprintf(outfile, ",");
889 fprintf(outfile, "%s",
890 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
892 switch (c) {
893 case INDEX_op_brcond_i32:
894 #if TCG_TARGET_REG_BITS == 32
895 case INDEX_op_brcond2_i32:
896 #elif TCG_TARGET_REG_BITS == 64
897 case INDEX_op_brcond_i64:
898 #endif
899 case INDEX_op_setcond_i32:
900 #if TCG_TARGET_REG_BITS == 32
901 case INDEX_op_setcond2_i32:
902 #elif TCG_TARGET_REG_BITS == 64
903 case INDEX_op_setcond_i64:
904 #endif
905 if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]])
906 fprintf(outfile, ",%s", cond_name[args[k++]]);
907 else
908 fprintf(outfile, ",$0x%" TCG_PRIlx, args[k++]);
909 i = 1;
910 break;
911 default:
912 i = 0;
913 break;
915 for(; i < nb_cargs; i++) {
916 if (k != 0)
917 fprintf(outfile, ",");
918 arg = args[k++];
919 fprintf(outfile, "$0x%" TCG_PRIlx, arg);
922 fprintf(outfile, "\n");
923 args += nb_iargs + nb_oargs + nb_cargs;
927 /* we give more priority to constraints with less registers */
928 static int get_constraint_priority(const TCGOpDef *def, int k)
930 const TCGArgConstraint *arg_ct;
932 int i, n;
933 arg_ct = &def->args_ct[k];
934 if (arg_ct->ct & TCG_CT_ALIAS) {
935 /* an alias is equivalent to a single register */
936 n = 1;
937 } else {
938 if (!(arg_ct->ct & TCG_CT_REG))
939 return 0;
940 n = 0;
941 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
942 if (tcg_regset_test_reg(arg_ct->u.regs, i))
943 n++;
946 return TCG_TARGET_NB_REGS - n + 1;
949 /* sort from highest priority to lowest */
950 static void sort_constraints(TCGOpDef *def, int start, int n)
952 int i, j, p1, p2, tmp;
954 for(i = 0; i < n; i++)
955 def->sorted_args[start + i] = start + i;
956 if (n <= 1)
957 return;
958 for(i = 0; i < n - 1; i++) {
959 for(j = i + 1; j < n; j++) {
960 p1 = get_constraint_priority(def, def->sorted_args[start + i]);
961 p2 = get_constraint_priority(def, def->sorted_args[start + j]);
962 if (p1 < p2) {
963 tmp = def->sorted_args[start + i];
964 def->sorted_args[start + i] = def->sorted_args[start + j];
965 def->sorted_args[start + j] = tmp;
971 void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
973 int op;
974 TCGOpDef *def;
975 const char *ct_str;
976 int i, nb_args;
978 for(;;) {
979 if (tdefs->op < 0)
980 break;
981 op = tdefs->op;
982 assert(op >= 0 && op < NB_OPS);
983 def = &tcg_op_defs[op];
984 #if defined(CONFIG_DEBUG_TCG)
985 /* Duplicate entry in op definitions? */
986 assert(!def->used);
987 def->used = 1;
988 #endif
989 nb_args = def->nb_iargs + def->nb_oargs;
990 for(i = 0; i < nb_args; i++) {
991 ct_str = tdefs->args_ct_str[i];
992 /* Incomplete TCGTargetOpDef entry? */
993 assert(ct_str != NULL);
994 tcg_regset_clear(def->args_ct[i].u.regs);
995 def->args_ct[i].ct = 0;
996 if (ct_str[0] >= '0' && ct_str[0] <= '9') {
997 int oarg;
998 oarg = ct_str[0] - '0';
999 assert(oarg < def->nb_oargs);
1000 assert(def->args_ct[oarg].ct & TCG_CT_REG);
1001 /* TCG_CT_ALIAS is for the output arguments. The input
1002 argument is tagged with TCG_CT_IALIAS. */
1003 def->args_ct[i] = def->args_ct[oarg];
1004 def->args_ct[oarg].ct = TCG_CT_ALIAS;
1005 def->args_ct[oarg].alias_index = i;
1006 def->args_ct[i].ct |= TCG_CT_IALIAS;
1007 def->args_ct[i].alias_index = oarg;
1008 } else {
1009 for(;;) {
1010 if (*ct_str == '\0')
1011 break;
1012 switch(*ct_str) {
1013 case 'i':
1014 def->args_ct[i].ct |= TCG_CT_CONST;
1015 ct_str++;
1016 break;
1017 default:
1018 if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) {
1019 fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n",
1020 ct_str, i, def->name);
1021 exit(1);
1028 /* TCGTargetOpDef entry with too much information? */
1029 assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
1031 /* sort the constraints (XXX: this is just an heuristic) */
1032 sort_constraints(def, 0, def->nb_oargs);
1033 sort_constraints(def, def->nb_oargs, def->nb_iargs);
1035 #if 0
1037 int i;
1039 printf("%s: sorted=", def->name);
1040 for(i = 0; i < def->nb_oargs + def->nb_iargs; i++)
1041 printf(" %d", def->sorted_args[i]);
1042 printf("\n");
1044 #endif
1045 tdefs++;
1048 #if defined(CONFIG_DEBUG_TCG)
1049 for (op = 0; op < ARRAY_SIZE(tcg_op_defs); op++) {
1050 if (op < INDEX_op_call || op == INDEX_op_debug_insn_start) {
1051 /* Wrong entry in op definitions? */
1052 assert(!tcg_op_defs[op].used);
1053 } else {
1054 /* Missing entry in op definitions? */
1055 assert(tcg_op_defs[op].used);
1058 #endif
1061 #ifdef USE_LIVENESS_ANALYSIS
1063 /* set a nop for an operation using 'nb_args' */
1064 static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr,
1065 TCGArg *args, int nb_args)
1067 if (nb_args == 0) {
1068 *opc_ptr = INDEX_op_nop;
1069 } else {
1070 *opc_ptr = INDEX_op_nopn;
1071 args[0] = nb_args;
1072 args[nb_args - 1] = nb_args;
1076 /* liveness analysis: end of function: globals are live, temps are
1077 dead. */
1078 /* XXX: at this stage, not used as there would be little gains because
1079 most TBs end with a conditional jump. */
1080 static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps)
1082 memset(dead_temps, 0, s->nb_globals);
1083 memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals);
1086 /* liveness analysis: end of basic block: globals are live, temps are
1087 dead, local temps are live. */
1088 static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps)
1090 int i;
1091 TCGTemp *ts;
1093 memset(dead_temps, 0, s->nb_globals);
1094 ts = &s->temps[s->nb_globals];
1095 for(i = s->nb_globals; i < s->nb_temps; i++) {
1096 if (ts->temp_local)
1097 dead_temps[i] = 0;
1098 else
1099 dead_temps[i] = 1;
1100 ts++;
1104 /* Liveness analysis : update the opc_dead_iargs array to tell if a
1105 given input arguments is dead. Instructions updating dead
1106 temporaries are removed. */
1107 static void tcg_liveness_analysis(TCGContext *s)
1109 int i, op_index, op, nb_args, nb_iargs, nb_oargs, arg, nb_ops;
1110 TCGArg *args;
1111 const TCGOpDef *def;
1112 uint8_t *dead_temps;
1113 unsigned int dead_iargs;
1115 gen_opc_ptr++; /* skip end */
1117 nb_ops = gen_opc_ptr - gen_opc_buf;
1119 s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
1121 dead_temps = tcg_malloc(s->nb_temps);
1122 memset(dead_temps, 1, s->nb_temps);
1124 args = gen_opparam_ptr;
1125 op_index = nb_ops - 1;
1126 while (op_index >= 0) {
1127 op = gen_opc_buf[op_index];
1128 def = &tcg_op_defs[op];
1129 switch(op) {
1130 case INDEX_op_call:
1132 int call_flags;
1134 nb_args = args[-1];
1135 args -= nb_args;
1136 nb_iargs = args[0] & 0xffff;
1137 nb_oargs = args[0] >> 16;
1138 args++;
1139 call_flags = args[nb_oargs + nb_iargs];
1141 /* pure functions can be removed if their result is not
1142 used */
1143 if (call_flags & TCG_CALL_PURE) {
1144 for(i = 0; i < nb_oargs; i++) {
1145 arg = args[i];
1146 if (!dead_temps[arg])
1147 goto do_not_remove_call;
1149 tcg_set_nop(s, gen_opc_buf + op_index,
1150 args - 1, nb_args);
1151 } else {
1152 do_not_remove_call:
1154 /* output args are dead */
1155 for(i = 0; i < nb_oargs; i++) {
1156 arg = args[i];
1157 dead_temps[arg] = 1;
1160 if (!(call_flags & TCG_CALL_CONST)) {
1161 /* globals are live (they may be used by the call) */
1162 memset(dead_temps, 0, s->nb_globals);
1165 /* input args are live */
1166 dead_iargs = 0;
1167 for(i = 0; i < nb_iargs; i++) {
1168 arg = args[i + nb_oargs];
1169 if (arg != TCG_CALL_DUMMY_ARG) {
1170 if (dead_temps[arg]) {
1171 dead_iargs |= (1 << i);
1173 dead_temps[arg] = 0;
1176 s->op_dead_iargs[op_index] = dead_iargs;
1178 args--;
1180 break;
1181 case INDEX_op_set_label:
1182 args--;
1183 /* mark end of basic block */
1184 tcg_la_bb_end(s, dead_temps);
1185 break;
1186 case INDEX_op_debug_insn_start:
1187 args -= def->nb_args;
1188 break;
1189 case INDEX_op_nopn:
1190 nb_args = args[-1];
1191 args -= nb_args;
1192 break;
1193 case INDEX_op_discard:
1194 args--;
1195 /* mark the temporary as dead */
1196 dead_temps[args[0]] = 1;
1197 break;
1198 case INDEX_op_end:
1199 break;
1200 /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1201 default:
1202 args -= def->nb_args;
1203 nb_iargs = def->nb_iargs;
1204 nb_oargs = def->nb_oargs;
1206 /* Test if the operation can be removed because all
1207 its outputs are dead. We assume that nb_oargs == 0
1208 implies side effects */
1209 if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
1210 for(i = 0; i < nb_oargs; i++) {
1211 arg = args[i];
1212 if (!dead_temps[arg])
1213 goto do_not_remove;
1215 tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args);
1216 #ifdef CONFIG_PROFILER
1217 s->del_op_count++;
1218 #endif
1219 } else {
1220 do_not_remove:
1222 /* output args are dead */
1223 for(i = 0; i < nb_oargs; i++) {
1224 arg = args[i];
1225 dead_temps[arg] = 1;
1228 /* if end of basic block, update */
1229 if (def->flags & TCG_OPF_BB_END) {
1230 tcg_la_bb_end(s, dead_temps);
1231 } else if (def->flags & TCG_OPF_CALL_CLOBBER) {
1232 /* globals are live */
1233 memset(dead_temps, 0, s->nb_globals);
1236 /* input args are live */
1237 dead_iargs = 0;
1238 for(i = 0; i < nb_iargs; i++) {
1239 arg = args[i + nb_oargs];
1240 if (dead_temps[arg]) {
1241 dead_iargs |= (1 << i);
1243 dead_temps[arg] = 0;
1245 s->op_dead_iargs[op_index] = dead_iargs;
1247 break;
1249 op_index--;
1252 if (args != gen_opparam_buf)
1253 tcg_abort();
1255 #else
1256 /* dummy liveness analysis */
1257 void tcg_liveness_analysis(TCGContext *s)
1259 int nb_ops;
1260 nb_ops = gen_opc_ptr - gen_opc_buf;
1262 s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
1263 memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t));
1265 #endif
1267 #ifndef NDEBUG
1268 static void dump_regs(TCGContext *s)
1270 TCGTemp *ts;
1271 int i;
1272 char buf[64];
1274 for(i = 0; i < s->nb_temps; i++) {
1275 ts = &s->temps[i];
1276 printf(" %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i));
1277 switch(ts->val_type) {
1278 case TEMP_VAL_REG:
1279 printf("%s", tcg_target_reg_names[ts->reg]);
1280 break;
1281 case TEMP_VAL_MEM:
1282 printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]);
1283 break;
1284 case TEMP_VAL_CONST:
1285 printf("$0x%" TCG_PRIlx, ts->val);
1286 break;
1287 case TEMP_VAL_DEAD:
1288 printf("D");
1289 break;
1290 default:
1291 printf("???");
1292 break;
1294 printf("\n");
1297 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
1298 if (s->reg_to_temp[i] >= 0) {
1299 printf("%s: %s\n",
1300 tcg_target_reg_names[i],
1301 tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i]));
1306 static void check_regs(TCGContext *s)
1308 int reg, k;
1309 TCGTemp *ts;
1310 char buf[64];
1312 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1313 k = s->reg_to_temp[reg];
1314 if (k >= 0) {
1315 ts = &s->temps[k];
1316 if (ts->val_type != TEMP_VAL_REG ||
1317 ts->reg != reg) {
1318 printf("Inconsistency for register %s:\n",
1319 tcg_target_reg_names[reg]);
1320 goto fail;
1324 for(k = 0; k < s->nb_temps; k++) {
1325 ts = &s->temps[k];
1326 if (ts->val_type == TEMP_VAL_REG &&
1327 !ts->fixed_reg &&
1328 s->reg_to_temp[ts->reg] != k) {
1329 printf("Inconsistency for temp %s:\n",
1330 tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
1331 fail:
1332 printf("reg state:\n");
1333 dump_regs(s);
1334 tcg_abort();
1338 #endif
1340 static void temp_allocate_frame(TCGContext *s, int temp)
1342 TCGTemp *ts;
1343 ts = &s->temps[temp];
1344 s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1);
1345 if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end)
1346 tcg_abort();
1347 ts->mem_offset = s->current_frame_offset;
1348 ts->mem_reg = s->frame_reg;
1349 ts->mem_allocated = 1;
1350 s->current_frame_offset += sizeof(tcg_target_long);
1353 /* free register 'reg' by spilling the corresponding temporary if necessary */
1354 static void tcg_reg_free(TCGContext *s, int reg)
1356 TCGTemp *ts;
1357 int temp;
1359 temp = s->reg_to_temp[reg];
1360 if (temp != -1) {
1361 ts = &s->temps[temp];
1362 assert(ts->val_type == TEMP_VAL_REG);
1363 if (!ts->mem_coherent) {
1364 if (!ts->mem_allocated)
1365 temp_allocate_frame(s, temp);
1366 tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1368 ts->val_type = TEMP_VAL_MEM;
1369 s->reg_to_temp[reg] = -1;
1373 /* Allocate a register belonging to reg1 & ~reg2 */
1374 static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2)
1376 int i, reg;
1377 TCGRegSet reg_ct;
1379 tcg_regset_andnot(reg_ct, reg1, reg2);
1381 /* first try free registers */
1382 for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
1383 reg = tcg_target_reg_alloc_order[i];
1384 if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1)
1385 return reg;
1388 /* XXX: do better spill choice */
1389 for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
1390 reg = tcg_target_reg_alloc_order[i];
1391 if (tcg_regset_test_reg(reg_ct, reg)) {
1392 tcg_reg_free(s, reg);
1393 return reg;
1397 tcg_abort();
1400 /* save a temporary to memory. 'allocated_regs' is used in case a
1401 temporary registers needs to be allocated to store a constant. */
1402 static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs)
1404 TCGTemp *ts;
1405 int reg;
1407 ts = &s->temps[temp];
1408 if (!ts->fixed_reg) {
1409 switch(ts->val_type) {
1410 case TEMP_VAL_REG:
1411 tcg_reg_free(s, ts->reg);
1412 break;
1413 case TEMP_VAL_DEAD:
1414 ts->val_type = TEMP_VAL_MEM;
1415 break;
1416 case TEMP_VAL_CONST:
1417 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1418 allocated_regs);
1419 if (!ts->mem_allocated)
1420 temp_allocate_frame(s, temp);
1421 tcg_out_movi(s, ts->type, reg, ts->val);
1422 tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1423 ts->val_type = TEMP_VAL_MEM;
1424 break;
1425 case TEMP_VAL_MEM:
1426 break;
1427 default:
1428 tcg_abort();
1433 /* save globals to their cannonical location and assume they can be
1434 modified be the following code. 'allocated_regs' is used in case a
1435 temporary registers needs to be allocated to store a constant. */
1436 static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
1438 int i;
1440 for(i = 0; i < s->nb_globals; i++) {
1441 temp_save(s, i, allocated_regs);
1445 /* at the end of a basic block, we assume all temporaries are dead and
1446 all globals are stored at their canonical location. */
1447 static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
1449 TCGTemp *ts;
1450 int i;
1452 for(i = s->nb_globals; i < s->nb_temps; i++) {
1453 ts = &s->temps[i];
1454 if (ts->temp_local) {
1455 temp_save(s, i, allocated_regs);
1456 } else {
1457 if (ts->val_type == TEMP_VAL_REG) {
1458 s->reg_to_temp[ts->reg] = -1;
1460 ts->val_type = TEMP_VAL_DEAD;
1464 save_globals(s, allocated_regs);
1467 #define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
1469 static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args)
1471 TCGTemp *ots;
1472 tcg_target_ulong val;
1474 ots = &s->temps[args[0]];
1475 val = args[1];
1477 if (ots->fixed_reg) {
1478 /* for fixed registers, we do not do any constant
1479 propagation */
1480 tcg_out_movi(s, ots->type, ots->reg, val);
1481 } else {
1482 /* The movi is not explicitly generated here */
1483 if (ots->val_type == TEMP_VAL_REG)
1484 s->reg_to_temp[ots->reg] = -1;
1485 ots->val_type = TEMP_VAL_CONST;
1486 ots->val = val;
1490 static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
1491 const TCGArg *args,
1492 unsigned int dead_iargs)
1494 TCGTemp *ts, *ots;
1495 int reg;
1496 const TCGArgConstraint *arg_ct;
1498 ots = &s->temps[args[0]];
1499 ts = &s->temps[args[1]];
1500 arg_ct = &def->args_ct[0];
1502 /* XXX: always mark arg dead if IS_DEAD_IARG(0) */
1503 if (ts->val_type == TEMP_VAL_REG) {
1504 if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) {
1505 /* the mov can be suppressed */
1506 if (ots->val_type == TEMP_VAL_REG)
1507 s->reg_to_temp[ots->reg] = -1;
1508 reg = ts->reg;
1509 s->reg_to_temp[reg] = -1;
1510 ts->val_type = TEMP_VAL_DEAD;
1511 } else {
1512 if (ots->val_type == TEMP_VAL_REG) {
1513 reg = ots->reg;
1514 } else {
1515 reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
1517 if (ts->reg != reg) {
1518 tcg_out_mov(s, reg, ts->reg);
1521 } else if (ts->val_type == TEMP_VAL_MEM) {
1522 if (ots->val_type == TEMP_VAL_REG) {
1523 reg = ots->reg;
1524 } else {
1525 reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
1527 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1528 } else if (ts->val_type == TEMP_VAL_CONST) {
1529 if (ots->fixed_reg) {
1530 reg = ots->reg;
1531 tcg_out_movi(s, ots->type, reg, ts->val);
1532 } else {
1533 /* propagate constant */
1534 if (ots->val_type == TEMP_VAL_REG)
1535 s->reg_to_temp[ots->reg] = -1;
1536 ots->val_type = TEMP_VAL_CONST;
1537 ots->val = ts->val;
1538 return;
1540 } else {
1541 tcg_abort();
1543 s->reg_to_temp[reg] = args[0];
1544 ots->reg = reg;
1545 ots->val_type = TEMP_VAL_REG;
1546 ots->mem_coherent = 0;
1549 static void tcg_reg_alloc_op(TCGContext *s,
1550 const TCGOpDef *def, int opc,
1551 const TCGArg *args,
1552 unsigned int dead_iargs)
1554 TCGRegSet allocated_regs;
1555 int i, k, nb_iargs, nb_oargs, reg;
1556 TCGArg arg;
1557 const TCGArgConstraint *arg_ct;
1558 TCGTemp *ts;
1559 TCGArg new_args[TCG_MAX_OP_ARGS];
1560 int const_args[TCG_MAX_OP_ARGS];
1562 nb_oargs = def->nb_oargs;
1563 nb_iargs = def->nb_iargs;
1565 /* copy constants */
1566 memcpy(new_args + nb_oargs + nb_iargs,
1567 args + nb_oargs + nb_iargs,
1568 sizeof(TCGArg) * def->nb_cargs);
1570 /* satisfy input constraints */
1571 tcg_regset_set(allocated_regs, s->reserved_regs);
1572 for(k = 0; k < nb_iargs; k++) {
1573 i = def->sorted_args[nb_oargs + k];
1574 arg = args[i];
1575 arg_ct = &def->args_ct[i];
1576 ts = &s->temps[arg];
1577 if (ts->val_type == TEMP_VAL_MEM) {
1578 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1579 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1580 ts->val_type = TEMP_VAL_REG;
1581 ts->reg = reg;
1582 ts->mem_coherent = 1;
1583 s->reg_to_temp[reg] = arg;
1584 } else if (ts->val_type == TEMP_VAL_CONST) {
1585 if (tcg_target_const_match(ts->val, arg_ct)) {
1586 /* constant is OK for instruction */
1587 const_args[i] = 1;
1588 new_args[i] = ts->val;
1589 goto iarg_end;
1590 } else {
1591 /* need to move to a register */
1592 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1593 tcg_out_movi(s, ts->type, reg, ts->val);
1594 ts->val_type = TEMP_VAL_REG;
1595 ts->reg = reg;
1596 ts->mem_coherent = 0;
1597 s->reg_to_temp[reg] = arg;
1600 assert(ts->val_type == TEMP_VAL_REG);
1601 if (arg_ct->ct & TCG_CT_IALIAS) {
1602 if (ts->fixed_reg) {
1603 /* if fixed register, we must allocate a new register
1604 if the alias is not the same register */
1605 if (arg != args[arg_ct->alias_index])
1606 goto allocate_in_reg;
1607 } else {
1608 /* if the input is aliased to an output and if it is
1609 not dead after the instruction, we must allocate
1610 a new register and move it */
1611 if (!IS_DEAD_IARG(i - nb_oargs))
1612 goto allocate_in_reg;
1615 reg = ts->reg;
1616 if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1617 /* nothing to do : the constraint is satisfied */
1618 } else {
1619 allocate_in_reg:
1620 /* allocate a new register matching the constraint
1621 and move the temporary register into it */
1622 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1623 tcg_out_mov(s, reg, ts->reg);
1625 new_args[i] = reg;
1626 const_args[i] = 0;
1627 tcg_regset_set_reg(allocated_regs, reg);
1628 iarg_end: ;
1631 if (def->flags & TCG_OPF_BB_END) {
1632 tcg_reg_alloc_bb_end(s, allocated_regs);
1633 } else {
1634 /* mark dead temporaries and free the associated registers */
1635 for(i = 0; i < nb_iargs; i++) {
1636 arg = args[nb_oargs + i];
1637 if (IS_DEAD_IARG(i)) {
1638 ts = &s->temps[arg];
1639 if (!ts->fixed_reg) {
1640 if (ts->val_type == TEMP_VAL_REG)
1641 s->reg_to_temp[ts->reg] = -1;
1642 ts->val_type = TEMP_VAL_DEAD;
1647 if (def->flags & TCG_OPF_CALL_CLOBBER) {
1648 /* XXX: permit generic clobber register list ? */
1649 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1650 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
1651 tcg_reg_free(s, reg);
1654 /* XXX: for load/store we could do that only for the slow path
1655 (i.e. when a memory callback is called) */
1657 /* store globals and free associated registers (we assume the insn
1658 can modify any global. */
1659 save_globals(s, allocated_regs);
1662 /* satisfy the output constraints */
1663 tcg_regset_set(allocated_regs, s->reserved_regs);
1664 for(k = 0; k < nb_oargs; k++) {
1665 i = def->sorted_args[k];
1666 arg = args[i];
1667 arg_ct = &def->args_ct[i];
1668 ts = &s->temps[arg];
1669 if (arg_ct->ct & TCG_CT_ALIAS) {
1670 reg = new_args[arg_ct->alias_index];
1671 } else {
1672 /* if fixed register, we try to use it */
1673 reg = ts->reg;
1674 if (ts->fixed_reg &&
1675 tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1676 goto oarg_end;
1678 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1680 tcg_regset_set_reg(allocated_regs, reg);
1681 /* if a fixed register is used, then a move will be done afterwards */
1682 if (!ts->fixed_reg) {
1683 if (ts->val_type == TEMP_VAL_REG)
1684 s->reg_to_temp[ts->reg] = -1;
1685 ts->val_type = TEMP_VAL_REG;
1686 ts->reg = reg;
1687 /* temp value is modified, so the value kept in memory is
1688 potentially not the same */
1689 ts->mem_coherent = 0;
1690 s->reg_to_temp[reg] = arg;
1692 oarg_end:
1693 new_args[i] = reg;
1697 /* emit instruction */
1698 tcg_out_op(s, opc, new_args, const_args);
1700 /* move the outputs in the correct register if needed */
1701 for(i = 0; i < nb_oargs; i++) {
1702 ts = &s->temps[args[i]];
1703 reg = new_args[i];
1704 if (ts->fixed_reg && ts->reg != reg) {
1705 tcg_out_mov(s, ts->reg, reg);
1710 #ifdef TCG_TARGET_STACK_GROWSUP
1711 #define STACK_DIR(x) (-(x))
1712 #else
1713 #define STACK_DIR(x) (x)
1714 #endif
1716 static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
1717 int opc, const TCGArg *args,
1718 unsigned int dead_iargs)
1720 int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params;
1721 TCGArg arg, func_arg;
1722 TCGTemp *ts;
1723 tcg_target_long stack_offset, call_stack_size, func_addr;
1724 int const_func_arg, allocate_args;
1725 TCGRegSet allocated_regs;
1726 const TCGArgConstraint *arg_ct;
1728 arg = *args++;
1730 nb_oargs = arg >> 16;
1731 nb_iargs = arg & 0xffff;
1732 nb_params = nb_iargs - 1;
1734 flags = args[nb_oargs + nb_iargs];
1736 nb_regs = tcg_target_get_call_iarg_regs_count(flags);
1737 if (nb_regs > nb_params)
1738 nb_regs = nb_params;
1740 /* assign stack slots first */
1741 /* XXX: preallocate call stack */
1742 call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);
1743 call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
1744 ~(TCG_TARGET_STACK_ALIGN - 1);
1745 allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
1746 if (allocate_args) {
1747 tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size));
1750 stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
1751 for(i = nb_regs; i < nb_params; i++) {
1752 arg = args[nb_oargs + i];
1753 #ifdef TCG_TARGET_STACK_GROWSUP
1754 stack_offset -= sizeof(tcg_target_long);
1755 #endif
1756 if (arg != TCG_CALL_DUMMY_ARG) {
1757 ts = &s->temps[arg];
1758 if (ts->val_type == TEMP_VAL_REG) {
1759 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
1760 } else if (ts->val_type == TEMP_VAL_MEM) {
1761 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1762 s->reserved_regs);
1763 /* XXX: not correct if reading values from the stack */
1764 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1765 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
1766 } else if (ts->val_type == TEMP_VAL_CONST) {
1767 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1768 s->reserved_regs);
1769 /* XXX: sign extend may be needed on some targets */
1770 tcg_out_movi(s, ts->type, reg, ts->val);
1771 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
1772 } else {
1773 tcg_abort();
1776 #ifndef TCG_TARGET_STACK_GROWSUP
1777 stack_offset += sizeof(tcg_target_long);
1778 #endif
1781 /* assign input registers */
1782 tcg_regset_set(allocated_regs, s->reserved_regs);
1783 for(i = 0; i < nb_regs; i++) {
1784 arg = args[nb_oargs + i];
1785 if (arg != TCG_CALL_DUMMY_ARG) {
1786 ts = &s->temps[arg];
1787 reg = tcg_target_call_iarg_regs[i];
1788 tcg_reg_free(s, reg);
1789 if (ts->val_type == TEMP_VAL_REG) {
1790 if (ts->reg != reg) {
1791 tcg_out_mov(s, reg, ts->reg);
1793 } else if (ts->val_type == TEMP_VAL_MEM) {
1794 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1795 } else if (ts->val_type == TEMP_VAL_CONST) {
1796 /* XXX: sign extend ? */
1797 tcg_out_movi(s, ts->type, reg, ts->val);
1798 } else {
1799 tcg_abort();
1801 tcg_regset_set_reg(allocated_regs, reg);
1805 /* assign function address */
1806 func_arg = args[nb_oargs + nb_iargs - 1];
1807 arg_ct = &def->args_ct[0];
1808 ts = &s->temps[func_arg];
1809 func_addr = ts->val;
1810 const_func_arg = 0;
1811 if (ts->val_type == TEMP_VAL_MEM) {
1812 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1813 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1814 func_arg = reg;
1815 tcg_regset_set_reg(allocated_regs, reg);
1816 } else if (ts->val_type == TEMP_VAL_REG) {
1817 reg = ts->reg;
1818 if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1819 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1820 tcg_out_mov(s, reg, ts->reg);
1822 func_arg = reg;
1823 tcg_regset_set_reg(allocated_regs, reg);
1824 } else if (ts->val_type == TEMP_VAL_CONST) {
1825 if (tcg_target_const_match(func_addr, arg_ct)) {
1826 const_func_arg = 1;
1827 func_arg = func_addr;
1828 } else {
1829 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1830 tcg_out_movi(s, ts->type, reg, func_addr);
1831 func_arg = reg;
1832 tcg_regset_set_reg(allocated_regs, reg);
1834 } else {
1835 tcg_abort();
1839 /* mark dead temporaries and free the associated registers */
1840 for(i = 0; i < nb_iargs; i++) {
1841 arg = args[nb_oargs + i];
1842 if (IS_DEAD_IARG(i)) {
1843 ts = &s->temps[arg];
1844 if (!ts->fixed_reg) {
1845 if (ts->val_type == TEMP_VAL_REG)
1846 s->reg_to_temp[ts->reg] = -1;
1847 ts->val_type = TEMP_VAL_DEAD;
1852 /* clobber call registers */
1853 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1854 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
1855 tcg_reg_free(s, reg);
1859 /* store globals and free associated registers (we assume the call
1860 can modify any global. */
1861 if (!(flags & TCG_CALL_CONST)) {
1862 save_globals(s, allocated_regs);
1865 tcg_out_op(s, opc, &func_arg, &const_func_arg);
1867 if (allocate_args) {
1868 tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size));
1871 /* assign output registers and emit moves if needed */
1872 for(i = 0; i < nb_oargs; i++) {
1873 arg = args[i];
1874 ts = &s->temps[arg];
1875 reg = tcg_target_call_oarg_regs[i];
1876 assert(s->reg_to_temp[reg] == -1);
1877 if (ts->fixed_reg) {
1878 if (ts->reg != reg) {
1879 tcg_out_mov(s, ts->reg, reg);
1881 } else {
1882 if (ts->val_type == TEMP_VAL_REG)
1883 s->reg_to_temp[ts->reg] = -1;
1884 ts->val_type = TEMP_VAL_REG;
1885 ts->reg = reg;
1886 ts->mem_coherent = 0;
1887 s->reg_to_temp[reg] = arg;
1891 return nb_iargs + nb_oargs + def->nb_cargs + 1;
1894 #ifdef CONFIG_PROFILER
1896 static int64_t tcg_table_op_count[NB_OPS];
1898 static void dump_op_count(void)
1900 int i;
1901 FILE *f;
1902 f = fopen("/tmp/op.log", "w");
1903 for(i = INDEX_op_end; i < NB_OPS; i++) {
1904 fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, tcg_table_op_count[i]);
1906 fclose(f);
1908 #endif
1911 static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
1912 long search_pc)
1914 int opc, op_index;
1915 const TCGOpDef *def;
1916 unsigned int dead_iargs;
1917 const TCGArg *args;
1919 #ifdef DEBUG_DISAS
1920 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
1921 qemu_log("OP:\n");
1922 tcg_dump_ops(s, logfile);
1923 qemu_log("\n");
1925 #endif
1927 #ifdef CONFIG_PROFILER
1928 s->la_time -= profile_getclock();
1929 #endif
1930 tcg_liveness_analysis(s);
1931 #ifdef CONFIG_PROFILER
1932 s->la_time += profile_getclock();
1933 #endif
1935 #ifdef DEBUG_DISAS
1936 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) {
1937 qemu_log("OP after liveness analysis:\n");
1938 tcg_dump_ops(s, logfile);
1939 qemu_log("\n");
1941 #endif
1943 tcg_reg_alloc_start(s);
1945 s->code_buf = gen_code_buf;
1946 s->code_ptr = gen_code_buf;
1948 args = gen_opparam_buf;
1949 op_index = 0;
1951 for(;;) {
1952 opc = gen_opc_buf[op_index];
1953 #ifdef CONFIG_PROFILER
1954 tcg_table_op_count[opc]++;
1955 #endif
1956 def = &tcg_op_defs[opc];
1957 #if 0
1958 printf("%s: %d %d %d\n", def->name,
1959 def->nb_oargs, def->nb_iargs, def->nb_cargs);
1960 // dump_regs(s);
1961 #endif
1962 switch(opc) {
1963 case INDEX_op_mov_i32:
1964 #if TCG_TARGET_REG_BITS == 64
1965 case INDEX_op_mov_i64:
1966 #endif
1967 dead_iargs = s->op_dead_iargs[op_index];
1968 tcg_reg_alloc_mov(s, def, args, dead_iargs);
1969 break;
1970 case INDEX_op_movi_i32:
1971 #if TCG_TARGET_REG_BITS == 64
1972 case INDEX_op_movi_i64:
1973 #endif
1974 tcg_reg_alloc_movi(s, args);
1975 break;
1976 case INDEX_op_debug_insn_start:
1977 /* debug instruction */
1978 break;
1979 case INDEX_op_nop:
1980 case INDEX_op_nop1:
1981 case INDEX_op_nop2:
1982 case INDEX_op_nop3:
1983 break;
1984 case INDEX_op_nopn:
1985 args += args[0];
1986 goto next;
1987 case INDEX_op_discard:
1989 TCGTemp *ts;
1990 ts = &s->temps[args[0]];
1991 /* mark the temporary as dead */
1992 if (!ts->fixed_reg) {
1993 if (ts->val_type == TEMP_VAL_REG)
1994 s->reg_to_temp[ts->reg] = -1;
1995 ts->val_type = TEMP_VAL_DEAD;
1998 break;
1999 case INDEX_op_set_label:
2000 tcg_reg_alloc_bb_end(s, s->reserved_regs);
2001 tcg_out_label(s, args[0], (long)s->code_ptr);
2002 break;
2003 case INDEX_op_call:
2004 dead_iargs = s->op_dead_iargs[op_index];
2005 args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs);
2006 goto next;
2007 case INDEX_op_end:
2008 goto the_end;
2009 default:
2010 /* Note: in order to speed up the code, it would be much
2011 faster to have specialized register allocator functions for
2012 some common argument patterns */
2013 dead_iargs = s->op_dead_iargs[op_index];
2014 tcg_reg_alloc_op(s, def, opc, args, dead_iargs);
2015 break;
2017 args += def->nb_args;
2018 next:
2019 if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) {
2020 return op_index;
2022 op_index++;
2023 #ifndef NDEBUG
2024 check_regs(s);
2025 #endif
2027 the_end:
2028 return -1;
2031 int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf)
2033 #ifdef CONFIG_PROFILER
2035 int n;
2036 n = (gen_opc_ptr - gen_opc_buf);
2037 s->op_count += n;
2038 if (n > s->op_count_max)
2039 s->op_count_max = n;
2041 s->temp_count += s->nb_temps;
2042 if (s->nb_temps > s->temp_count_max)
2043 s->temp_count_max = s->nb_temps;
2045 #endif
2047 tcg_gen_code_common(s, gen_code_buf, -1);
2049 /* flush instruction cache */
2050 flush_icache_range((unsigned long)gen_code_buf,
2051 (unsigned long)s->code_ptr);
2052 return s->code_ptr - gen_code_buf;
2055 /* Return the index of the micro operation such as the pc after is <
2056 offset bytes from the start of the TB. The contents of gen_code_buf must
2057 not be changed, though writing the same values is ok.
2058 Return -1 if not found. */
2059 int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset)
2061 return tcg_gen_code_common(s, gen_code_buf, offset);
2064 #ifdef CONFIG_PROFILER
2065 void tcg_dump_info(FILE *f,
2066 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2068 TCGContext *s = &tcg_ctx;
2069 int64_t tot;
2071 tot = s->interm_time + s->code_time;
2072 cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n",
2073 tot, tot / 2.4e9);
2074 cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n",
2075 s->tb_count,
2076 s->tb_count1 - s->tb_count,
2077 s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0);
2078 cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n",
2079 s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max);
2080 cpu_fprintf(f, "deleted ops/TB %0.2f\n",
2081 s->tb_count ?
2082 (double)s->del_op_count / s->tb_count : 0);
2083 cpu_fprintf(f, "avg temps/TB %0.2f max=%d\n",
2084 s->tb_count ?
2085 (double)s->temp_count / s->tb_count : 0,
2086 s->temp_count_max);
2088 cpu_fprintf(f, "cycles/op %0.1f\n",
2089 s->op_count ? (double)tot / s->op_count : 0);
2090 cpu_fprintf(f, "cycles/in byte %0.1f\n",
2091 s->code_in_len ? (double)tot / s->code_in_len : 0);
2092 cpu_fprintf(f, "cycles/out byte %0.1f\n",
2093 s->code_out_len ? (double)tot / s->code_out_len : 0);
2094 if (tot == 0)
2095 tot = 1;
2096 cpu_fprintf(f, " gen_interm time %0.1f%%\n",
2097 (double)s->interm_time / tot * 100.0);
2098 cpu_fprintf(f, " gen_code time %0.1f%%\n",
2099 (double)s->code_time / tot * 100.0);
2100 cpu_fprintf(f, "liveness/code time %0.1f%%\n",
2101 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
2102 cpu_fprintf(f, "cpu_restore count %" PRId64 "\n",
2103 s->restore_count);
2104 cpu_fprintf(f, " avg cycles %0.1f\n",
2105 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
2107 dump_op_count();
2109 #else
2110 void tcg_dump_info(FILE *f,
2111 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2113 cpu_fprintf(f, "[TCG profiler not compiled]\n");
2115 #endif