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
25 /* define it to use liveness analysis (better code) */
26 #define USE_LIVENESS_ANALYSIS
30 #ifndef CONFIG_DEBUG_TCG
31 /* define it to suppress various consistency checks (faster) */
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
54 #define NO_CPU_IO_DEFS
61 #if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
62 #error GUEST_BASE not supported on this host.
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, iargs, oargs, cargs, flags) { #s, iargs, oargs, cargs, iargs + oargs + cargs, flags, 0 },
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
)
88 static inline void tcg_out16(TCGContext
*s
, uint16_t v
)
90 *(uint16_t *)s
->code_ptr
= v
;
94 static inline void tcg_out32(TCGContext
*s
, uint32_t v
)
96 *(uint32_t *)s
->code_ptr
= v
;
100 /* label relocation processing */
102 void tcg_out_reloc(TCGContext
*s
, uint8_t *code_ptr
, int type
,
103 int label_index
, long addend
)
108 l
= &s
->labels
[label_index
];
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
);
115 /* add a new relocation entry */
116 r
= tcg_malloc(sizeof(TCGRelocation
));
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
)
131 l
= &s
->labels
[label_index
];
134 r
= l
->u
.first_reloc
;
136 patch_reloc(r
->ptr
, r
->type
, value
, r
->addend
);
143 int gen_new_label(void)
145 TCGContext
*s
= &tcg_ctx
;
149 if (s
->nb_labels
>= TCG_MAX_LABELS
)
151 idx
= s
->nb_labels
++;
154 l
->u
.first_reloc
= NULL
;
158 #include "tcg-target.c"
160 /* pool based memory allocation */
161 void *tcg_malloc_internal(TCGContext
*s
, int 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
);
171 s
->pool_current
->next
= p
;
174 p
->next
= s
->pool_current
;
184 pool_size
= TCG_POOL_CHUNK_SIZE
;
185 p
= qemu_malloc(sizeof(TCGPool
) + pool_size
);
189 s
->pool_current
->next
= p
;
198 s
->pool_cur
= p
->data
+ size
;
199 s
->pool_end
= p
->data
+ p
->size
;
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
;
213 TCGArgConstraint
*args_ct
;
216 memset(s
, 0, sizeof(*s
));
217 s
->temps
= s
->static_temps
;
220 /* Count total number of arguments and allocate the corresponding
223 for(op
= 0; op
< NB_OPS
; op
++) {
224 def
= &tcg_op_defs
[op
];
225 n
= def
->nb_iargs
+ def
->nb_oargs
;
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
;
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
;
259 void tcg_func_start(TCGContext
*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
);
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
)
280 static inline int tcg_global_reg_new_internal(TCGType type
, int reg
,
283 TCGContext
*s
= &tcg_ctx
;
287 #if TCG_TARGET_REG_BITS == 32
288 if (type
!= TCG_TYPE_I32
)
291 if (tcg_regset_test_reg(s
->reserved_regs
, reg
))
294 tcg_temp_alloc(s
, s
->nb_globals
+ 1);
295 ts
= &s
->temps
[s
->nb_globals
];
296 ts
->base_type
= type
;
302 tcg_regset_set_reg(s
->reserved_regs
, reg
);
306 TCGv_i32
tcg_global_reg_new_i32(int reg
, const char *name
)
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
)
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
,
326 TCGContext
*s
= &tcg_ctx
;
331 #if TCG_TARGET_REG_BITS == 32
332 if (type
== TCG_TYPE_I64
) {
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
;
339 ts
->mem_allocated
= 1;
341 #ifdef TCG_TARGET_WORDS_BIGENDIAN
342 ts
->mem_offset
= offset
+ 4;
344 ts
->mem_offset
= offset
;
346 pstrcpy(buf
, sizeof(buf
), name
);
347 pstrcat(buf
, sizeof(buf
), "_0");
348 ts
->name
= strdup(buf
);
351 ts
->base_type
= type
;
352 ts
->type
= TCG_TYPE_I32
;
354 ts
->mem_allocated
= 1;
356 #ifdef TCG_TARGET_WORDS_BIGENDIAN
357 ts
->mem_offset
= offset
;
359 ts
->mem_offset
= offset
+ 4;
361 pstrcpy(buf
, sizeof(buf
), name
);
362 pstrcat(buf
, sizeof(buf
), "_1");
363 ts
->name
= strdup(buf
);
369 tcg_temp_alloc(s
, s
->nb_globals
+ 1);
370 ts
= &s
->temps
[s
->nb_globals
];
371 ts
->base_type
= type
;
374 ts
->mem_allocated
= 1;
376 ts
->mem_offset
= offset
;
383 TCGv_i32
tcg_global_mem_new_i32(int reg
, tcg_target_long offset
,
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
,
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
;
410 idx
= s
->first_free_temp
[k
];
412 /* There is already an available temp with the
415 s
->first_free_temp
[k
] = ts
->next_free_temp
;
416 ts
->temp_allocated
= 1;
417 assert(ts
->temp_local
== temp_local
);
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
;
430 ts
->base_type
= TCG_TYPE_I32
;
431 ts
->type
= TCG_TYPE_I32
;
432 ts
->temp_allocated
= 1;
433 ts
->temp_local
= temp_local
;
439 tcg_temp_alloc(s
, s
->nb_temps
+ 1);
440 ts
= &s
->temps
[s
->nb_temps
];
441 ts
->base_type
= type
;
443 ts
->temp_allocated
= 1;
444 ts
->temp_local
= temp_local
;
452 TCGv_i32
tcg_temp_new_internal_i32(int temp_local
)
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
)
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
;
474 assert(idx
>= s
->nb_globals
&& idx
< s
->nb_temps
);
476 assert(ts
->temp_allocated
!= 0);
477 ts
->temp_allocated
= 0;
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
)
498 t0
= tcg_temp_new_i32();
499 tcg_gen_movi_i32(t0
, val
);
503 TCGv_i64
tcg_const_i64(int64_t val
)
506 t0
= tcg_temp_new_i64();
507 tcg_gen_movi_i64(t0
, val
);
511 TCGv_i32
tcg_const_local_i32(int32_t val
)
514 t0
= tcg_temp_local_new_i32();
515 tcg_gen_movi_i32(t0
, val
);
519 TCGv_i64
tcg_const_local_i64(int64_t val
)
522 t0
= tcg_temp_local_new_i64();
523 tcg_gen_movi_i64(t0
, val
);
527 void tcg_register_helper(void *func
, const char *name
)
529 TCGContext
*s
= &tcg_ctx
;
531 if ((s
->nb_helpers
+ 1) > s
->allocated_helpers
) {
532 n
= s
->allocated_helpers
;
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
;
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
)
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
563 #ifdef TCG_TARGET_WORDS_BIGENDIAN
564 *gen_opparam_ptr
++ = ret
+ 1;
565 *gen_opparam_ptr
++ = ret
;
567 *gen_opparam_ptr
++ = ret
;
568 *gen_opparam_ptr
++ = ret
+ 1;
574 *gen_opparam_ptr
++ = ret
;
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
;
592 #ifdef TCG_TARGET_CALL_ALIGN_ARGS
593 /* some targets want aligned 64 bit args */
595 *gen_opparam_ptr
++ = TCG_CALL_DUMMY_ARG
;
599 #ifdef TCG_TARGET_WORDS_BIGENDIAN
600 *gen_opparam_ptr
++ = args
[i
] + 1;
601 *gen_opparam_ptr
++ = args
[i
];
603 *gen_opparam_ptr
++ = args
[i
];
604 *gen_opparam_ptr
++ = args
[i
] + 1;
610 *gen_opparam_ptr
++ = args
[i
];
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
)
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) {
635 tcg_gen_sari_i32(TCGV_LOW(ret
), TCGV_HIGH(arg1
), c
);
636 tcg_gen_sari_i32(TCGV_HIGH(ret
), TCGV_HIGH(arg1
), 31);
638 tcg_gen_shri_i32(TCGV_LOW(ret
), TCGV_HIGH(arg1
), c
);
639 tcg_gen_movi_i32(TCGV_HIGH(ret
), 0);
642 tcg_gen_shli_i32(TCGV_HIGH(ret
), TCGV_LOW(arg1
), c
);
643 tcg_gen_movi_i32(TCGV_LOW(ret
), 0);
648 t0
= tcg_temp_new_i32();
649 t1
= tcg_temp_new_i32();
651 tcg_gen_shli_i32(t0
, TCGV_HIGH(arg1
), 32 - c
);
653 tcg_gen_sari_i32(t1
, TCGV_HIGH(arg1
), c
);
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
);
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
);
673 static void tcg_reg_alloc_start(TCGContext
*s
)
677 for(i
= 0; i
< s
->nb_globals
; i
++) {
680 ts
->val_type
= TEMP_VAL_REG
;
682 ts
->val_type
= TEMP_VAL_MEM
;
685 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
687 ts
->val_type
= TEMP_VAL_DEAD
;
688 ts
->mem_allocated
= 0;
691 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
692 s
->reg_to_temp
[i
] = -1;
696 static char *tcg_get_arg_str_idx(TCGContext
*s
, char *buf
, int buf_size
,
702 if (idx
< s
->nb_globals
) {
703 pstrcpy(buf
, buf_size
, ts
->name
);
706 snprintf(buf
, buf_size
, "loc%d", idx
- s
->nb_globals
);
708 snprintf(buf
, buf_size
, "tmp%d", idx
- s
->nb_globals
);
713 char *tcg_get_arg_str_i32(TCGContext
*s
, char *buf
, int buf_size
, TCGv_i32 arg
)
715 return tcg_get_arg_str_idx(s
, buf
, buf_size
, GET_TCGV_I32(arg
));
718 char *tcg_get_arg_str_i64(TCGContext
*s
, char *buf
, int buf_size
, TCGv_i64 arg
)
720 return tcg_get_arg_str_idx(s
, buf
, buf_size
, GET_TCGV_I64(arg
));
723 static int helper_cmp(const void *p1
, const void *p2
)
725 const TCGHelperInfo
*th1
= p1
;
726 const TCGHelperInfo
*th2
= p2
;
727 if (th1
->func
< th2
->func
)
729 else if (th1
->func
== th2
->func
)
735 /* find helper definition (Note: A hash table would be better) */
736 static TCGHelperInfo
*tcg_find_helper(TCGContext
*s
, tcg_target_ulong val
)
742 if (unlikely(!s
->helpers_sorted
)) {
743 qsort(s
->helpers
, s
->nb_helpers
, sizeof(TCGHelperInfo
),
745 s
->helpers_sorted
= 1;
750 m_max
= s
->nb_helpers
- 1;
751 while (m_min
<= m_max
) {
752 m
= (m_min
+ m_max
) >> 1;
766 static const char * const cond_name
[] =
768 [TCG_COND_EQ
] = "eq",
769 [TCG_COND_NE
] = "ne",
770 [TCG_COND_LT
] = "lt",
771 [TCG_COND_GE
] = "ge",
772 [TCG_COND_LE
] = "le",
773 [TCG_COND_GT
] = "gt",
774 [TCG_COND_LTU
] = "ltu",
775 [TCG_COND_GEU
] = "geu",
776 [TCG_COND_LEU
] = "leu",
777 [TCG_COND_GTU
] = "gtu"
780 void tcg_dump_ops(TCGContext
*s
, FILE *outfile
)
782 const uint16_t *opc_ptr
;
785 int c
, i
, k
, nb_oargs
, nb_iargs
, nb_cargs
, first_insn
;
790 opc_ptr
= gen_opc_buf
;
791 args
= gen_opparam_buf
;
792 while (opc_ptr
< gen_opc_ptr
) {
794 def
= &tcg_op_defs
[c
];
795 if (c
== INDEX_op_debug_insn_start
) {
797 #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
798 pc
= ((uint64_t)args
[1] << 32) | args
[0];
803 fprintf(outfile
, "\n");
804 fprintf(outfile
, " ---- 0x%" PRIx64
, pc
);
806 nb_oargs
= def
->nb_oargs
;
807 nb_iargs
= def
->nb_iargs
;
808 nb_cargs
= def
->nb_cargs
;
809 } else if (c
== INDEX_op_call
) {
812 /* variable number of arguments */
814 nb_oargs
= arg
>> 16;
815 nb_iargs
= arg
& 0xffff;
816 nb_cargs
= def
->nb_cargs
;
818 fprintf(outfile
, " %s ", def
->name
);
821 fprintf(outfile
, "%s",
822 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[nb_oargs
+ nb_iargs
- 1]));
824 fprintf(outfile
, ",$0x%" TCG_PRIlx
,
825 args
[nb_oargs
+ nb_iargs
]);
827 fprintf(outfile
, ",$%d", nb_oargs
);
828 for(i
= 0; i
< nb_oargs
; i
++) {
829 fprintf(outfile
, ",");
830 fprintf(outfile
, "%s",
831 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[i
]));
833 for(i
= 0; i
< (nb_iargs
- 1); i
++) {
834 fprintf(outfile
, ",");
835 if (args
[nb_oargs
+ i
] == TCG_CALL_DUMMY_ARG
) {
836 fprintf(outfile
, "<dummy>");
838 fprintf(outfile
, "%s",
839 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[nb_oargs
+ i
]));
842 } else if (c
== INDEX_op_movi_i32
843 #if TCG_TARGET_REG_BITS == 64
844 || c
== INDEX_op_movi_i64
847 tcg_target_ulong val
;
850 nb_oargs
= def
->nb_oargs
;
851 nb_iargs
= def
->nb_iargs
;
852 nb_cargs
= def
->nb_cargs
;
853 fprintf(outfile
, " %s %s,$", def
->name
,
854 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[0]));
856 th
= tcg_find_helper(s
, val
);
858 fprintf(outfile
, "%s", th
->name
);
860 if (c
== INDEX_op_movi_i32
)
861 fprintf(outfile
, "0x%x", (uint32_t)val
);
863 fprintf(outfile
, "0x%" PRIx64
, (uint64_t)val
);
866 fprintf(outfile
, " %s ", def
->name
);
867 if (c
== INDEX_op_nopn
) {
868 /* variable number of arguments */
873 nb_oargs
= def
->nb_oargs
;
874 nb_iargs
= def
->nb_iargs
;
875 nb_cargs
= def
->nb_cargs
;
879 for(i
= 0; i
< nb_oargs
; i
++) {
881 fprintf(outfile
, ",");
882 fprintf(outfile
, "%s",
883 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[k
++]));
885 for(i
= 0; i
< nb_iargs
; i
++) {
887 fprintf(outfile
, ",");
888 fprintf(outfile
, "%s",
889 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[k
++]));
891 if (c
== INDEX_op_brcond_i32
892 #if TCG_TARGET_REG_BITS == 32
893 || c
== INDEX_op_brcond2_i32
894 #elif TCG_TARGET_REG_BITS == 64
895 || c
== INDEX_op_brcond_i64
898 if (args
[k
] < ARRAY_SIZE(cond_name
) && cond_name
[args
[k
]])
899 fprintf(outfile
, ",%s", cond_name
[args
[k
++]]);
901 fprintf(outfile
, ",$0x%" TCG_PRIlx
, args
[k
++]);
906 for(; i
< nb_cargs
; i
++) {
908 fprintf(outfile
, ",");
910 fprintf(outfile
, "$0x%" TCG_PRIlx
, arg
);
913 fprintf(outfile
, "\n");
914 args
+= nb_iargs
+ nb_oargs
+ nb_cargs
;
918 /* we give more priority to constraints with less registers */
919 static int get_constraint_priority(const TCGOpDef
*def
, int k
)
921 const TCGArgConstraint
*arg_ct
;
924 arg_ct
= &def
->args_ct
[k
];
925 if (arg_ct
->ct
& TCG_CT_ALIAS
) {
926 /* an alias is equivalent to a single register */
929 if (!(arg_ct
->ct
& TCG_CT_REG
))
932 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
933 if (tcg_regset_test_reg(arg_ct
->u
.regs
, i
))
937 return TCG_TARGET_NB_REGS
- n
+ 1;
940 /* sort from highest priority to lowest */
941 static void sort_constraints(TCGOpDef
*def
, int start
, int n
)
943 int i
, j
, p1
, p2
, tmp
;
945 for(i
= 0; i
< n
; i
++)
946 def
->sorted_args
[start
+ i
] = start
+ i
;
949 for(i
= 0; i
< n
- 1; i
++) {
950 for(j
= i
+ 1; j
< n
; j
++) {
951 p1
= get_constraint_priority(def
, def
->sorted_args
[start
+ i
]);
952 p2
= get_constraint_priority(def
, def
->sorted_args
[start
+ j
]);
954 tmp
= def
->sorted_args
[start
+ i
];
955 def
->sorted_args
[start
+ i
] = def
->sorted_args
[start
+ j
];
956 def
->sorted_args
[start
+ j
] = tmp
;
962 void tcg_add_target_add_op_defs(const TCGTargetOpDef
*tdefs
)
973 assert(op
>= 0 && op
< NB_OPS
);
974 def
= &tcg_op_defs
[op
];
975 nb_args
= def
->nb_iargs
+ def
->nb_oargs
;
976 for(i
= 0; i
< nb_args
; i
++) {
977 ct_str
= tdefs
->args_ct_str
[i
];
978 tcg_regset_clear(def
->args_ct
[i
].u
.regs
);
979 def
->args_ct
[i
].ct
= 0;
980 if (ct_str
[0] >= '0' && ct_str
[0] <= '9') {
982 oarg
= ct_str
[0] - '0';
983 assert(oarg
< def
->nb_oargs
);
984 assert(def
->args_ct
[oarg
].ct
& TCG_CT_REG
);
985 /* TCG_CT_ALIAS is for the output arguments. The input
986 argument is tagged with TCG_CT_IALIAS. */
987 def
->args_ct
[i
] = def
->args_ct
[oarg
];
988 def
->args_ct
[oarg
].ct
= TCG_CT_ALIAS
;
989 def
->args_ct
[oarg
].alias_index
= i
;
990 def
->args_ct
[i
].ct
|= TCG_CT_IALIAS
;
991 def
->args_ct
[i
].alias_index
= oarg
;
998 def
->args_ct
[i
].ct
|= TCG_CT_CONST
;
1002 if (target_parse_constraint(&def
->args_ct
[i
], &ct_str
) < 0) {
1003 fprintf(stderr
, "Invalid constraint '%s' for arg %d of operation '%s'\n",
1004 ct_str
, i
, def
->name
);
1012 /* sort the constraints (XXX: this is just an heuristic) */
1013 sort_constraints(def
, 0, def
->nb_oargs
);
1014 sort_constraints(def
, def
->nb_oargs
, def
->nb_iargs
);
1020 printf("%s: sorted=", def
->name
);
1021 for(i
= 0; i
< def
->nb_oargs
+ def
->nb_iargs
; i
++)
1022 printf(" %d", def
->sorted_args
[i
]);
1031 #ifdef USE_LIVENESS_ANALYSIS
1033 /* set a nop for an operation using 'nb_args' */
1034 static inline void tcg_set_nop(TCGContext
*s
, uint16_t *opc_ptr
,
1035 TCGArg
*args
, int nb_args
)
1038 *opc_ptr
= INDEX_op_nop
;
1040 *opc_ptr
= INDEX_op_nopn
;
1042 args
[nb_args
- 1] = nb_args
;
1046 /* liveness analysis: end of function: globals are live, temps are
1048 /* XXX: at this stage, not used as there would be little gains because
1049 most TBs end with a conditional jump. */
1050 static inline void tcg_la_func_end(TCGContext
*s
, uint8_t *dead_temps
)
1052 memset(dead_temps
, 0, s
->nb_globals
);
1053 memset(dead_temps
+ s
->nb_globals
, 1, s
->nb_temps
- s
->nb_globals
);
1056 /* liveness analysis: end of basic block: globals are live, temps are
1057 dead, local temps are live. */
1058 static inline void tcg_la_bb_end(TCGContext
*s
, uint8_t *dead_temps
)
1063 memset(dead_temps
, 0, s
->nb_globals
);
1064 ts
= &s
->temps
[s
->nb_globals
];
1065 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
1074 /* Liveness analysis : update the opc_dead_iargs array to tell if a
1075 given input arguments is dead. Instructions updating dead
1076 temporaries are removed. */
1077 static void tcg_liveness_analysis(TCGContext
*s
)
1079 int i
, op_index
, op
, nb_args
, nb_iargs
, nb_oargs
, arg
, nb_ops
;
1081 const TCGOpDef
*def
;
1082 uint8_t *dead_temps
;
1083 unsigned int dead_iargs
;
1085 gen_opc_ptr
++; /* skip end */
1087 nb_ops
= gen_opc_ptr
- gen_opc_buf
;
1089 /* XXX: make it really dynamic */
1090 s
->op_dead_iargs
= tcg_malloc(OPC_BUF_SIZE
* sizeof(uint16_t));
1092 dead_temps
= tcg_malloc(s
->nb_temps
);
1093 memset(dead_temps
, 1, s
->nb_temps
);
1095 args
= gen_opparam_ptr
;
1096 op_index
= nb_ops
- 1;
1097 while (op_index
>= 0) {
1098 op
= gen_opc_buf
[op_index
];
1099 def
= &tcg_op_defs
[op
];
1107 nb_iargs
= args
[0] & 0xffff;
1108 nb_oargs
= args
[0] >> 16;
1110 call_flags
= args
[nb_oargs
+ nb_iargs
];
1112 /* pure functions can be removed if their result is not
1114 if (call_flags
& TCG_CALL_PURE
) {
1115 for(i
= 0; i
< nb_oargs
; i
++) {
1117 if (!dead_temps
[arg
])
1118 goto do_not_remove_call
;
1120 tcg_set_nop(s
, gen_opc_buf
+ op_index
,
1125 /* output args are dead */
1126 for(i
= 0; i
< nb_oargs
; i
++) {
1128 dead_temps
[arg
] = 1;
1131 if (!(call_flags
& TCG_CALL_CONST
)) {
1132 /* globals are live (they may be used by the call) */
1133 memset(dead_temps
, 0, s
->nb_globals
);
1136 /* input args are live */
1138 for(i
= 0; i
< nb_iargs
; i
++) {
1139 arg
= args
[i
+ nb_oargs
];
1140 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1141 if (dead_temps
[arg
]) {
1142 dead_iargs
|= (1 << i
);
1144 dead_temps
[arg
] = 0;
1147 s
->op_dead_iargs
[op_index
] = dead_iargs
;
1152 case INDEX_op_set_label
:
1154 /* mark end of basic block */
1155 tcg_la_bb_end(s
, dead_temps
);
1157 case INDEX_op_debug_insn_start
:
1158 args
-= def
->nb_args
;
1164 case INDEX_op_discard
:
1166 /* mark the temporary as dead */
1167 dead_temps
[args
[0]] = 1;
1171 /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1173 args
-= def
->nb_args
;
1174 nb_iargs
= def
->nb_iargs
;
1175 nb_oargs
= def
->nb_oargs
;
1177 /* Test if the operation can be removed because all
1178 its outputs are dead. We assume that nb_oargs == 0
1179 implies side effects */
1180 if (!(def
->flags
& TCG_OPF_SIDE_EFFECTS
) && nb_oargs
!= 0) {
1181 for(i
= 0; i
< nb_oargs
; i
++) {
1183 if (!dead_temps
[arg
])
1186 tcg_set_nop(s
, gen_opc_buf
+ op_index
, args
, def
->nb_args
);
1187 #ifdef CONFIG_PROFILER
1193 /* output args are dead */
1194 for(i
= 0; i
< nb_oargs
; i
++) {
1196 dead_temps
[arg
] = 1;
1199 /* if end of basic block, update */
1200 if (def
->flags
& TCG_OPF_BB_END
) {
1201 tcg_la_bb_end(s
, dead_temps
);
1202 } else if (def
->flags
& TCG_OPF_CALL_CLOBBER
) {
1203 /* globals are live */
1204 memset(dead_temps
, 0, s
->nb_globals
);
1207 /* input args are live */
1209 for(i
= 0; i
< nb_iargs
; i
++) {
1210 arg
= args
[i
+ nb_oargs
];
1211 if (dead_temps
[arg
]) {
1212 dead_iargs
|= (1 << i
);
1214 dead_temps
[arg
] = 0;
1216 s
->op_dead_iargs
[op_index
] = dead_iargs
;
1223 if (args
!= gen_opparam_buf
)
1227 /* dummy liveness analysis */
1228 void tcg_liveness_analysis(TCGContext
*s
)
1231 nb_ops
= gen_opc_ptr
- gen_opc_buf
;
1233 s
->op_dead_iargs
= tcg_malloc(nb_ops
* sizeof(uint16_t));
1234 memset(s
->op_dead_iargs
, 0, nb_ops
* sizeof(uint16_t));
1239 static void dump_regs(TCGContext
*s
)
1245 for(i
= 0; i
< s
->nb_temps
; i
++) {
1247 printf(" %10s: ", tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), i
));
1248 switch(ts
->val_type
) {
1250 printf("%s", tcg_target_reg_names
[ts
->reg
]);
1253 printf("%d(%s)", (int)ts
->mem_offset
, tcg_target_reg_names
[ts
->mem_reg
]);
1255 case TEMP_VAL_CONST
:
1256 printf("$0x%" TCG_PRIlx
, ts
->val
);
1268 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
1269 if (s
->reg_to_temp
[i
] >= 0) {
1271 tcg_target_reg_names
[i
],
1272 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), s
->reg_to_temp
[i
]));
1277 static void check_regs(TCGContext
*s
)
1283 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1284 k
= s
->reg_to_temp
[reg
];
1287 if (ts
->val_type
!= TEMP_VAL_REG
||
1289 printf("Inconsistency for register %s:\n",
1290 tcg_target_reg_names
[reg
]);
1295 for(k
= 0; k
< s
->nb_temps
; k
++) {
1297 if (ts
->val_type
== TEMP_VAL_REG
&&
1299 s
->reg_to_temp
[ts
->reg
] != k
) {
1300 printf("Inconsistency for temp %s:\n",
1301 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), k
));
1303 printf("reg state:\n");
1311 static void temp_allocate_frame(TCGContext
*s
, int temp
)
1314 ts
= &s
->temps
[temp
];
1315 s
->current_frame_offset
= (s
->current_frame_offset
+ sizeof(tcg_target_long
) - 1) & ~(sizeof(tcg_target_long
) - 1);
1316 if (s
->current_frame_offset
+ sizeof(tcg_target_long
) > s
->frame_end
)
1318 ts
->mem_offset
= s
->current_frame_offset
;
1319 ts
->mem_reg
= s
->frame_reg
;
1320 ts
->mem_allocated
= 1;
1321 s
->current_frame_offset
+= sizeof(tcg_target_long
);
1324 /* free register 'reg' by spilling the corresponding temporary if necessary */
1325 static void tcg_reg_free(TCGContext
*s
, int reg
)
1330 temp
= s
->reg_to_temp
[reg
];
1332 ts
= &s
->temps
[temp
];
1333 assert(ts
->val_type
== TEMP_VAL_REG
);
1334 if (!ts
->mem_coherent
) {
1335 if (!ts
->mem_allocated
)
1336 temp_allocate_frame(s
, temp
);
1337 tcg_out_st(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1339 ts
->val_type
= TEMP_VAL_MEM
;
1340 s
->reg_to_temp
[reg
] = -1;
1344 /* Allocate a register belonging to reg1 & ~reg2 */
1345 static int tcg_reg_alloc(TCGContext
*s
, TCGRegSet reg1
, TCGRegSet reg2
)
1350 tcg_regset_andnot(reg_ct
, reg1
, reg2
);
1352 /* first try free registers */
1353 for(i
= 0; i
< ARRAY_SIZE(tcg_target_reg_alloc_order
); i
++) {
1354 reg
= tcg_target_reg_alloc_order
[i
];
1355 if (tcg_regset_test_reg(reg_ct
, reg
) && s
->reg_to_temp
[reg
] == -1)
1359 /* XXX: do better spill choice */
1360 for(i
= 0; i
< ARRAY_SIZE(tcg_target_reg_alloc_order
); i
++) {
1361 reg
= tcg_target_reg_alloc_order
[i
];
1362 if (tcg_regset_test_reg(reg_ct
, reg
)) {
1363 tcg_reg_free(s
, reg
);
1371 /* save a temporary to memory. 'allocated_regs' is used in case a
1372 temporary registers needs to be allocated to store a constant. */
1373 static void temp_save(TCGContext
*s
, int temp
, TCGRegSet allocated_regs
)
1378 ts
= &s
->temps
[temp
];
1379 if (!ts
->fixed_reg
) {
1380 switch(ts
->val_type
) {
1382 tcg_reg_free(s
, ts
->reg
);
1385 ts
->val_type
= TEMP_VAL_MEM
;
1387 case TEMP_VAL_CONST
:
1388 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1390 if (!ts
->mem_allocated
)
1391 temp_allocate_frame(s
, temp
);
1392 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1393 tcg_out_st(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1394 ts
->val_type
= TEMP_VAL_MEM
;
1404 /* save globals to their cannonical location and assume they can be
1405 modified be the following code. 'allocated_regs' is used in case a
1406 temporary registers needs to be allocated to store a constant. */
1407 static void save_globals(TCGContext
*s
, TCGRegSet allocated_regs
)
1411 for(i
= 0; i
< s
->nb_globals
; i
++) {
1412 temp_save(s
, i
, allocated_regs
);
1416 /* at the end of a basic block, we assume all temporaries are dead and
1417 all globals are stored at their canonical location. */
1418 static void tcg_reg_alloc_bb_end(TCGContext
*s
, TCGRegSet allocated_regs
)
1423 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
1425 if (ts
->temp_local
) {
1426 temp_save(s
, i
, allocated_regs
);
1428 if (ts
->val_type
== TEMP_VAL_REG
) {
1429 s
->reg_to_temp
[ts
->reg
] = -1;
1431 ts
->val_type
= TEMP_VAL_DEAD
;
1435 save_globals(s
, allocated_regs
);
1438 #define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
1440 static void tcg_reg_alloc_movi(TCGContext
*s
, const TCGArg
*args
)
1443 tcg_target_ulong val
;
1445 ots
= &s
->temps
[args
[0]];
1448 if (ots
->fixed_reg
) {
1449 /* for fixed registers, we do not do any constant
1451 tcg_out_movi(s
, ots
->type
, ots
->reg
, val
);
1453 /* The movi is not explicitly generated here */
1454 if (ots
->val_type
== TEMP_VAL_REG
)
1455 s
->reg_to_temp
[ots
->reg
] = -1;
1456 ots
->val_type
= TEMP_VAL_CONST
;
1461 static void tcg_reg_alloc_mov(TCGContext
*s
, const TCGOpDef
*def
,
1463 unsigned int dead_iargs
)
1467 const TCGArgConstraint
*arg_ct
;
1469 ots
= &s
->temps
[args
[0]];
1470 ts
= &s
->temps
[args
[1]];
1471 arg_ct
= &def
->args_ct
[0];
1473 /* XXX: always mark arg dead if IS_DEAD_IARG(0) */
1474 if (ts
->val_type
== TEMP_VAL_REG
) {
1475 if (IS_DEAD_IARG(0) && !ts
->fixed_reg
&& !ots
->fixed_reg
) {
1476 /* the mov can be suppressed */
1477 if (ots
->val_type
== TEMP_VAL_REG
)
1478 s
->reg_to_temp
[ots
->reg
] = -1;
1480 s
->reg_to_temp
[reg
] = -1;
1481 ts
->val_type
= TEMP_VAL_DEAD
;
1483 if (ots
->val_type
== TEMP_VAL_REG
) {
1486 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, s
->reserved_regs
);
1488 if (ts
->reg
!= reg
) {
1489 tcg_out_mov(s
, reg
, ts
->reg
);
1492 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1493 if (ots
->val_type
== TEMP_VAL_REG
) {
1496 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, s
->reserved_regs
);
1498 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1499 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1500 if (ots
->fixed_reg
) {
1502 tcg_out_movi(s
, ots
->type
, reg
, ts
->val
);
1504 /* propagate constant */
1505 if (ots
->val_type
== TEMP_VAL_REG
)
1506 s
->reg_to_temp
[ots
->reg
] = -1;
1507 ots
->val_type
= TEMP_VAL_CONST
;
1514 s
->reg_to_temp
[reg
] = args
[0];
1516 ots
->val_type
= TEMP_VAL_REG
;
1517 ots
->mem_coherent
= 0;
1520 static void tcg_reg_alloc_op(TCGContext
*s
,
1521 const TCGOpDef
*def
, int opc
,
1523 unsigned int dead_iargs
)
1525 TCGRegSet allocated_regs
;
1526 int i
, k
, nb_iargs
, nb_oargs
, reg
;
1528 const TCGArgConstraint
*arg_ct
;
1530 TCGArg new_args
[TCG_MAX_OP_ARGS
];
1531 int const_args
[TCG_MAX_OP_ARGS
];
1533 nb_oargs
= def
->nb_oargs
;
1534 nb_iargs
= def
->nb_iargs
;
1536 /* copy constants */
1537 memcpy(new_args
+ nb_oargs
+ nb_iargs
,
1538 args
+ nb_oargs
+ nb_iargs
,
1539 sizeof(TCGArg
) * def
->nb_cargs
);
1541 /* satisfy input constraints */
1542 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1543 for(k
= 0; k
< nb_iargs
; k
++) {
1544 i
= def
->sorted_args
[nb_oargs
+ k
];
1546 arg_ct
= &def
->args_ct
[i
];
1547 ts
= &s
->temps
[arg
];
1548 if (ts
->val_type
== TEMP_VAL_MEM
) {
1549 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1550 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1551 ts
->val_type
= TEMP_VAL_REG
;
1553 ts
->mem_coherent
= 1;
1554 s
->reg_to_temp
[reg
] = arg
;
1555 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1556 if (tcg_target_const_match(ts
->val
, arg_ct
)) {
1557 /* constant is OK for instruction */
1559 new_args
[i
] = ts
->val
;
1562 /* need to move to a register */
1563 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1564 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1565 ts
->val_type
= TEMP_VAL_REG
;
1567 ts
->mem_coherent
= 0;
1568 s
->reg_to_temp
[reg
] = arg
;
1571 assert(ts
->val_type
== TEMP_VAL_REG
);
1572 if (arg_ct
->ct
& TCG_CT_IALIAS
) {
1573 if (ts
->fixed_reg
) {
1574 /* if fixed register, we must allocate a new register
1575 if the alias is not the same register */
1576 if (arg
!= args
[arg_ct
->alias_index
])
1577 goto allocate_in_reg
;
1579 /* if the input is aliased to an output and if it is
1580 not dead after the instruction, we must allocate
1581 a new register and move it */
1582 if (!IS_DEAD_IARG(i
- nb_oargs
))
1583 goto allocate_in_reg
;
1587 if (tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1588 /* nothing to do : the constraint is satisfied */
1591 /* allocate a new register matching the constraint
1592 and move the temporary register into it */
1593 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1594 tcg_out_mov(s
, reg
, ts
->reg
);
1598 tcg_regset_set_reg(allocated_regs
, reg
);
1602 if (def
->flags
& TCG_OPF_BB_END
) {
1603 tcg_reg_alloc_bb_end(s
, allocated_regs
);
1605 /* mark dead temporaries and free the associated registers */
1606 for(i
= 0; i
< nb_iargs
; i
++) {
1607 arg
= args
[nb_oargs
+ i
];
1608 if (IS_DEAD_IARG(i
)) {
1609 ts
= &s
->temps
[arg
];
1610 if (!ts
->fixed_reg
) {
1611 if (ts
->val_type
== TEMP_VAL_REG
)
1612 s
->reg_to_temp
[ts
->reg
] = -1;
1613 ts
->val_type
= TEMP_VAL_DEAD
;
1618 if (def
->flags
& TCG_OPF_CALL_CLOBBER
) {
1619 /* XXX: permit generic clobber register list ? */
1620 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1621 if (tcg_regset_test_reg(tcg_target_call_clobber_regs
, reg
)) {
1622 tcg_reg_free(s
, reg
);
1625 /* XXX: for load/store we could do that only for the slow path
1626 (i.e. when a memory callback is called) */
1628 /* store globals and free associated registers (we assume the insn
1629 can modify any global. */
1630 save_globals(s
, allocated_regs
);
1633 /* satisfy the output constraints */
1634 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1635 for(k
= 0; k
< nb_oargs
; k
++) {
1636 i
= def
->sorted_args
[k
];
1638 arg_ct
= &def
->args_ct
[i
];
1639 ts
= &s
->temps
[arg
];
1640 if (arg_ct
->ct
& TCG_CT_ALIAS
) {
1641 reg
= new_args
[arg_ct
->alias_index
];
1643 /* if fixed register, we try to use it */
1645 if (ts
->fixed_reg
&&
1646 tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1649 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1651 tcg_regset_set_reg(allocated_regs
, reg
);
1652 /* if a fixed register is used, then a move will be done afterwards */
1653 if (!ts
->fixed_reg
) {
1654 if (ts
->val_type
== TEMP_VAL_REG
)
1655 s
->reg_to_temp
[ts
->reg
] = -1;
1656 ts
->val_type
= TEMP_VAL_REG
;
1658 /* temp value is modified, so the value kept in memory is
1659 potentially not the same */
1660 ts
->mem_coherent
= 0;
1661 s
->reg_to_temp
[reg
] = arg
;
1668 /* emit instruction */
1669 tcg_out_op(s
, opc
, new_args
, const_args
);
1671 /* move the outputs in the correct register if needed */
1672 for(i
= 0; i
< nb_oargs
; i
++) {
1673 ts
= &s
->temps
[args
[i
]];
1675 if (ts
->fixed_reg
&& ts
->reg
!= reg
) {
1676 tcg_out_mov(s
, ts
->reg
, reg
);
1681 #ifdef TCG_TARGET_STACK_GROWSUP
1682 #define STACK_DIR(x) (-(x))
1684 #define STACK_DIR(x) (x)
1687 static int tcg_reg_alloc_call(TCGContext
*s
, const TCGOpDef
*def
,
1688 int opc
, const TCGArg
*args
,
1689 unsigned int dead_iargs
)
1691 int nb_iargs
, nb_oargs
, flags
, nb_regs
, i
, reg
, nb_params
;
1692 TCGArg arg
, func_arg
;
1694 tcg_target_long stack_offset
, call_stack_size
, func_addr
;
1695 int const_func_arg
, allocate_args
;
1696 TCGRegSet allocated_regs
;
1697 const TCGArgConstraint
*arg_ct
;
1701 nb_oargs
= arg
>> 16;
1702 nb_iargs
= arg
& 0xffff;
1703 nb_params
= nb_iargs
- 1;
1705 flags
= args
[nb_oargs
+ nb_iargs
];
1707 nb_regs
= tcg_target_get_call_iarg_regs_count(flags
);
1708 if (nb_regs
> nb_params
)
1709 nb_regs
= nb_params
;
1711 /* assign stack slots first */
1712 /* XXX: preallocate call stack */
1713 call_stack_size
= (nb_params
- nb_regs
) * sizeof(tcg_target_long
);
1714 call_stack_size
= (call_stack_size
+ TCG_TARGET_STACK_ALIGN
- 1) &
1715 ~(TCG_TARGET_STACK_ALIGN
- 1);
1716 allocate_args
= (call_stack_size
> TCG_STATIC_CALL_ARGS_SIZE
);
1717 if (allocate_args
) {
1718 tcg_out_addi(s
, TCG_REG_CALL_STACK
, -STACK_DIR(call_stack_size
));
1721 stack_offset
= TCG_TARGET_CALL_STACK_OFFSET
;
1722 for(i
= nb_regs
; i
< nb_params
; i
++) {
1723 arg
= args
[nb_oargs
+ i
];
1724 #ifdef TCG_TARGET_STACK_GROWSUP
1725 stack_offset
-= sizeof(tcg_target_long
);
1727 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1728 ts
= &s
->temps
[arg
];
1729 if (ts
->val_type
== TEMP_VAL_REG
) {
1730 tcg_out_st(s
, ts
->type
, ts
->reg
, TCG_REG_CALL_STACK
, stack_offset
);
1731 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1732 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1734 /* XXX: not correct if reading values from the stack */
1735 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1736 tcg_out_st(s
, ts
->type
, reg
, TCG_REG_CALL_STACK
, stack_offset
);
1737 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1738 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1740 /* XXX: sign extend may be needed on some targets */
1741 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1742 tcg_out_st(s
, ts
->type
, reg
, TCG_REG_CALL_STACK
, stack_offset
);
1747 #ifndef TCG_TARGET_STACK_GROWSUP
1748 stack_offset
+= sizeof(tcg_target_long
);
1752 /* assign input registers */
1753 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1754 for(i
= 0; i
< nb_regs
; i
++) {
1755 arg
= args
[nb_oargs
+ i
];
1756 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1757 ts
= &s
->temps
[arg
];
1758 reg
= tcg_target_call_iarg_regs
[i
];
1759 tcg_reg_free(s
, reg
);
1760 if (ts
->val_type
== TEMP_VAL_REG
) {
1761 if (ts
->reg
!= reg
) {
1762 tcg_out_mov(s
, reg
, ts
->reg
);
1764 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1765 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1766 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1767 /* XXX: sign extend ? */
1768 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1772 tcg_regset_set_reg(allocated_regs
, reg
);
1776 /* assign function address */
1777 func_arg
= args
[nb_oargs
+ nb_iargs
- 1];
1778 arg_ct
= &def
->args_ct
[0];
1779 ts
= &s
->temps
[func_arg
];
1780 func_addr
= ts
->val
;
1782 if (ts
->val_type
== TEMP_VAL_MEM
) {
1783 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1784 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1786 tcg_regset_set_reg(allocated_regs
, reg
);
1787 } else if (ts
->val_type
== TEMP_VAL_REG
) {
1789 if (!tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1790 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1791 tcg_out_mov(s
, reg
, ts
->reg
);
1794 tcg_regset_set_reg(allocated_regs
, reg
);
1795 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1796 if (tcg_target_const_match(func_addr
, arg_ct
)) {
1798 func_arg
= func_addr
;
1800 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1801 tcg_out_movi(s
, ts
->type
, reg
, func_addr
);
1803 tcg_regset_set_reg(allocated_regs
, reg
);
1810 /* mark dead temporaries and free the associated registers */
1811 for(i
= 0; i
< nb_iargs
; i
++) {
1812 arg
= args
[nb_oargs
+ i
];
1813 if (IS_DEAD_IARG(i
)) {
1814 ts
= &s
->temps
[arg
];
1815 if (!ts
->fixed_reg
) {
1816 if (ts
->val_type
== TEMP_VAL_REG
)
1817 s
->reg_to_temp
[ts
->reg
] = -1;
1818 ts
->val_type
= TEMP_VAL_DEAD
;
1823 /* clobber call registers */
1824 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1825 if (tcg_regset_test_reg(tcg_target_call_clobber_regs
, reg
)) {
1826 tcg_reg_free(s
, reg
);
1830 /* store globals and free associated registers (we assume the call
1831 can modify any global. */
1832 if (!(flags
& TCG_CALL_CONST
)) {
1833 save_globals(s
, allocated_regs
);
1836 tcg_out_op(s
, opc
, &func_arg
, &const_func_arg
);
1838 if (allocate_args
) {
1839 tcg_out_addi(s
, TCG_REG_CALL_STACK
, STACK_DIR(call_stack_size
));
1842 /* assign output registers and emit moves if needed */
1843 for(i
= 0; i
< nb_oargs
; i
++) {
1845 ts
= &s
->temps
[arg
];
1846 reg
= tcg_target_call_oarg_regs
[i
];
1847 assert(s
->reg_to_temp
[reg
] == -1);
1848 if (ts
->fixed_reg
) {
1849 if (ts
->reg
!= reg
) {
1850 tcg_out_mov(s
, ts
->reg
, reg
);
1853 if (ts
->val_type
== TEMP_VAL_REG
)
1854 s
->reg_to_temp
[ts
->reg
] = -1;
1855 ts
->val_type
= TEMP_VAL_REG
;
1857 ts
->mem_coherent
= 0;
1858 s
->reg_to_temp
[reg
] = arg
;
1862 return nb_iargs
+ nb_oargs
+ def
->nb_cargs
+ 1;
1865 #ifdef CONFIG_PROFILER
1867 static int64_t tcg_table_op_count
[NB_OPS
];
1869 static void dump_op_count(void)
1873 f
= fopen("/tmp/op.log", "w");
1874 for(i
= INDEX_op_end
; i
< NB_OPS
; i
++) {
1875 fprintf(f
, "%s %" PRId64
"\n", tcg_op_defs
[i
].name
, tcg_table_op_count
[i
]);
1882 static inline int tcg_gen_code_common(TCGContext
*s
, uint8_t *gen_code_buf
,
1886 const TCGOpDef
*def
;
1887 unsigned int dead_iargs
;
1891 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP
))) {
1893 tcg_dump_ops(s
, logfile
);
1898 #ifdef CONFIG_PROFILER
1899 s
->la_time
-= profile_getclock();
1901 tcg_liveness_analysis(s
);
1902 #ifdef CONFIG_PROFILER
1903 s
->la_time
+= profile_getclock();
1907 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT
))) {
1908 qemu_log("OP after la:\n");
1909 tcg_dump_ops(s
, logfile
);
1914 tcg_reg_alloc_start(s
);
1916 s
->code_buf
= gen_code_buf
;
1917 s
->code_ptr
= gen_code_buf
;
1919 args
= gen_opparam_buf
;
1923 opc
= gen_opc_buf
[op_index
];
1924 #ifdef CONFIG_PROFILER
1925 tcg_table_op_count
[opc
]++;
1927 def
= &tcg_op_defs
[opc
];
1929 printf("%s: %d %d %d\n", def
->name
,
1930 def
->nb_oargs
, def
->nb_iargs
, def
->nb_cargs
);
1934 case INDEX_op_mov_i32
:
1935 #if TCG_TARGET_REG_BITS == 64
1936 case INDEX_op_mov_i64
:
1938 dead_iargs
= s
->op_dead_iargs
[op_index
];
1939 tcg_reg_alloc_mov(s
, def
, args
, dead_iargs
);
1941 case INDEX_op_movi_i32
:
1942 #if TCG_TARGET_REG_BITS == 64
1943 case INDEX_op_movi_i64
:
1945 tcg_reg_alloc_movi(s
, args
);
1947 case INDEX_op_debug_insn_start
:
1948 /* debug instruction */
1958 case INDEX_op_discard
:
1961 ts
= &s
->temps
[args
[0]];
1962 /* mark the temporary as dead */
1963 if (!ts
->fixed_reg
) {
1964 if (ts
->val_type
== TEMP_VAL_REG
)
1965 s
->reg_to_temp
[ts
->reg
] = -1;
1966 ts
->val_type
= TEMP_VAL_DEAD
;
1970 case INDEX_op_set_label
:
1971 tcg_reg_alloc_bb_end(s
, s
->reserved_regs
);
1972 tcg_out_label(s
, args
[0], (long)s
->code_ptr
);
1975 dead_iargs
= s
->op_dead_iargs
[op_index
];
1976 args
+= tcg_reg_alloc_call(s
, def
, opc
, args
, dead_iargs
);
1981 /* Note: in order to speed up the code, it would be much
1982 faster to have specialized register allocator functions for
1983 some common argument patterns */
1984 dead_iargs
= s
->op_dead_iargs
[op_index
];
1985 tcg_reg_alloc_op(s
, def
, opc
, args
, dead_iargs
);
1988 args
+= def
->nb_args
;
1990 if (search_pc
>= 0 && search_pc
< s
->code_ptr
- gen_code_buf
) {
2002 int tcg_gen_code(TCGContext
*s
, uint8_t *gen_code_buf
)
2004 #ifdef CONFIG_PROFILER
2007 n
= (gen_opc_ptr
- gen_opc_buf
);
2009 if (n
> s
->op_count_max
)
2010 s
->op_count_max
= n
;
2012 s
->temp_count
+= s
->nb_temps
;
2013 if (s
->nb_temps
> s
->temp_count_max
)
2014 s
->temp_count_max
= s
->nb_temps
;
2018 tcg_gen_code_common(s
, gen_code_buf
, -1);
2020 /* flush instruction cache */
2021 flush_icache_range((unsigned long)gen_code_buf
,
2022 (unsigned long)s
->code_ptr
);
2023 return s
->code_ptr
- gen_code_buf
;
2026 /* Return the index of the micro operation such as the pc after is <
2027 offset bytes from the start of the TB. The contents of gen_code_buf must
2028 not be changed, though writing the same values is ok.
2029 Return -1 if not found. */
2030 int tcg_gen_code_search_pc(TCGContext
*s
, uint8_t *gen_code_buf
, long offset
)
2032 return tcg_gen_code_common(s
, gen_code_buf
, offset
);
2035 #ifdef CONFIG_PROFILER
2036 void tcg_dump_info(FILE *f
,
2037 int (*cpu_fprintf
)(FILE *f
, const char *fmt
, ...))
2039 TCGContext
*s
= &tcg_ctx
;
2042 tot
= s
->interm_time
+ s
->code_time
;
2043 cpu_fprintf(f
, "JIT cycles %" PRId64
" (%0.3f s at 2.4 GHz)\n",
2045 cpu_fprintf(f
, "translated TBs %" PRId64
" (aborted=%" PRId64
" %0.1f%%)\n",
2047 s
->tb_count1
- s
->tb_count
,
2048 s
->tb_count1
? (double)(s
->tb_count1
- s
->tb_count
) / s
->tb_count1
* 100.0 : 0);
2049 cpu_fprintf(f
, "avg ops/TB %0.1f max=%d\n",
2050 s
->tb_count
? (double)s
->op_count
/ s
->tb_count
: 0, s
->op_count_max
);
2051 cpu_fprintf(f
, "deleted ops/TB %0.2f\n",
2053 (double)s
->del_op_count
/ s
->tb_count
: 0);
2054 cpu_fprintf(f
, "avg temps/TB %0.2f max=%d\n",
2056 (double)s
->temp_count
/ s
->tb_count
: 0,
2059 cpu_fprintf(f
, "cycles/op %0.1f\n",
2060 s
->op_count
? (double)tot
/ s
->op_count
: 0);
2061 cpu_fprintf(f
, "cycles/in byte %0.1f\n",
2062 s
->code_in_len
? (double)tot
/ s
->code_in_len
: 0);
2063 cpu_fprintf(f
, "cycles/out byte %0.1f\n",
2064 s
->code_out_len
? (double)tot
/ s
->code_out_len
: 0);
2067 cpu_fprintf(f
, " gen_interm time %0.1f%%\n",
2068 (double)s
->interm_time
/ tot
* 100.0);
2069 cpu_fprintf(f
, " gen_code time %0.1f%%\n",
2070 (double)s
->code_time
/ tot
* 100.0);
2071 cpu_fprintf(f
, "liveness/code time %0.1f%%\n",
2072 (double)s
->la_time
/ (s
->code_time
? s
->code_time
: 1) * 100.0);
2073 cpu_fprintf(f
, "cpu_restore count %" PRId64
"\n",
2075 cpu_fprintf(f
, " avg cycles %0.1f\n",
2076 s
->restore_count
? (double)s
->restore_time
/ s
->restore_count
: 0);
2081 void tcg_dump_info(FILE *f
,
2082 int (*cpu_fprintf
)(FILE *f
, const char *fmt
, ...))
2084 cpu_fprintf(f
, "[TCG profiler not compiled]\n");