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((uintptr_t)s
->code_buf
,
248 (uintptr_t)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
]);
1030 static void tcg_const_analysis(TCGContext
*s
)
1032 int nb_cargs
, nb_iargs
, nb_oargs
, dest
, src
, src2
, del_args
, i
;
1036 const TCGOpDef
*def
;
1037 uint8_t *const_temps
;
1038 tcg_target_ulong
*temp_values
;
1039 tcg_target_ulong val
;
1040 tcg_target_ulong dest_val
, src_val
, src2_val
;
1042 const_temps
= tcg_malloc(s
->nb_temps
);
1043 memset(const_temps
, 0, s
->nb_temps
);
1044 temp_values
= tcg_malloc(s
->nb_temps
* sizeof(uint32_t));
1046 opc_ptr
= gen_opc_buf
;
1047 args
= gen_opparam_buf
;
1048 while (opc_ptr
< gen_opc_ptr
) {
1050 def
= &tcg_op_defs
[op
];
1051 nb_oargs
= def
->nb_oargs
;
1052 nb_iargs
= def
->nb_iargs
;
1053 nb_cargs
= def
->nb_cargs
;
1057 case INDEX_op_movi_i32
:
1058 #if TCG_TARGET_REG_BITS == 64
1059 case INDEX_op_movi_i64
:
1063 const_temps
[dest
] = 1;
1064 temp_values
[dest
] = val
;
1066 case INDEX_op_mov_i32
:
1067 #if TCG_TARGET_REG_BITS == 64
1068 case INDEX_op_mov_i64
:
1072 const_temps
[dest
] = const_temps
[src
];
1073 temp_values
[dest
] = temp_values
[src
];
1075 #ifdef TCG_TARGET_HAS_not_i32
1076 case INDEX_op_not_i32
:
1079 if (const_temps
[src
]) {
1080 const_temps
[dest
] = 1;
1081 *opc_ptr
= INDEX_op_movi_i32
;
1082 args
[1] = temp_values
[dest
] = ~temp_values
[src
] & 0xffffffff;
1084 const_temps
[dest
] = 0;
1088 #ifdef TCG_TARGET_HAS_not_i64
1089 case INDEX_op_not_i64
:
1092 if (const_temps
[src
]) {
1093 const_temps
[dest
] = 1;
1094 *opc_ptr
= INDEX_op_movi_i64
;
1095 args
[1] = temp_values
[dest
] = ~temp_values
[src
];
1097 const_temps
[dest
] = 0;
1101 case INDEX_op_add_i32
:
1102 case INDEX_op_sub_i32
:
1103 case INDEX_op_mul_i32
:
1104 case INDEX_op_and_i32
:
1105 case INDEX_op_or_i32
:
1106 case INDEX_op_xor_i32
:
1107 case INDEX_op_shl_i32
:
1108 case INDEX_op_shr_i32
:
1112 if (const_temps
[src
] && const_temps
[src2
]) {
1113 src_val
= temp_values
[src
];
1114 src2_val
= temp_values
[src2
];
1115 const_temps
[dest
] = 1;
1117 case INDEX_op_add_i32
: dest_val
= src_val
+ src2_val
; break;
1118 case INDEX_op_sub_i32
: dest_val
= src_val
- src2_val
; break;
1119 case INDEX_op_mul_i32
: dest_val
= src_val
* src2_val
; break;
1120 case INDEX_op_and_i32
: dest_val
= src_val
& src2_val
; break;
1121 case INDEX_op_or_i32
: dest_val
= src_val
| src2_val
; break;
1122 case INDEX_op_xor_i32
: dest_val
= src_val
^ src2_val
; break;
1123 case INDEX_op_shl_i32
: dest_val
= src_val
<< src2_val
; break;
1124 case INDEX_op_shr_i32
: dest_val
= src_val
>> src2_val
; break;
1125 default: tcg_abort(); return;
1127 *opc_ptr
= INDEX_op_movi_i32
;
1128 args
[1] = temp_values
[dest
] = dest_val
& 0xffffffff;
1131 const_temps
[dest
] = 0;
1134 #if TCG_TARGET_REG_BITS == 64
1135 case INDEX_op_add_i64
:
1136 case INDEX_op_sub_i64
:
1137 case INDEX_op_mul_i64
:
1138 case INDEX_op_and_i64
:
1139 case INDEX_op_or_i64
:
1140 case INDEX_op_xor_i64
:
1141 case INDEX_op_shl_i64
:
1142 case INDEX_op_shr_i64
:
1146 if (const_temps
[src
] && const_temps
[src2
]) {
1147 src_val
= temp_values
[src
];
1148 src2_val
= temp_values
[src2
];
1149 const_temps
[dest
] = 1;
1151 case INDEX_op_add_i64
: dest_val
= src_val
+ src2_val
; break;
1152 case INDEX_op_sub_i64
: dest_val
= src_val
- src2_val
; break;
1153 case INDEX_op_mul_i64
: dest_val
= src_val
* src2_val
; break;
1154 case INDEX_op_and_i64
: dest_val
= src_val
& src2_val
; break;
1155 case INDEX_op_or_i64
: dest_val
= src_val
| src2_val
; break;
1156 case INDEX_op_xor_i64
: dest_val
= src_val
^ src2_val
; break;
1157 case INDEX_op_shl_i64
: dest_val
= src_val
<< src2_val
; break;
1158 case INDEX_op_shr_i64
: dest_val
= src_val
>> src2_val
; break;
1159 default: tcg_abort(); return;
1161 *opc_ptr
= INDEX_op_movi_i64
;
1162 args
[1] = temp_values
[dest
] = dest_val
;
1165 const_temps
[dest
] = 0;
1170 nb_oargs
= args
[0] >> 16;
1171 nb_iargs
= args
[0] & 0xffff;
1172 nb_cargs
= def
->nb_cargs
;
1174 for (i
= 0; i
< nb_oargs
; i
++) {
1175 const_temps
[args
[i
]] = 0;
1179 /* variable number of arguments */
1182 case INDEX_op_set_label
:
1183 memset(const_temps
, 0, s
->nb_temps
);
1186 if (def
->flags
& TCG_OPF_BB_END
) {
1187 memset(const_temps
, 0, s
->nb_temps
);
1189 for (i
= 0; i
< nb_oargs
; i
++) {
1190 const_temps
[args
[i
]] = 0;
1196 args
+= nb_iargs
+ nb_oargs
+ nb_cargs
- del_args
;
1198 gen_opparam_ptr
-= del_args
;
1199 memmove(args
, args
+ del_args
, (gen_opparam_ptr
- args
) * sizeof(*args
));
1203 if (args
!= gen_opparam_ptr
)
1207 #ifdef USE_LIVENESS_ANALYSIS
1209 /* set a nop for an operation using 'nb_args' */
1210 static inline void tcg_set_nop(TCGContext
*s
, uint16_t *opc_ptr
,
1211 TCGArg
*args
, int nb_args
)
1214 *opc_ptr
= INDEX_op_nop
;
1216 *opc_ptr
= INDEX_op_nopn
;
1218 args
[nb_args
- 1] = nb_args
;
1222 /* liveness analysis: end of function: globals are live, temps are
1224 /* XXX: at this stage, not used as there would be little gains because
1225 most TBs end with a conditional jump. */
1226 static inline void tcg_la_func_end(TCGContext
*s
, uint8_t *dead_temps
)
1228 memset(dead_temps
, 0, s
->nb_globals
);
1229 memset(dead_temps
+ s
->nb_globals
, 1, s
->nb_temps
- s
->nb_globals
);
1232 /* liveness analysis: end of basic block: globals are live, temps are
1233 dead, local temps are live. */
1234 static inline void tcg_la_bb_end(TCGContext
*s
, uint8_t *dead_temps
)
1239 memset(dead_temps
, 0, s
->nb_globals
);
1240 ts
= &s
->temps
[s
->nb_globals
];
1241 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
1250 /* Liveness analysis : update the opc_dead_iargs array to tell if a
1251 given input arguments is dead. Instructions updating dead
1252 temporaries are removed. */
1253 static void tcg_liveness_analysis(TCGContext
*s
)
1255 int i
, op_index
, op
, nb_args
, nb_iargs
, nb_oargs
, arg
, nb_ops
;
1257 const TCGOpDef
*def
;
1258 uint8_t *dead_temps
;
1259 unsigned int dead_iargs
;
1261 gen_opc_ptr
++; /* skip end */
1263 nb_ops
= gen_opc_ptr
- gen_opc_buf
;
1265 /* XXX: make it really dynamic */
1266 s
->op_dead_iargs
= tcg_malloc(OPC_BUF_SIZE
* sizeof(uint16_t));
1268 dead_temps
= tcg_malloc(s
->nb_temps
);
1269 memset(dead_temps
, 1, s
->nb_temps
);
1271 args
= gen_opparam_ptr
;
1272 op_index
= nb_ops
- 1;
1273 while (op_index
>= 0) {
1274 op
= gen_opc_buf
[op_index
];
1275 def
= &tcg_op_defs
[op
];
1283 nb_iargs
= args
[0] & 0xffff;
1284 nb_oargs
= args
[0] >> 16;
1286 call_flags
= args
[nb_oargs
+ nb_iargs
];
1288 /* pure functions can be removed if their result is not
1290 if (call_flags
& TCG_CALL_PURE
) {
1291 for(i
= 0; i
< nb_oargs
; i
++) {
1293 if (!dead_temps
[arg
])
1294 goto do_not_remove_call
;
1296 tcg_set_nop(s
, gen_opc_buf
+ op_index
,
1301 /* output args are dead */
1302 for(i
= 0; i
< nb_oargs
; i
++) {
1304 dead_temps
[arg
] = 1;
1307 if (!(call_flags
& TCG_CALL_CONST
)) {
1308 /* globals are live (they may be used by the call) */
1309 memset(dead_temps
, 0, s
->nb_globals
);
1312 /* input args are live */
1314 for(i
= 0; i
< nb_iargs
; i
++) {
1315 arg
= args
[i
+ nb_oargs
];
1316 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1317 if (dead_temps
[arg
]) {
1318 dead_iargs
|= (1 << i
);
1320 dead_temps
[arg
] = 0;
1323 s
->op_dead_iargs
[op_index
] = dead_iargs
;
1328 case INDEX_op_set_label
:
1330 /* mark end of basic block */
1331 tcg_la_bb_end(s
, dead_temps
);
1333 case INDEX_op_debug_insn_start
:
1334 args
-= def
->nb_args
;
1340 case INDEX_op_discard
:
1342 /* mark the temporary as dead */
1343 dead_temps
[args
[0]] = 1;
1347 /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1349 args
-= def
->nb_args
;
1350 nb_iargs
= def
->nb_iargs
;
1351 nb_oargs
= def
->nb_oargs
;
1353 /* Test if the operation can be removed because all
1354 its outputs are dead. We assume that nb_oargs == 0
1355 implies side effects */
1356 if (!(def
->flags
& TCG_OPF_SIDE_EFFECTS
) && nb_oargs
!= 0) {
1357 for(i
= 0; i
< nb_oargs
; i
++) {
1359 if (!dead_temps
[arg
])
1362 tcg_set_nop(s
, gen_opc_buf
+ op_index
, args
, def
->nb_args
);
1363 #ifdef CONFIG_PROFILER
1369 /* output args are dead */
1370 for(i
= 0; i
< nb_oargs
; i
++) {
1372 dead_temps
[arg
] = 1;
1375 /* if end of basic block, update */
1376 if (def
->flags
& TCG_OPF_BB_END
) {
1377 tcg_la_bb_end(s
, dead_temps
);
1378 } else if (def
->flags
& TCG_OPF_CALL_CLOBBER
) {
1379 /* globals are live */
1380 memset(dead_temps
, 0, s
->nb_globals
);
1383 /* input args are live */
1385 for(i
= 0; i
< nb_iargs
; i
++) {
1386 arg
= args
[i
+ nb_oargs
];
1387 if (dead_temps
[arg
]) {
1388 dead_iargs
|= (1 << i
);
1390 dead_temps
[arg
] = 0;
1392 s
->op_dead_iargs
[op_index
] = dead_iargs
;
1399 if (args
!= gen_opparam_buf
)
1403 /* dummy liveness analysis */
1404 void tcg_liveness_analysis(TCGContext
*s
)
1407 nb_ops
= gen_opc_ptr
- gen_opc_buf
;
1409 s
->op_dead_iargs
= tcg_malloc(nb_ops
* sizeof(uint16_t));
1410 memset(s
->op_dead_iargs
, 0, nb_ops
* sizeof(uint16_t));
1415 static void dump_regs(TCGContext
*s
)
1421 for(i
= 0; i
< s
->nb_temps
; i
++) {
1423 printf(" %10s: ", tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), i
));
1424 switch(ts
->val_type
) {
1426 printf("%s", tcg_target_reg_names
[ts
->reg
]);
1429 printf("%d(%s)", (int)ts
->mem_offset
, tcg_target_reg_names
[ts
->mem_reg
]);
1431 case TEMP_VAL_CONST
:
1432 printf("$0x%" TCG_PRIlx
, ts
->val
);
1444 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
1445 if (s
->reg_to_temp
[i
] >= 0) {
1447 tcg_target_reg_names
[i
],
1448 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), s
->reg_to_temp
[i
]));
1453 static void check_regs(TCGContext
*s
)
1459 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1460 k
= s
->reg_to_temp
[reg
];
1463 if (ts
->val_type
!= TEMP_VAL_REG
||
1465 printf("Inconsistency for register %s:\n",
1466 tcg_target_reg_names
[reg
]);
1471 for(k
= 0; k
< s
->nb_temps
; k
++) {
1473 if (ts
->val_type
== TEMP_VAL_REG
&&
1475 s
->reg_to_temp
[ts
->reg
] != k
) {
1476 printf("Inconsistency for temp %s:\n",
1477 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), k
));
1479 printf("reg state:\n");
1487 static void temp_allocate_frame(TCGContext
*s
, int temp
)
1490 ts
= &s
->temps
[temp
];
1491 s
->current_frame_offset
= (s
->current_frame_offset
+ sizeof(tcg_target_long
) - 1) & ~(sizeof(tcg_target_long
) - 1);
1492 if (s
->current_frame_offset
+ sizeof(tcg_target_long
) > s
->frame_end
)
1494 ts
->mem_offset
= s
->current_frame_offset
;
1495 ts
->mem_reg
= s
->frame_reg
;
1496 ts
->mem_allocated
= 1;
1497 s
->current_frame_offset
+= sizeof(tcg_target_long
);
1500 /* free register 'reg' by spilling the corresponding temporary if necessary */
1501 static void tcg_reg_free(TCGContext
*s
, int reg
)
1506 temp
= s
->reg_to_temp
[reg
];
1508 ts
= &s
->temps
[temp
];
1509 assert(ts
->val_type
== TEMP_VAL_REG
);
1510 if (!ts
->mem_coherent
) {
1511 if (!ts
->mem_allocated
)
1512 temp_allocate_frame(s
, temp
);
1513 tcg_out_st(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1515 ts
->val_type
= TEMP_VAL_MEM
;
1516 s
->reg_to_temp
[reg
] = -1;
1520 /* Allocate a register belonging to reg1 & ~reg2 */
1521 static int tcg_reg_alloc(TCGContext
*s
, TCGRegSet reg1
, TCGRegSet reg2
)
1526 tcg_regset_andnot(reg_ct
, reg1
, reg2
);
1528 /* first try free registers */
1529 for(i
= 0; i
< ARRAY_SIZE(tcg_target_reg_alloc_order
); i
++) {
1530 reg
= tcg_target_reg_alloc_order
[i
];
1531 if (tcg_regset_test_reg(reg_ct
, reg
) && s
->reg_to_temp
[reg
] == -1)
1535 /* XXX: do better spill choice */
1536 for(i
= 0; i
< ARRAY_SIZE(tcg_target_reg_alloc_order
); i
++) {
1537 reg
= tcg_target_reg_alloc_order
[i
];
1538 if (tcg_regset_test_reg(reg_ct
, reg
)) {
1539 tcg_reg_free(s
, reg
);
1547 /* save a temporary to memory. 'allocated_regs' is used in case a
1548 temporary registers needs to be allocated to store a constant. */
1549 static void temp_save(TCGContext
*s
, int temp
, TCGRegSet allocated_regs
)
1554 ts
= &s
->temps
[temp
];
1555 if (!ts
->fixed_reg
) {
1556 switch(ts
->val_type
) {
1558 tcg_reg_free(s
, ts
->reg
);
1561 ts
->val_type
= TEMP_VAL_MEM
;
1563 case TEMP_VAL_CONST
:
1564 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1566 if (!ts
->mem_allocated
)
1567 temp_allocate_frame(s
, temp
);
1568 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1569 tcg_out_st(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1570 ts
->val_type
= TEMP_VAL_MEM
;
1580 /* save globals to their cannonical location and assume they can be
1581 modified be the following code. 'allocated_regs' is used in case a
1582 temporary registers needs to be allocated to store a constant. */
1583 static void save_globals(TCGContext
*s
, TCGRegSet allocated_regs
)
1587 for(i
= 0; i
< s
->nb_globals
; i
++) {
1588 temp_save(s
, i
, allocated_regs
);
1592 /* at the end of a basic block, we assume all temporaries are dead and
1593 all globals are stored at their canonical location. */
1594 static void tcg_reg_alloc_bb_end(TCGContext
*s
, TCGRegSet allocated_regs
)
1599 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
1601 if (ts
->temp_local
) {
1602 temp_save(s
, i
, allocated_regs
);
1604 if (ts
->val_type
== TEMP_VAL_REG
) {
1605 s
->reg_to_temp
[ts
->reg
] = -1;
1607 ts
->val_type
= TEMP_VAL_DEAD
;
1611 save_globals(s
, allocated_regs
);
1614 #define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
1616 static void tcg_reg_alloc_movi(TCGContext
*s
, const TCGArg
*args
)
1619 tcg_target_ulong val
;
1621 ots
= &s
->temps
[args
[0]];
1624 if (ots
->fixed_reg
) {
1625 /* for fixed registers, we do not do any constant
1627 tcg_out_movi(s
, ots
->type
, ots
->reg
, val
);
1629 /* The movi is not explicitly generated here */
1630 if (ots
->val_type
== TEMP_VAL_REG
)
1631 s
->reg_to_temp
[ots
->reg
] = -1;
1632 ots
->val_type
= TEMP_VAL_CONST
;
1637 static void tcg_reg_alloc_mov(TCGContext
*s
, const TCGOpDef
*def
,
1639 unsigned int dead_iargs
)
1643 const TCGArgConstraint
*arg_ct
;
1645 ots
= &s
->temps
[args
[0]];
1646 ts
= &s
->temps
[args
[1]];
1647 arg_ct
= &def
->args_ct
[0];
1649 /* XXX: always mark arg dead if IS_DEAD_IARG(0) */
1650 if (ts
->val_type
== TEMP_VAL_REG
) {
1651 if (IS_DEAD_IARG(0) && !ts
->fixed_reg
&& !ots
->fixed_reg
) {
1652 /* the mov can be suppressed */
1653 if (ots
->val_type
== TEMP_VAL_REG
)
1654 s
->reg_to_temp
[ots
->reg
] = -1;
1656 s
->reg_to_temp
[reg
] = -1;
1657 ts
->val_type
= TEMP_VAL_DEAD
;
1659 if (ots
->val_type
== TEMP_VAL_REG
) {
1662 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, s
->reserved_regs
);
1664 if (ts
->reg
!= reg
) {
1665 tcg_out_mov(s
, reg
, ts
->reg
);
1668 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1669 if (ots
->val_type
== TEMP_VAL_REG
) {
1672 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, s
->reserved_regs
);
1674 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1675 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1676 if (ots
->fixed_reg
) {
1678 tcg_out_movi(s
, ots
->type
, reg
, ts
->val
);
1680 /* propagate constant */
1681 if (ots
->val_type
== TEMP_VAL_REG
)
1682 s
->reg_to_temp
[ots
->reg
] = -1;
1683 ots
->val_type
= TEMP_VAL_CONST
;
1690 s
->reg_to_temp
[reg
] = args
[0];
1692 ots
->val_type
= TEMP_VAL_REG
;
1693 ots
->mem_coherent
= 0;
1696 static void tcg_reg_alloc_op(TCGContext
*s
,
1697 const TCGOpDef
*def
, int opc
,
1699 unsigned int dead_iargs
)
1701 TCGRegSet allocated_regs
;
1702 int i
, k
, nb_iargs
, nb_oargs
, reg
;
1704 const TCGArgConstraint
*arg_ct
;
1706 TCGArg new_args
[TCG_MAX_OP_ARGS
];
1707 int const_args
[TCG_MAX_OP_ARGS
];
1709 nb_oargs
= def
->nb_oargs
;
1710 nb_iargs
= def
->nb_iargs
;
1712 /* copy constants */
1713 memcpy(new_args
+ nb_oargs
+ nb_iargs
,
1714 args
+ nb_oargs
+ nb_iargs
,
1715 sizeof(TCGArg
) * def
->nb_cargs
);
1717 /* satisfy input constraints */
1718 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1719 for(k
= 0; k
< nb_iargs
; k
++) {
1720 i
= def
->sorted_args
[nb_oargs
+ k
];
1722 arg_ct
= &def
->args_ct
[i
];
1723 ts
= &s
->temps
[arg
];
1724 if (ts
->val_type
== TEMP_VAL_MEM
) {
1725 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1726 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1727 ts
->val_type
= TEMP_VAL_REG
;
1729 ts
->mem_coherent
= 1;
1730 s
->reg_to_temp
[reg
] = arg
;
1731 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1732 if (tcg_target_const_match(ts
->val
, arg_ct
)) {
1733 /* constant is OK for instruction */
1735 new_args
[i
] = ts
->val
;
1738 /* need to move to a register */
1739 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1740 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1741 ts
->val_type
= TEMP_VAL_REG
;
1743 ts
->mem_coherent
= 0;
1744 s
->reg_to_temp
[reg
] = arg
;
1747 assert(ts
->val_type
== TEMP_VAL_REG
);
1748 if (arg_ct
->ct
& TCG_CT_IALIAS
) {
1749 if (ts
->fixed_reg
) {
1750 /* if fixed register, we must allocate a new register
1751 if the alias is not the same register */
1752 if (arg
!= args
[arg_ct
->alias_index
])
1753 goto allocate_in_reg
;
1755 /* if the input is aliased to an output and if it is
1756 not dead after the instruction, we must allocate
1757 a new register and move it */
1758 if (!IS_DEAD_IARG(i
- nb_oargs
))
1759 goto allocate_in_reg
;
1763 if (tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1764 /* nothing to do : the constraint is satisfied */
1767 /* allocate a new register matching the constraint
1768 and move the temporary register into it */
1769 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1770 tcg_out_mov(s
, reg
, ts
->reg
);
1774 tcg_regset_set_reg(allocated_regs
, reg
);
1778 if (def
->flags
& TCG_OPF_BB_END
) {
1779 tcg_reg_alloc_bb_end(s
, allocated_regs
);
1781 /* mark dead temporaries and free the associated registers */
1782 for(i
= 0; i
< nb_iargs
; i
++) {
1783 arg
= args
[nb_oargs
+ i
];
1784 if (IS_DEAD_IARG(i
)) {
1785 ts
= &s
->temps
[arg
];
1786 if (!ts
->fixed_reg
) {
1787 if (ts
->val_type
== TEMP_VAL_REG
)
1788 s
->reg_to_temp
[ts
->reg
] = -1;
1789 ts
->val_type
= TEMP_VAL_DEAD
;
1794 if (def
->flags
& TCG_OPF_CALL_CLOBBER
) {
1795 /* XXX: permit generic clobber register list ? */
1796 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1797 if (tcg_regset_test_reg(tcg_target_call_clobber_regs
, reg
)) {
1798 tcg_reg_free(s
, reg
);
1801 /* XXX: for load/store we could do that only for the slow path
1802 (i.e. when a memory callback is called) */
1804 /* store globals and free associated registers (we assume the insn
1805 can modify any global. */
1806 save_globals(s
, allocated_regs
);
1809 /* satisfy the output constraints */
1810 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1811 for(k
= 0; k
< nb_oargs
; k
++) {
1812 i
= def
->sorted_args
[k
];
1814 arg_ct
= &def
->args_ct
[i
];
1815 ts
= &s
->temps
[arg
];
1816 if (arg_ct
->ct
& TCG_CT_ALIAS
) {
1817 reg
= new_args
[arg_ct
->alias_index
];
1819 /* if fixed register, we try to use it */
1821 if (ts
->fixed_reg
&&
1822 tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1825 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1827 tcg_regset_set_reg(allocated_regs
, reg
);
1828 /* if a fixed register is used, then a move will be done afterwards */
1829 if (!ts
->fixed_reg
) {
1830 if (ts
->val_type
== TEMP_VAL_REG
)
1831 s
->reg_to_temp
[ts
->reg
] = -1;
1832 ts
->val_type
= TEMP_VAL_REG
;
1834 /* temp value is modified, so the value kept in memory is
1835 potentially not the same */
1836 ts
->mem_coherent
= 0;
1837 s
->reg_to_temp
[reg
] = arg
;
1844 /* emit instruction */
1845 tcg_out_op(s
, opc
, new_args
, const_args
);
1847 /* move the outputs in the correct register if needed */
1848 for(i
= 0; i
< nb_oargs
; i
++) {
1849 ts
= &s
->temps
[args
[i
]];
1851 if (ts
->fixed_reg
&& ts
->reg
!= reg
) {
1852 tcg_out_mov(s
, ts
->reg
, reg
);
1857 #ifdef TCG_TARGET_STACK_GROWSUP
1858 #define STACK_DIR(x) (-(x))
1860 #define STACK_DIR(x) (x)
1863 static int tcg_reg_alloc_call(TCGContext
*s
, const TCGOpDef
*def
,
1864 int opc
, const TCGArg
*args
,
1865 unsigned int dead_iargs
)
1867 int nb_iargs
, nb_oargs
, flags
, nb_regs
, i
, reg
, nb_params
;
1868 TCGArg arg
, func_arg
;
1870 tcg_target_long stack_offset
, call_stack_size
, func_addr
;
1871 int const_func_arg
, allocate_args
;
1872 TCGRegSet allocated_regs
;
1873 const TCGArgConstraint
*arg_ct
;
1877 nb_oargs
= arg
>> 16;
1878 nb_iargs
= arg
& 0xffff;
1879 nb_params
= nb_iargs
- 1;
1881 flags
= args
[nb_oargs
+ nb_iargs
];
1883 nb_regs
= tcg_target_get_call_iarg_regs_count(flags
);
1884 if (nb_regs
> nb_params
)
1885 nb_regs
= nb_params
;
1887 /* assign stack slots first */
1888 /* XXX: preallocate call stack */
1889 call_stack_size
= (nb_params
- nb_regs
) * sizeof(tcg_target_long
);
1890 call_stack_size
= (call_stack_size
+ TCG_TARGET_STACK_ALIGN
- 1) &
1891 ~(TCG_TARGET_STACK_ALIGN
- 1);
1892 allocate_args
= (call_stack_size
> TCG_STATIC_CALL_ARGS_SIZE
);
1893 if (allocate_args
) {
1894 tcg_out_addi(s
, TCG_REG_CALL_STACK
, -STACK_DIR(call_stack_size
));
1897 stack_offset
= TCG_TARGET_CALL_STACK_OFFSET
;
1898 for(i
= nb_regs
; i
< nb_params
; i
++) {
1899 arg
= args
[nb_oargs
+ i
];
1900 #ifdef TCG_TARGET_STACK_GROWSUP
1901 stack_offset
-= sizeof(tcg_target_long
);
1903 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1904 ts
= &s
->temps
[arg
];
1905 if (ts
->val_type
== TEMP_VAL_REG
) {
1906 tcg_out_st(s
, ts
->type
, ts
->reg
, TCG_REG_CALL_STACK
, stack_offset
);
1907 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1908 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1910 /* XXX: not correct if reading values from the stack */
1911 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1912 tcg_out_st(s
, ts
->type
, reg
, TCG_REG_CALL_STACK
, stack_offset
);
1913 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1914 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1916 /* XXX: sign extend may be needed on some targets */
1917 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1918 tcg_out_st(s
, ts
->type
, reg
, TCG_REG_CALL_STACK
, stack_offset
);
1923 #ifndef TCG_TARGET_STACK_GROWSUP
1924 stack_offset
+= sizeof(tcg_target_long
);
1928 /* assign input registers */
1929 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1930 for(i
= 0; i
< nb_regs
; i
++) {
1931 arg
= args
[nb_oargs
+ i
];
1932 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1933 ts
= &s
->temps
[arg
];
1934 reg
= tcg_target_call_iarg_regs
[i
];
1935 tcg_reg_free(s
, reg
);
1936 if (ts
->val_type
== TEMP_VAL_REG
) {
1937 if (ts
->reg
!= reg
) {
1938 tcg_out_mov(s
, reg
, ts
->reg
);
1940 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1941 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1942 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1943 /* XXX: sign extend ? */
1944 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1948 tcg_regset_set_reg(allocated_regs
, reg
);
1952 /* assign function address */
1953 func_arg
= args
[nb_oargs
+ nb_iargs
- 1];
1954 arg_ct
= &def
->args_ct
[0];
1955 ts
= &s
->temps
[func_arg
];
1956 func_addr
= ts
->val
;
1958 if (ts
->val_type
== TEMP_VAL_MEM
) {
1959 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1960 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1962 tcg_regset_set_reg(allocated_regs
, reg
);
1963 } else if (ts
->val_type
== TEMP_VAL_REG
) {
1965 if (!tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1966 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1967 tcg_out_mov(s
, reg
, ts
->reg
);
1970 tcg_regset_set_reg(allocated_regs
, reg
);
1971 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1972 if (tcg_target_const_match(func_addr
, arg_ct
)) {
1974 func_arg
= func_addr
;
1976 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1977 tcg_out_movi(s
, ts
->type
, reg
, func_addr
);
1979 tcg_regset_set_reg(allocated_regs
, reg
);
1986 /* mark dead temporaries and free the associated registers */
1987 for(i
= 0; i
< nb_iargs
; i
++) {
1988 arg
= args
[nb_oargs
+ i
];
1989 if (IS_DEAD_IARG(i
)) {
1990 ts
= &s
->temps
[arg
];
1991 if (!ts
->fixed_reg
) {
1992 if (ts
->val_type
== TEMP_VAL_REG
)
1993 s
->reg_to_temp
[ts
->reg
] = -1;
1994 ts
->val_type
= TEMP_VAL_DEAD
;
1999 /* clobber call registers */
2000 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
2001 if (tcg_regset_test_reg(tcg_target_call_clobber_regs
, reg
)) {
2002 tcg_reg_free(s
, reg
);
2006 /* store globals and free associated registers (we assume the call
2007 can modify any global. */
2008 if (!(flags
& TCG_CALL_CONST
)) {
2009 save_globals(s
, allocated_regs
);
2012 tcg_out_op(s
, opc
, &func_arg
, &const_func_arg
);
2014 if (allocate_args
) {
2015 tcg_out_addi(s
, TCG_REG_CALL_STACK
, STACK_DIR(call_stack_size
));
2018 /* assign output registers and emit moves if needed */
2019 for(i
= 0; i
< nb_oargs
; i
++) {
2021 ts
= &s
->temps
[arg
];
2022 reg
= tcg_target_call_oarg_regs
[i
];
2023 assert(s
->reg_to_temp
[reg
] == -1);
2024 if (ts
->fixed_reg
) {
2025 if (ts
->reg
!= reg
) {
2026 tcg_out_mov(s
, ts
->reg
, reg
);
2029 if (ts
->val_type
== TEMP_VAL_REG
)
2030 s
->reg_to_temp
[ts
->reg
] = -1;
2031 ts
->val_type
= TEMP_VAL_REG
;
2033 ts
->mem_coherent
= 0;
2034 s
->reg_to_temp
[reg
] = arg
;
2038 return nb_iargs
+ nb_oargs
+ def
->nb_cargs
+ 1;
2041 #ifdef CONFIG_PROFILER
2043 static int64_t tcg_table_op_count
[NB_OPS
];
2045 static void dump_op_count(void)
2049 f
= fopen("/tmp/op.log", "w");
2050 for(i
= INDEX_op_end
; i
< NB_OPS
; i
++) {
2051 fprintf(f
, "%s %" PRId64
"\n", tcg_op_defs
[i
].name
, tcg_table_op_count
[i
]);
2058 static inline int tcg_gen_code_common(TCGContext
*s
, uint8_t *gen_code_buf
,
2062 const TCGOpDef
*def
;
2063 unsigned int dead_iargs
;
2067 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP
))) {
2069 tcg_dump_ops(s
, logfile
);
2074 #ifdef CONFIG_PROFILER
2075 s
->const_time
-= profile_getclock();
2077 tcg_const_analysis(s
);
2078 #ifdef CONFIG_PROFILER
2079 s
->const_time
+= profile_getclock();
2082 #ifdef CONFIG_PROFILER
2083 s
->la_time
-= profile_getclock();
2085 tcg_liveness_analysis(s
);
2086 #ifdef CONFIG_PROFILER
2087 s
->la_time
+= profile_getclock();
2091 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT
))) {
2092 qemu_log("OP after la:\n");
2093 tcg_dump_ops(s
, logfile
);
2098 tcg_reg_alloc_start(s
);
2100 s
->code_buf
= gen_code_buf
;
2101 s
->code_ptr
= gen_code_buf
;
2103 args
= gen_opparam_buf
;
2107 opc
= gen_opc_buf
[op_index
];
2108 #ifdef CONFIG_PROFILER
2109 tcg_table_op_count
[opc
]++;
2111 def
= &tcg_op_defs
[opc
];
2113 printf("%s: %d %d %d\n", def
->name
,
2114 def
->nb_oargs
, def
->nb_iargs
, def
->nb_cargs
);
2118 case INDEX_op_mov_i32
:
2119 #if TCG_TARGET_REG_BITS == 64
2120 case INDEX_op_mov_i64
:
2122 dead_iargs
= s
->op_dead_iargs
[op_index
];
2123 tcg_reg_alloc_mov(s
, def
, args
, dead_iargs
);
2125 case INDEX_op_movi_i32
:
2126 #if TCG_TARGET_REG_BITS == 64
2127 case INDEX_op_movi_i64
:
2129 tcg_reg_alloc_movi(s
, args
);
2131 case INDEX_op_debug_insn_start
:
2132 /* debug instruction */
2142 case INDEX_op_discard
:
2145 ts
= &s
->temps
[args
[0]];
2146 /* mark the temporary as dead */
2147 if (!ts
->fixed_reg
) {
2148 if (ts
->val_type
== TEMP_VAL_REG
)
2149 s
->reg_to_temp
[ts
->reg
] = -1;
2150 ts
->val_type
= TEMP_VAL_DEAD
;
2154 case INDEX_op_set_label
:
2155 tcg_reg_alloc_bb_end(s
, s
->reserved_regs
);
2156 tcg_out_label(s
, args
[0], (intptr_t)s
->code_ptr
);
2159 dead_iargs
= s
->op_dead_iargs
[op_index
];
2160 args
+= tcg_reg_alloc_call(s
, def
, opc
, args
, dead_iargs
);
2165 /* Note: in order to speed up the code, it would be much
2166 faster to have specialized register allocator functions for
2167 some common argument patterns */
2168 dead_iargs
= s
->op_dead_iargs
[op_index
];
2169 tcg_reg_alloc_op(s
, def
, opc
, args
, dead_iargs
);
2172 args
+= def
->nb_args
;
2174 if (search_pc
>= 0 && search_pc
< s
->code_ptr
- gen_code_buf
) {
2186 int tcg_gen_code(TCGContext
*s
, uint8_t *gen_code_buf
)
2188 #ifdef CONFIG_PROFILER
2191 n
= (gen_opc_ptr
- gen_opc_buf
);
2193 if (n
> s
->op_count_max
)
2194 s
->op_count_max
= n
;
2196 s
->temp_count
+= s
->nb_temps
;
2197 if (s
->nb_temps
> s
->temp_count_max
)
2198 s
->temp_count_max
= s
->nb_temps
;
2202 tcg_gen_code_common(s
, gen_code_buf
, -1);
2204 /* flush instruction cache */
2205 flush_icache_range((uintptr_t)gen_code_buf
,
2206 (uintptr_t)s
->code_ptr
);
2207 return s
->code_ptr
- gen_code_buf
;
2210 /* Return the index of the micro operation such as the pc after is <
2211 offset bytes from the start of the TB. The contents of gen_code_buf must
2212 not be changed, though writing the same values is ok.
2213 Return -1 if not found. */
2214 int tcg_gen_code_search_pc(TCGContext
*s
, uint8_t *gen_code_buf
, long offset
)
2216 return tcg_gen_code_common(s
, gen_code_buf
, offset
);
2219 #ifdef CONFIG_PROFILER
2220 void tcg_dump_info(FILE *f
,
2221 int (*cpu_fprintf
)(FILE *f
, const char *fmt
, ...))
2223 TCGContext
*s
= &tcg_ctx
;
2226 tot
= s
->interm_time
+ s
->code_time
;
2227 cpu_fprintf(f
, "JIT cycles %" PRId64
" (%0.3f s at 2.4 GHz)\n",
2229 cpu_fprintf(f
, "translated TBs %" PRId64
" (aborted=%" PRId64
" %0.1f%%)\n",
2231 s
->tb_count1
- s
->tb_count
,
2232 s
->tb_count1
? (double)(s
->tb_count1
- s
->tb_count
) / s
->tb_count1
* 100.0 : 0);
2233 cpu_fprintf(f
, "avg ops/TB %0.1f max=%d\n",
2234 s
->tb_count
? (double)s
->op_count
/ s
->tb_count
: 0, s
->op_count_max
);
2235 cpu_fprintf(f
, "deleted ops/TB %0.2f\n",
2237 (double)s
->del_op_count
/ s
->tb_count
: 0);
2238 cpu_fprintf(f
, "avg temps/TB %0.2f max=%d\n",
2240 (double)s
->temp_count
/ s
->tb_count
: 0,
2243 cpu_fprintf(f
, "cycles/op %0.1f\n",
2244 s
->op_count
? (double)tot
/ s
->op_count
: 0);
2245 cpu_fprintf(f
, "cycles/in byte %0.1f\n",
2246 s
->code_in_len
? (double)tot
/ s
->code_in_len
: 0);
2247 cpu_fprintf(f
, "cycles/out byte %0.1f\n",
2248 s
->code_out_len
? (double)tot
/ s
->code_out_len
: 0);
2251 cpu_fprintf(f
, " gen_interm time %0.1f%%\n",
2252 (double)s
->interm_time
/ tot
* 100.0);
2253 cpu_fprintf(f
, " gen_code time %0.1f%%\n",
2254 (double)s
->code_time
/ tot
* 100.0);
2255 cpu_fprintf(f
, "const/code time %0.1f%%\n",
2256 (double)s
->const_time
/ (s
->code_time
? s
->code_time
: 1) * 100.0);
2257 cpu_fprintf(f
, "liveness/code time %0.1f%%\n",
2258 (double)s
->la_time
/ (s
->code_time
? s
->code_time
: 1) * 100.0);
2259 cpu_fprintf(f
, "cpu_restore count %" PRId64
"\n",
2261 cpu_fprintf(f
, " avg cycles %0.1f\n",
2262 s
->restore_count
? (double)s
->restore_time
/ s
->restore_count
: 0);
2267 void tcg_dump_info(FILE *f
,
2268 int (*cpu_fprintf
)(FILE *f
, const char *fmt
, ...))
2270 cpu_fprintf(f
, "[TCG profiler not compiled]\n");