linux-user: Add the syscall id for pselect6 on ARM
[qemu/kraxel.git] / tcg / tcg.c
blobd753149f76ed37117fe428ef3ce7f5e78edfeed6
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 /* If stack grows up, then we will be placing successive
600 arguments at lower addresses, which means we need to
601 reverse the order compared to how we would normally
602 treat either big or little-endian. For those arguments
603 that will wind up in registers, this still works for
604 HPPA (the only current STACK_GROWSUP target) since the
605 argument registers are *also* allocated in decreasing
606 order. If another such target is added, this logic may
607 have to get more complicated to differentiate between
608 stack arguments and register arguments. */
609 #if defined(TCG_TARGET_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
610 *gen_opparam_ptr++ = args[i] + 1;
611 *gen_opparam_ptr++ = args[i];
612 #else
613 *gen_opparam_ptr++ = args[i];
614 *gen_opparam_ptr++ = args[i] + 1;
615 #endif
616 real_args += 2;
617 } else
618 #endif
620 *gen_opparam_ptr++ = args[i];
621 real_args++;
624 *gen_opparam_ptr++ = GET_TCGV_PTR(func);
626 *gen_opparam_ptr++ = flags;
628 *nparam = (nb_rets << 16) | (real_args + 1);
630 /* total parameters, needed to go backward in the instruction stream */
631 *gen_opparam_ptr++ = 1 + nb_rets + real_args + 3;
634 #if TCG_TARGET_REG_BITS == 32
635 void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
636 int c, int right, int arith)
638 if (c == 0) {
639 tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
640 tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
641 } else if (c >= 32) {
642 c -= 32;
643 if (right) {
644 if (arith) {
645 tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
646 tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31);
647 } else {
648 tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
649 tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
651 } else {
652 tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c);
653 tcg_gen_movi_i32(TCGV_LOW(ret), 0);
655 } else {
656 TCGv_i32 t0, t1;
658 t0 = tcg_temp_new_i32();
659 t1 = tcg_temp_new_i32();
660 if (right) {
661 tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c);
662 if (arith)
663 tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c);
664 else
665 tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c);
666 tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c);
667 tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0);
668 tcg_gen_mov_i32(TCGV_HIGH(ret), t1);
669 } else {
670 tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c);
671 /* Note: ret can be the same as arg1, so we use t1 */
672 tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c);
673 tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c);
674 tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0);
675 tcg_gen_mov_i32(TCGV_LOW(ret), t1);
677 tcg_temp_free_i32(t0);
678 tcg_temp_free_i32(t1);
681 #endif
684 static void tcg_reg_alloc_start(TCGContext *s)
686 int i;
687 TCGTemp *ts;
688 for(i = 0; i < s->nb_globals; i++) {
689 ts = &s->temps[i];
690 if (ts->fixed_reg) {
691 ts->val_type = TEMP_VAL_REG;
692 } else {
693 ts->val_type = TEMP_VAL_MEM;
696 for(i = s->nb_globals; i < s->nb_temps; i++) {
697 ts = &s->temps[i];
698 ts->val_type = TEMP_VAL_DEAD;
699 ts->mem_allocated = 0;
700 ts->fixed_reg = 0;
702 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
703 s->reg_to_temp[i] = -1;
707 static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size,
708 int idx)
710 TCGTemp *ts;
712 ts = &s->temps[idx];
713 if (idx < s->nb_globals) {
714 pstrcpy(buf, buf_size, ts->name);
715 } else {
716 if (ts->temp_local)
717 snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
718 else
719 snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
721 return buf;
724 char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg)
726 return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I32(arg));
729 char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg)
731 return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I64(arg));
734 static int helper_cmp(const void *p1, const void *p2)
736 const TCGHelperInfo *th1 = p1;
737 const TCGHelperInfo *th2 = p2;
738 if (th1->func < th2->func)
739 return -1;
740 else if (th1->func == th2->func)
741 return 0;
742 else
743 return 1;
746 /* find helper definition (Note: A hash table would be better) */
747 static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val)
749 int m, m_min, m_max;
750 TCGHelperInfo *th;
751 tcg_target_ulong v;
753 if (unlikely(!s->helpers_sorted)) {
754 qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo),
755 helper_cmp);
756 s->helpers_sorted = 1;
759 /* binary search */
760 m_min = 0;
761 m_max = s->nb_helpers - 1;
762 while (m_min <= m_max) {
763 m = (m_min + m_max) >> 1;
764 th = &s->helpers[m];
765 v = th->func;
766 if (v == val)
767 return th;
768 else if (val < v) {
769 m_max = m - 1;
770 } else {
771 m_min = m + 1;
774 return NULL;
777 static const char * const cond_name[] =
779 [TCG_COND_EQ] = "eq",
780 [TCG_COND_NE] = "ne",
781 [TCG_COND_LT] = "lt",
782 [TCG_COND_GE] = "ge",
783 [TCG_COND_LE] = "le",
784 [TCG_COND_GT] = "gt",
785 [TCG_COND_LTU] = "ltu",
786 [TCG_COND_GEU] = "geu",
787 [TCG_COND_LEU] = "leu",
788 [TCG_COND_GTU] = "gtu"
791 void tcg_dump_ops(TCGContext *s, FILE *outfile)
793 const uint16_t *opc_ptr;
794 const TCGArg *args;
795 TCGArg arg;
796 int c, i, k, nb_oargs, nb_iargs, nb_cargs, first_insn;
797 const TCGOpDef *def;
798 char buf[128];
800 first_insn = 1;
801 opc_ptr = gen_opc_buf;
802 args = gen_opparam_buf;
803 while (opc_ptr < gen_opc_ptr) {
804 c = *opc_ptr++;
805 def = &tcg_op_defs[c];
806 if (c == INDEX_op_debug_insn_start) {
807 uint64_t pc;
808 #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
809 pc = ((uint64_t)args[1] << 32) | args[0];
810 #else
811 pc = args[0];
812 #endif
813 if (!first_insn)
814 fprintf(outfile, "\n");
815 fprintf(outfile, " ---- 0x%" PRIx64, pc);
816 first_insn = 0;
817 nb_oargs = def->nb_oargs;
818 nb_iargs = def->nb_iargs;
819 nb_cargs = def->nb_cargs;
820 } else if (c == INDEX_op_call) {
821 TCGArg arg;
823 /* variable number of arguments */
824 arg = *args++;
825 nb_oargs = arg >> 16;
826 nb_iargs = arg & 0xffff;
827 nb_cargs = def->nb_cargs;
829 fprintf(outfile, " %s ", def->name);
831 /* function name */
832 fprintf(outfile, "%s",
833 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1]));
834 /* flags */
835 fprintf(outfile, ",$0x%" TCG_PRIlx,
836 args[nb_oargs + nb_iargs]);
837 /* nb out args */
838 fprintf(outfile, ",$%d", nb_oargs);
839 for(i = 0; i < nb_oargs; i++) {
840 fprintf(outfile, ",");
841 fprintf(outfile, "%s",
842 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i]));
844 for(i = 0; i < (nb_iargs - 1); i++) {
845 fprintf(outfile, ",");
846 if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) {
847 fprintf(outfile, "<dummy>");
848 } else {
849 fprintf(outfile, "%s",
850 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i]));
853 } else if (c == INDEX_op_movi_i32
854 #if TCG_TARGET_REG_BITS == 64
855 || c == INDEX_op_movi_i64
856 #endif
858 tcg_target_ulong val;
859 TCGHelperInfo *th;
861 nb_oargs = def->nb_oargs;
862 nb_iargs = def->nb_iargs;
863 nb_cargs = def->nb_cargs;
864 fprintf(outfile, " %s %s,$", def->name,
865 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0]));
866 val = args[1];
867 th = tcg_find_helper(s, val);
868 if (th) {
869 fprintf(outfile, "%s", th->name);
870 } else {
871 if (c == INDEX_op_movi_i32)
872 fprintf(outfile, "0x%x", (uint32_t)val);
873 else
874 fprintf(outfile, "0x%" PRIx64 , (uint64_t)val);
876 } else {
877 fprintf(outfile, " %s ", def->name);
878 if (c == INDEX_op_nopn) {
879 /* variable number of arguments */
880 nb_cargs = *args;
881 nb_oargs = 0;
882 nb_iargs = 0;
883 } else {
884 nb_oargs = def->nb_oargs;
885 nb_iargs = def->nb_iargs;
886 nb_cargs = def->nb_cargs;
889 k = 0;
890 for(i = 0; i < nb_oargs; i++) {
891 if (k != 0)
892 fprintf(outfile, ",");
893 fprintf(outfile, "%s",
894 tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
896 for(i = 0; i < nb_iargs; 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 switch (c) {
903 case INDEX_op_brcond_i32:
904 #if TCG_TARGET_REG_BITS == 32
905 case INDEX_op_brcond2_i32:
906 #elif TCG_TARGET_REG_BITS == 64
907 case INDEX_op_brcond_i64:
908 #endif
909 case INDEX_op_setcond_i32:
910 #if TCG_TARGET_REG_BITS == 32
911 case INDEX_op_setcond2_i32:
912 #elif TCG_TARGET_REG_BITS == 64
913 case INDEX_op_setcond_i64:
914 #endif
915 if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]])
916 fprintf(outfile, ",%s", cond_name[args[k++]]);
917 else
918 fprintf(outfile, ",$0x%" TCG_PRIlx, args[k++]);
919 i = 1;
920 break;
921 default:
922 i = 0;
923 break;
925 for(; i < nb_cargs; i++) {
926 if (k != 0)
927 fprintf(outfile, ",");
928 arg = args[k++];
929 fprintf(outfile, "$0x%" TCG_PRIlx, arg);
932 fprintf(outfile, "\n");
933 args += nb_iargs + nb_oargs + nb_cargs;
937 /* we give more priority to constraints with less registers */
938 static int get_constraint_priority(const TCGOpDef *def, int k)
940 const TCGArgConstraint *arg_ct;
942 int i, n;
943 arg_ct = &def->args_ct[k];
944 if (arg_ct->ct & TCG_CT_ALIAS) {
945 /* an alias is equivalent to a single register */
946 n = 1;
947 } else {
948 if (!(arg_ct->ct & TCG_CT_REG))
949 return 0;
950 n = 0;
951 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
952 if (tcg_regset_test_reg(arg_ct->u.regs, i))
953 n++;
956 return TCG_TARGET_NB_REGS - n + 1;
959 /* sort from highest priority to lowest */
960 static void sort_constraints(TCGOpDef *def, int start, int n)
962 int i, j, p1, p2, tmp;
964 for(i = 0; i < n; i++)
965 def->sorted_args[start + i] = start + i;
966 if (n <= 1)
967 return;
968 for(i = 0; i < n - 1; i++) {
969 for(j = i + 1; j < n; j++) {
970 p1 = get_constraint_priority(def, def->sorted_args[start + i]);
971 p2 = get_constraint_priority(def, def->sorted_args[start + j]);
972 if (p1 < p2) {
973 tmp = def->sorted_args[start + i];
974 def->sorted_args[start + i] = def->sorted_args[start + j];
975 def->sorted_args[start + j] = tmp;
981 void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
983 int op;
984 TCGOpDef *def;
985 const char *ct_str;
986 int i, nb_args;
988 for(;;) {
989 if (tdefs->op < 0)
990 break;
991 op = tdefs->op;
992 assert(op >= 0 && op < NB_OPS);
993 def = &tcg_op_defs[op];
994 #if defined(CONFIG_DEBUG_TCG)
995 /* Duplicate entry in op definitions? */
996 assert(!def->used);
997 def->used = 1;
998 #endif
999 nb_args = def->nb_iargs + def->nb_oargs;
1000 for(i = 0; i < nb_args; i++) {
1001 ct_str = tdefs->args_ct_str[i];
1002 /* Incomplete TCGTargetOpDef entry? */
1003 assert(ct_str != NULL);
1004 tcg_regset_clear(def->args_ct[i].u.regs);
1005 def->args_ct[i].ct = 0;
1006 if (ct_str[0] >= '0' && ct_str[0] <= '9') {
1007 int oarg;
1008 oarg = ct_str[0] - '0';
1009 assert(oarg < def->nb_oargs);
1010 assert(def->args_ct[oarg].ct & TCG_CT_REG);
1011 /* TCG_CT_ALIAS is for the output arguments. The input
1012 argument is tagged with TCG_CT_IALIAS. */
1013 def->args_ct[i] = def->args_ct[oarg];
1014 def->args_ct[oarg].ct = TCG_CT_ALIAS;
1015 def->args_ct[oarg].alias_index = i;
1016 def->args_ct[i].ct |= TCG_CT_IALIAS;
1017 def->args_ct[i].alias_index = oarg;
1018 } else {
1019 for(;;) {
1020 if (*ct_str == '\0')
1021 break;
1022 switch(*ct_str) {
1023 case 'i':
1024 def->args_ct[i].ct |= TCG_CT_CONST;
1025 ct_str++;
1026 break;
1027 default:
1028 if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) {
1029 fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n",
1030 ct_str, i, def->name);
1031 exit(1);
1038 /* TCGTargetOpDef entry with too much information? */
1039 assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
1041 /* sort the constraints (XXX: this is just an heuristic) */
1042 sort_constraints(def, 0, def->nb_oargs);
1043 sort_constraints(def, def->nb_oargs, def->nb_iargs);
1045 #if 0
1047 int i;
1049 printf("%s: sorted=", def->name);
1050 for(i = 0; i < def->nb_oargs + def->nb_iargs; i++)
1051 printf(" %d", def->sorted_args[i]);
1052 printf("\n");
1054 #endif
1055 tdefs++;
1058 #if defined(CONFIG_DEBUG_TCG)
1059 for (op = 0; op < ARRAY_SIZE(tcg_op_defs); op++) {
1060 if (op < INDEX_op_call || op == INDEX_op_debug_insn_start) {
1061 /* Wrong entry in op definitions? */
1062 assert(!tcg_op_defs[op].used);
1063 } else {
1064 /* Missing entry in op definitions? */
1065 assert(tcg_op_defs[op].used);
1068 #endif
1071 #ifdef USE_LIVENESS_ANALYSIS
1073 /* set a nop for an operation using 'nb_args' */
1074 static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr,
1075 TCGArg *args, int nb_args)
1077 if (nb_args == 0) {
1078 *opc_ptr = INDEX_op_nop;
1079 } else {
1080 *opc_ptr = INDEX_op_nopn;
1081 args[0] = nb_args;
1082 args[nb_args - 1] = nb_args;
1086 /* liveness analysis: end of function: globals are live, temps are
1087 dead. */
1088 /* XXX: at this stage, not used as there would be little gains because
1089 most TBs end with a conditional jump. */
1090 static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps)
1092 memset(dead_temps, 0, s->nb_globals);
1093 memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals);
1096 /* liveness analysis: end of basic block: globals are live, temps are
1097 dead, local temps are live. */
1098 static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps)
1100 int i;
1101 TCGTemp *ts;
1103 memset(dead_temps, 0, s->nb_globals);
1104 ts = &s->temps[s->nb_globals];
1105 for(i = s->nb_globals; i < s->nb_temps; i++) {
1106 if (ts->temp_local)
1107 dead_temps[i] = 0;
1108 else
1109 dead_temps[i] = 1;
1110 ts++;
1114 /* Liveness analysis : update the opc_dead_iargs array to tell if a
1115 given input arguments is dead. Instructions updating dead
1116 temporaries are removed. */
1117 static void tcg_liveness_analysis(TCGContext *s)
1119 int i, op_index, op, nb_args, nb_iargs, nb_oargs, arg, nb_ops;
1120 TCGArg *args;
1121 const TCGOpDef *def;
1122 uint8_t *dead_temps;
1123 unsigned int dead_iargs;
1125 gen_opc_ptr++; /* skip end */
1127 nb_ops = gen_opc_ptr - gen_opc_buf;
1129 s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
1131 dead_temps = tcg_malloc(s->nb_temps);
1132 memset(dead_temps, 1, s->nb_temps);
1134 args = gen_opparam_ptr;
1135 op_index = nb_ops - 1;
1136 while (op_index >= 0) {
1137 op = gen_opc_buf[op_index];
1138 def = &tcg_op_defs[op];
1139 switch(op) {
1140 case INDEX_op_call:
1142 int call_flags;
1144 nb_args = args[-1];
1145 args -= nb_args;
1146 nb_iargs = args[0] & 0xffff;
1147 nb_oargs = args[0] >> 16;
1148 args++;
1149 call_flags = args[nb_oargs + nb_iargs];
1151 /* pure functions can be removed if their result is not
1152 used */
1153 if (call_flags & TCG_CALL_PURE) {
1154 for(i = 0; i < nb_oargs; i++) {
1155 arg = args[i];
1156 if (!dead_temps[arg])
1157 goto do_not_remove_call;
1159 tcg_set_nop(s, gen_opc_buf + op_index,
1160 args - 1, nb_args);
1161 } else {
1162 do_not_remove_call:
1164 /* output args are dead */
1165 for(i = 0; i < nb_oargs; i++) {
1166 arg = args[i];
1167 dead_temps[arg] = 1;
1170 if (!(call_flags & TCG_CALL_CONST)) {
1171 /* globals are live (they may be used by the call) */
1172 memset(dead_temps, 0, s->nb_globals);
1175 /* input args are live */
1176 dead_iargs = 0;
1177 for(i = 0; i < nb_iargs; i++) {
1178 arg = args[i + nb_oargs];
1179 if (arg != TCG_CALL_DUMMY_ARG) {
1180 if (dead_temps[arg]) {
1181 dead_iargs |= (1 << i);
1183 dead_temps[arg] = 0;
1186 s->op_dead_iargs[op_index] = dead_iargs;
1188 args--;
1190 break;
1191 case INDEX_op_set_label:
1192 args--;
1193 /* mark end of basic block */
1194 tcg_la_bb_end(s, dead_temps);
1195 break;
1196 case INDEX_op_debug_insn_start:
1197 args -= def->nb_args;
1198 break;
1199 case INDEX_op_nopn:
1200 nb_args = args[-1];
1201 args -= nb_args;
1202 break;
1203 case INDEX_op_discard:
1204 args--;
1205 /* mark the temporary as dead */
1206 dead_temps[args[0]] = 1;
1207 break;
1208 case INDEX_op_end:
1209 break;
1210 /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1211 default:
1212 args -= def->nb_args;
1213 nb_iargs = def->nb_iargs;
1214 nb_oargs = def->nb_oargs;
1216 /* Test if the operation can be removed because all
1217 its outputs are dead. We assume that nb_oargs == 0
1218 implies side effects */
1219 if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
1220 for(i = 0; i < nb_oargs; i++) {
1221 arg = args[i];
1222 if (!dead_temps[arg])
1223 goto do_not_remove;
1225 tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args);
1226 #ifdef CONFIG_PROFILER
1227 s->del_op_count++;
1228 #endif
1229 } else {
1230 do_not_remove:
1232 /* output args are dead */
1233 for(i = 0; i < nb_oargs; i++) {
1234 arg = args[i];
1235 dead_temps[arg] = 1;
1238 /* if end of basic block, update */
1239 if (def->flags & TCG_OPF_BB_END) {
1240 tcg_la_bb_end(s, dead_temps);
1241 } else if (def->flags & TCG_OPF_CALL_CLOBBER) {
1242 /* globals are live */
1243 memset(dead_temps, 0, s->nb_globals);
1246 /* input args are live */
1247 dead_iargs = 0;
1248 for(i = 0; i < nb_iargs; i++) {
1249 arg = args[i + nb_oargs];
1250 if (dead_temps[arg]) {
1251 dead_iargs |= (1 << i);
1253 dead_temps[arg] = 0;
1255 s->op_dead_iargs[op_index] = dead_iargs;
1257 break;
1259 op_index--;
1262 if (args != gen_opparam_buf)
1263 tcg_abort();
1265 #else
1266 /* dummy liveness analysis */
1267 void tcg_liveness_analysis(TCGContext *s)
1269 int nb_ops;
1270 nb_ops = gen_opc_ptr - gen_opc_buf;
1272 s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
1273 memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t));
1275 #endif
1277 #ifndef NDEBUG
1278 static void dump_regs(TCGContext *s)
1280 TCGTemp *ts;
1281 int i;
1282 char buf[64];
1284 for(i = 0; i < s->nb_temps; i++) {
1285 ts = &s->temps[i];
1286 printf(" %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i));
1287 switch(ts->val_type) {
1288 case TEMP_VAL_REG:
1289 printf("%s", tcg_target_reg_names[ts->reg]);
1290 break;
1291 case TEMP_VAL_MEM:
1292 printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]);
1293 break;
1294 case TEMP_VAL_CONST:
1295 printf("$0x%" TCG_PRIlx, ts->val);
1296 break;
1297 case TEMP_VAL_DEAD:
1298 printf("D");
1299 break;
1300 default:
1301 printf("???");
1302 break;
1304 printf("\n");
1307 for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
1308 if (s->reg_to_temp[i] >= 0) {
1309 printf("%s: %s\n",
1310 tcg_target_reg_names[i],
1311 tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i]));
1316 static void check_regs(TCGContext *s)
1318 int reg, k;
1319 TCGTemp *ts;
1320 char buf[64];
1322 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1323 k = s->reg_to_temp[reg];
1324 if (k >= 0) {
1325 ts = &s->temps[k];
1326 if (ts->val_type != TEMP_VAL_REG ||
1327 ts->reg != reg) {
1328 printf("Inconsistency for register %s:\n",
1329 tcg_target_reg_names[reg]);
1330 goto fail;
1334 for(k = 0; k < s->nb_temps; k++) {
1335 ts = &s->temps[k];
1336 if (ts->val_type == TEMP_VAL_REG &&
1337 !ts->fixed_reg &&
1338 s->reg_to_temp[ts->reg] != k) {
1339 printf("Inconsistency for temp %s:\n",
1340 tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
1341 fail:
1342 printf("reg state:\n");
1343 dump_regs(s);
1344 tcg_abort();
1348 #endif
1350 static void temp_allocate_frame(TCGContext *s, int temp)
1352 TCGTemp *ts;
1353 ts = &s->temps[temp];
1354 s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1);
1355 if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end)
1356 tcg_abort();
1357 ts->mem_offset = s->current_frame_offset;
1358 ts->mem_reg = s->frame_reg;
1359 ts->mem_allocated = 1;
1360 s->current_frame_offset += sizeof(tcg_target_long);
1363 /* free register 'reg' by spilling the corresponding temporary if necessary */
1364 static void tcg_reg_free(TCGContext *s, int reg)
1366 TCGTemp *ts;
1367 int temp;
1369 temp = s->reg_to_temp[reg];
1370 if (temp != -1) {
1371 ts = &s->temps[temp];
1372 assert(ts->val_type == TEMP_VAL_REG);
1373 if (!ts->mem_coherent) {
1374 if (!ts->mem_allocated)
1375 temp_allocate_frame(s, temp);
1376 tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1378 ts->val_type = TEMP_VAL_MEM;
1379 s->reg_to_temp[reg] = -1;
1383 /* Allocate a register belonging to reg1 & ~reg2 */
1384 static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2)
1386 int i, reg;
1387 TCGRegSet reg_ct;
1389 tcg_regset_andnot(reg_ct, reg1, reg2);
1391 /* first try free registers */
1392 for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
1393 reg = tcg_target_reg_alloc_order[i];
1394 if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1)
1395 return reg;
1398 /* XXX: do better spill choice */
1399 for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
1400 reg = tcg_target_reg_alloc_order[i];
1401 if (tcg_regset_test_reg(reg_ct, reg)) {
1402 tcg_reg_free(s, reg);
1403 return reg;
1407 tcg_abort();
1410 /* save a temporary to memory. 'allocated_regs' is used in case a
1411 temporary registers needs to be allocated to store a constant. */
1412 static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs)
1414 TCGTemp *ts;
1415 int reg;
1417 ts = &s->temps[temp];
1418 if (!ts->fixed_reg) {
1419 switch(ts->val_type) {
1420 case TEMP_VAL_REG:
1421 tcg_reg_free(s, ts->reg);
1422 break;
1423 case TEMP_VAL_DEAD:
1424 ts->val_type = TEMP_VAL_MEM;
1425 break;
1426 case TEMP_VAL_CONST:
1427 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1428 allocated_regs);
1429 if (!ts->mem_allocated)
1430 temp_allocate_frame(s, temp);
1431 tcg_out_movi(s, ts->type, reg, ts->val);
1432 tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1433 ts->val_type = TEMP_VAL_MEM;
1434 break;
1435 case TEMP_VAL_MEM:
1436 break;
1437 default:
1438 tcg_abort();
1443 /* save globals to their cannonical location and assume they can be
1444 modified be the following code. 'allocated_regs' is used in case a
1445 temporary registers needs to be allocated to store a constant. */
1446 static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
1448 int i;
1450 for(i = 0; i < s->nb_globals; i++) {
1451 temp_save(s, i, allocated_regs);
1455 /* at the end of a basic block, we assume all temporaries are dead and
1456 all globals are stored at their canonical location. */
1457 static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
1459 TCGTemp *ts;
1460 int i;
1462 for(i = s->nb_globals; i < s->nb_temps; i++) {
1463 ts = &s->temps[i];
1464 if (ts->temp_local) {
1465 temp_save(s, i, allocated_regs);
1466 } else {
1467 if (ts->val_type == TEMP_VAL_REG) {
1468 s->reg_to_temp[ts->reg] = -1;
1470 ts->val_type = TEMP_VAL_DEAD;
1474 save_globals(s, allocated_regs);
1477 #define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
1479 static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args)
1481 TCGTemp *ots;
1482 tcg_target_ulong val;
1484 ots = &s->temps[args[0]];
1485 val = args[1];
1487 if (ots->fixed_reg) {
1488 /* for fixed registers, we do not do any constant
1489 propagation */
1490 tcg_out_movi(s, ots->type, ots->reg, val);
1491 } else {
1492 /* The movi is not explicitly generated here */
1493 if (ots->val_type == TEMP_VAL_REG)
1494 s->reg_to_temp[ots->reg] = -1;
1495 ots->val_type = TEMP_VAL_CONST;
1496 ots->val = val;
1500 static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
1501 const TCGArg *args,
1502 unsigned int dead_iargs)
1504 TCGTemp *ts, *ots;
1505 int reg;
1506 const TCGArgConstraint *arg_ct;
1508 ots = &s->temps[args[0]];
1509 ts = &s->temps[args[1]];
1510 arg_ct = &def->args_ct[0];
1512 /* XXX: always mark arg dead if IS_DEAD_IARG(0) */
1513 if (ts->val_type == TEMP_VAL_REG) {
1514 if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) {
1515 /* the mov can be suppressed */
1516 if (ots->val_type == TEMP_VAL_REG)
1517 s->reg_to_temp[ots->reg] = -1;
1518 reg = ts->reg;
1519 s->reg_to_temp[reg] = -1;
1520 ts->val_type = TEMP_VAL_DEAD;
1521 } else {
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 if (ts->reg != reg) {
1528 tcg_out_mov(s, reg, ts->reg);
1531 } else if (ts->val_type == TEMP_VAL_MEM) {
1532 if (ots->val_type == TEMP_VAL_REG) {
1533 reg = ots->reg;
1534 } else {
1535 reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
1537 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1538 } else if (ts->val_type == TEMP_VAL_CONST) {
1539 if (ots->fixed_reg) {
1540 reg = ots->reg;
1541 tcg_out_movi(s, ots->type, reg, ts->val);
1542 } else {
1543 /* propagate constant */
1544 if (ots->val_type == TEMP_VAL_REG)
1545 s->reg_to_temp[ots->reg] = -1;
1546 ots->val_type = TEMP_VAL_CONST;
1547 ots->val = ts->val;
1548 return;
1550 } else {
1551 tcg_abort();
1553 s->reg_to_temp[reg] = args[0];
1554 ots->reg = reg;
1555 ots->val_type = TEMP_VAL_REG;
1556 ots->mem_coherent = 0;
1559 static void tcg_reg_alloc_op(TCGContext *s,
1560 const TCGOpDef *def, int opc,
1561 const TCGArg *args,
1562 unsigned int dead_iargs)
1564 TCGRegSet allocated_regs;
1565 int i, k, nb_iargs, nb_oargs, reg;
1566 TCGArg arg;
1567 const TCGArgConstraint *arg_ct;
1568 TCGTemp *ts;
1569 TCGArg new_args[TCG_MAX_OP_ARGS];
1570 int const_args[TCG_MAX_OP_ARGS];
1572 nb_oargs = def->nb_oargs;
1573 nb_iargs = def->nb_iargs;
1575 /* copy constants */
1576 memcpy(new_args + nb_oargs + nb_iargs,
1577 args + nb_oargs + nb_iargs,
1578 sizeof(TCGArg) * def->nb_cargs);
1580 /* satisfy input constraints */
1581 tcg_regset_set(allocated_regs, s->reserved_regs);
1582 for(k = 0; k < nb_iargs; k++) {
1583 i = def->sorted_args[nb_oargs + k];
1584 arg = args[i];
1585 arg_ct = &def->args_ct[i];
1586 ts = &s->temps[arg];
1587 if (ts->val_type == TEMP_VAL_MEM) {
1588 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1589 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1590 ts->val_type = TEMP_VAL_REG;
1591 ts->reg = reg;
1592 ts->mem_coherent = 1;
1593 s->reg_to_temp[reg] = arg;
1594 } else if (ts->val_type == TEMP_VAL_CONST) {
1595 if (tcg_target_const_match(ts->val, arg_ct)) {
1596 /* constant is OK for instruction */
1597 const_args[i] = 1;
1598 new_args[i] = ts->val;
1599 goto iarg_end;
1600 } else {
1601 /* need to move to a register */
1602 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1603 tcg_out_movi(s, ts->type, reg, ts->val);
1604 ts->val_type = TEMP_VAL_REG;
1605 ts->reg = reg;
1606 ts->mem_coherent = 0;
1607 s->reg_to_temp[reg] = arg;
1610 assert(ts->val_type == TEMP_VAL_REG);
1611 if (arg_ct->ct & TCG_CT_IALIAS) {
1612 if (ts->fixed_reg) {
1613 /* if fixed register, we must allocate a new register
1614 if the alias is not the same register */
1615 if (arg != args[arg_ct->alias_index])
1616 goto allocate_in_reg;
1617 } else {
1618 /* if the input is aliased to an output and if it is
1619 not dead after the instruction, we must allocate
1620 a new register and move it */
1621 if (!IS_DEAD_IARG(i - nb_oargs))
1622 goto allocate_in_reg;
1625 reg = ts->reg;
1626 if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1627 /* nothing to do : the constraint is satisfied */
1628 } else {
1629 allocate_in_reg:
1630 /* allocate a new register matching the constraint
1631 and move the temporary register into it */
1632 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1633 tcg_out_mov(s, reg, ts->reg);
1635 new_args[i] = reg;
1636 const_args[i] = 0;
1637 tcg_regset_set_reg(allocated_regs, reg);
1638 iarg_end: ;
1641 if (def->flags & TCG_OPF_BB_END) {
1642 tcg_reg_alloc_bb_end(s, allocated_regs);
1643 } else {
1644 /* mark dead temporaries and free the associated registers */
1645 for(i = 0; i < nb_iargs; i++) {
1646 arg = args[nb_oargs + i];
1647 if (IS_DEAD_IARG(i)) {
1648 ts = &s->temps[arg];
1649 if (!ts->fixed_reg) {
1650 if (ts->val_type == TEMP_VAL_REG)
1651 s->reg_to_temp[ts->reg] = -1;
1652 ts->val_type = TEMP_VAL_DEAD;
1657 if (def->flags & TCG_OPF_CALL_CLOBBER) {
1658 /* XXX: permit generic clobber register list ? */
1659 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1660 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
1661 tcg_reg_free(s, reg);
1664 /* XXX: for load/store we could do that only for the slow path
1665 (i.e. when a memory callback is called) */
1667 /* store globals and free associated registers (we assume the insn
1668 can modify any global. */
1669 save_globals(s, allocated_regs);
1672 /* satisfy the output constraints */
1673 tcg_regset_set(allocated_regs, s->reserved_regs);
1674 for(k = 0; k < nb_oargs; k++) {
1675 i = def->sorted_args[k];
1676 arg = args[i];
1677 arg_ct = &def->args_ct[i];
1678 ts = &s->temps[arg];
1679 if (arg_ct->ct & TCG_CT_ALIAS) {
1680 reg = new_args[arg_ct->alias_index];
1681 } else {
1682 /* if fixed register, we try to use it */
1683 reg = ts->reg;
1684 if (ts->fixed_reg &&
1685 tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1686 goto oarg_end;
1688 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1690 tcg_regset_set_reg(allocated_regs, reg);
1691 /* if a fixed register is used, then a move will be done afterwards */
1692 if (!ts->fixed_reg) {
1693 if (ts->val_type == TEMP_VAL_REG)
1694 s->reg_to_temp[ts->reg] = -1;
1695 ts->val_type = TEMP_VAL_REG;
1696 ts->reg = reg;
1697 /* temp value is modified, so the value kept in memory is
1698 potentially not the same */
1699 ts->mem_coherent = 0;
1700 s->reg_to_temp[reg] = arg;
1702 oarg_end:
1703 new_args[i] = reg;
1707 /* emit instruction */
1708 tcg_out_op(s, opc, new_args, const_args);
1710 /* move the outputs in the correct register if needed */
1711 for(i = 0; i < nb_oargs; i++) {
1712 ts = &s->temps[args[i]];
1713 reg = new_args[i];
1714 if (ts->fixed_reg && ts->reg != reg) {
1715 tcg_out_mov(s, ts->reg, reg);
1720 #ifdef TCG_TARGET_STACK_GROWSUP
1721 #define STACK_DIR(x) (-(x))
1722 #else
1723 #define STACK_DIR(x) (x)
1724 #endif
1726 static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
1727 int opc, const TCGArg *args,
1728 unsigned int dead_iargs)
1730 int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params;
1731 TCGArg arg, func_arg;
1732 TCGTemp *ts;
1733 tcg_target_long stack_offset, call_stack_size, func_addr;
1734 int const_func_arg, allocate_args;
1735 TCGRegSet allocated_regs;
1736 const TCGArgConstraint *arg_ct;
1738 arg = *args++;
1740 nb_oargs = arg >> 16;
1741 nb_iargs = arg & 0xffff;
1742 nb_params = nb_iargs - 1;
1744 flags = args[nb_oargs + nb_iargs];
1746 nb_regs = tcg_target_get_call_iarg_regs_count(flags);
1747 if (nb_regs > nb_params)
1748 nb_regs = nb_params;
1750 /* assign stack slots first */
1751 /* XXX: preallocate call stack */
1752 call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);
1753 call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
1754 ~(TCG_TARGET_STACK_ALIGN - 1);
1755 allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
1756 if (allocate_args) {
1757 tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size));
1760 stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
1761 for(i = nb_regs; i < nb_params; i++) {
1762 arg = args[nb_oargs + i];
1763 #ifdef TCG_TARGET_STACK_GROWSUP
1764 stack_offset -= sizeof(tcg_target_long);
1765 #endif
1766 if (arg != TCG_CALL_DUMMY_ARG) {
1767 ts = &s->temps[arg];
1768 if (ts->val_type == TEMP_VAL_REG) {
1769 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
1770 } else if (ts->val_type == TEMP_VAL_MEM) {
1771 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1772 s->reserved_regs);
1773 /* XXX: not correct if reading values from the stack */
1774 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1775 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
1776 } else if (ts->val_type == TEMP_VAL_CONST) {
1777 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
1778 s->reserved_regs);
1779 /* XXX: sign extend may be needed on some targets */
1780 tcg_out_movi(s, ts->type, reg, ts->val);
1781 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
1782 } else {
1783 tcg_abort();
1786 #ifndef TCG_TARGET_STACK_GROWSUP
1787 stack_offset += sizeof(tcg_target_long);
1788 #endif
1791 /* assign input registers */
1792 tcg_regset_set(allocated_regs, s->reserved_regs);
1793 for(i = 0; i < nb_regs; i++) {
1794 arg = args[nb_oargs + i];
1795 if (arg != TCG_CALL_DUMMY_ARG) {
1796 ts = &s->temps[arg];
1797 reg = tcg_target_call_iarg_regs[i];
1798 tcg_reg_free(s, reg);
1799 if (ts->val_type == TEMP_VAL_REG) {
1800 if (ts->reg != reg) {
1801 tcg_out_mov(s, reg, ts->reg);
1803 } else if (ts->val_type == TEMP_VAL_MEM) {
1804 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1805 } else if (ts->val_type == TEMP_VAL_CONST) {
1806 /* XXX: sign extend ? */
1807 tcg_out_movi(s, ts->type, reg, ts->val);
1808 } else {
1809 tcg_abort();
1811 tcg_regset_set_reg(allocated_regs, reg);
1815 /* assign function address */
1816 func_arg = args[nb_oargs + nb_iargs - 1];
1817 arg_ct = &def->args_ct[0];
1818 ts = &s->temps[func_arg];
1819 func_addr = ts->val;
1820 const_func_arg = 0;
1821 if (ts->val_type == TEMP_VAL_MEM) {
1822 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1823 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
1824 func_arg = reg;
1825 tcg_regset_set_reg(allocated_regs, reg);
1826 } else if (ts->val_type == TEMP_VAL_REG) {
1827 reg = ts->reg;
1828 if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) {
1829 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1830 tcg_out_mov(s, reg, ts->reg);
1832 func_arg = reg;
1833 tcg_regset_set_reg(allocated_regs, reg);
1834 } else if (ts->val_type == TEMP_VAL_CONST) {
1835 if (tcg_target_const_match(func_addr, arg_ct)) {
1836 const_func_arg = 1;
1837 func_arg = func_addr;
1838 } else {
1839 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
1840 tcg_out_movi(s, ts->type, reg, func_addr);
1841 func_arg = reg;
1842 tcg_regset_set_reg(allocated_regs, reg);
1844 } else {
1845 tcg_abort();
1849 /* mark dead temporaries and free the associated registers */
1850 for(i = 0; i < nb_iargs; i++) {
1851 arg = args[nb_oargs + i];
1852 if (IS_DEAD_IARG(i)) {
1853 ts = &s->temps[arg];
1854 if (!ts->fixed_reg) {
1855 if (ts->val_type == TEMP_VAL_REG)
1856 s->reg_to_temp[ts->reg] = -1;
1857 ts->val_type = TEMP_VAL_DEAD;
1862 /* clobber call registers */
1863 for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
1864 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
1865 tcg_reg_free(s, reg);
1869 /* store globals and free associated registers (we assume the call
1870 can modify any global. */
1871 if (!(flags & TCG_CALL_CONST)) {
1872 save_globals(s, allocated_regs);
1875 tcg_out_op(s, opc, &func_arg, &const_func_arg);
1877 if (allocate_args) {
1878 tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size));
1881 /* assign output registers and emit moves if needed */
1882 for(i = 0; i < nb_oargs; i++) {
1883 arg = args[i];
1884 ts = &s->temps[arg];
1885 reg = tcg_target_call_oarg_regs[i];
1886 assert(s->reg_to_temp[reg] == -1);
1887 if (ts->fixed_reg) {
1888 if (ts->reg != reg) {
1889 tcg_out_mov(s, ts->reg, reg);
1891 } else {
1892 if (ts->val_type == TEMP_VAL_REG)
1893 s->reg_to_temp[ts->reg] = -1;
1894 ts->val_type = TEMP_VAL_REG;
1895 ts->reg = reg;
1896 ts->mem_coherent = 0;
1897 s->reg_to_temp[reg] = arg;
1901 return nb_iargs + nb_oargs + def->nb_cargs + 1;
1904 #ifdef CONFIG_PROFILER
1906 static int64_t tcg_table_op_count[NB_OPS];
1908 static void dump_op_count(void)
1910 int i;
1911 FILE *f;
1912 f = fopen("/tmp/op.log", "w");
1913 for(i = INDEX_op_end; i < NB_OPS; i++) {
1914 fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, tcg_table_op_count[i]);
1916 fclose(f);
1918 #endif
1921 static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
1922 long search_pc)
1924 int opc, op_index;
1925 const TCGOpDef *def;
1926 unsigned int dead_iargs;
1927 const TCGArg *args;
1929 #ifdef DEBUG_DISAS
1930 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
1931 qemu_log("OP:\n");
1932 tcg_dump_ops(s, logfile);
1933 qemu_log("\n");
1935 #endif
1937 #ifdef CONFIG_PROFILER
1938 s->la_time -= profile_getclock();
1939 #endif
1940 tcg_liveness_analysis(s);
1941 #ifdef CONFIG_PROFILER
1942 s->la_time += profile_getclock();
1943 #endif
1945 #ifdef DEBUG_DISAS
1946 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) {
1947 qemu_log("OP after liveness analysis:\n");
1948 tcg_dump_ops(s, logfile);
1949 qemu_log("\n");
1951 #endif
1953 tcg_reg_alloc_start(s);
1955 s->code_buf = gen_code_buf;
1956 s->code_ptr = gen_code_buf;
1958 args = gen_opparam_buf;
1959 op_index = 0;
1961 for(;;) {
1962 opc = gen_opc_buf[op_index];
1963 #ifdef CONFIG_PROFILER
1964 tcg_table_op_count[opc]++;
1965 #endif
1966 def = &tcg_op_defs[opc];
1967 #if 0
1968 printf("%s: %d %d %d\n", def->name,
1969 def->nb_oargs, def->nb_iargs, def->nb_cargs);
1970 // dump_regs(s);
1971 #endif
1972 switch(opc) {
1973 case INDEX_op_mov_i32:
1974 #if TCG_TARGET_REG_BITS == 64
1975 case INDEX_op_mov_i64:
1976 #endif
1977 dead_iargs = s->op_dead_iargs[op_index];
1978 tcg_reg_alloc_mov(s, def, args, dead_iargs);
1979 break;
1980 case INDEX_op_movi_i32:
1981 #if TCG_TARGET_REG_BITS == 64
1982 case INDEX_op_movi_i64:
1983 #endif
1984 tcg_reg_alloc_movi(s, args);
1985 break;
1986 case INDEX_op_debug_insn_start:
1987 /* debug instruction */
1988 break;
1989 case INDEX_op_nop:
1990 case INDEX_op_nop1:
1991 case INDEX_op_nop2:
1992 case INDEX_op_nop3:
1993 break;
1994 case INDEX_op_nopn:
1995 args += args[0];
1996 goto next;
1997 case INDEX_op_discard:
1999 TCGTemp *ts;
2000 ts = &s->temps[args[0]];
2001 /* mark the temporary as dead */
2002 if (!ts->fixed_reg) {
2003 if (ts->val_type == TEMP_VAL_REG)
2004 s->reg_to_temp[ts->reg] = -1;
2005 ts->val_type = TEMP_VAL_DEAD;
2008 break;
2009 case INDEX_op_set_label:
2010 tcg_reg_alloc_bb_end(s, s->reserved_regs);
2011 tcg_out_label(s, args[0], (long)s->code_ptr);
2012 break;
2013 case INDEX_op_call:
2014 dead_iargs = s->op_dead_iargs[op_index];
2015 args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs);
2016 goto next;
2017 case INDEX_op_end:
2018 goto the_end;
2019 default:
2020 /* Note: in order to speed up the code, it would be much
2021 faster to have specialized register allocator functions for
2022 some common argument patterns */
2023 dead_iargs = s->op_dead_iargs[op_index];
2024 tcg_reg_alloc_op(s, def, opc, args, dead_iargs);
2025 break;
2027 args += def->nb_args;
2028 next:
2029 if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) {
2030 return op_index;
2032 op_index++;
2033 #ifndef NDEBUG
2034 check_regs(s);
2035 #endif
2037 the_end:
2038 return -1;
2041 int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf)
2043 #ifdef CONFIG_PROFILER
2045 int n;
2046 n = (gen_opc_ptr - gen_opc_buf);
2047 s->op_count += n;
2048 if (n > s->op_count_max)
2049 s->op_count_max = n;
2051 s->temp_count += s->nb_temps;
2052 if (s->nb_temps > s->temp_count_max)
2053 s->temp_count_max = s->nb_temps;
2055 #endif
2057 tcg_gen_code_common(s, gen_code_buf, -1);
2059 /* flush instruction cache */
2060 flush_icache_range((unsigned long)gen_code_buf,
2061 (unsigned long)s->code_ptr);
2062 return s->code_ptr - gen_code_buf;
2065 /* Return the index of the micro operation such as the pc after is <
2066 offset bytes from the start of the TB. The contents of gen_code_buf must
2067 not be changed, though writing the same values is ok.
2068 Return -1 if not found. */
2069 int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset)
2071 return tcg_gen_code_common(s, gen_code_buf, offset);
2074 #ifdef CONFIG_PROFILER
2075 void tcg_dump_info(FILE *f,
2076 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2078 TCGContext *s = &tcg_ctx;
2079 int64_t tot;
2081 tot = s->interm_time + s->code_time;
2082 cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n",
2083 tot, tot / 2.4e9);
2084 cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n",
2085 s->tb_count,
2086 s->tb_count1 - s->tb_count,
2087 s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0);
2088 cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n",
2089 s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max);
2090 cpu_fprintf(f, "deleted ops/TB %0.2f\n",
2091 s->tb_count ?
2092 (double)s->del_op_count / s->tb_count : 0);
2093 cpu_fprintf(f, "avg temps/TB %0.2f max=%d\n",
2094 s->tb_count ?
2095 (double)s->temp_count / s->tb_count : 0,
2096 s->temp_count_max);
2098 cpu_fprintf(f, "cycles/op %0.1f\n",
2099 s->op_count ? (double)tot / s->op_count : 0);
2100 cpu_fprintf(f, "cycles/in byte %0.1f\n",
2101 s->code_in_len ? (double)tot / s->code_in_len : 0);
2102 cpu_fprintf(f, "cycles/out byte %0.1f\n",
2103 s->code_out_len ? (double)tot / s->code_out_len : 0);
2104 if (tot == 0)
2105 tot = 1;
2106 cpu_fprintf(f, " gen_interm time %0.1f%%\n",
2107 (double)s->interm_time / tot * 100.0);
2108 cpu_fprintf(f, " gen_code time %0.1f%%\n",
2109 (double)s->code_time / tot * 100.0);
2110 cpu_fprintf(f, "liveness/code time %0.1f%%\n",
2111 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
2112 cpu_fprintf(f, "cpu_restore count %" PRId64 "\n",
2113 s->restore_count);
2114 cpu_fprintf(f, " avg cycles %0.1f\n",
2115 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
2117 dump_op_count();
2119 #else
2120 void tcg_dump_info(FILE *f,
2121 int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2123 cpu_fprintf(f, "[TCG profiler not compiled]\n");
2125 #endif