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 #if !defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG)
31 /* define it to suppress various consistency checks (faster) */
47 #include "qemu-common.h"
48 #include "cache-utils.h"
49 #include "host-utils.h"
50 #include "qemu-timer.h"
52 /* Note: the long term plan is to reduce the dependancies on the QEMU
53 CPU definitions. Currently they are used for qemu_ld/st
55 #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 tcg_target_init(TCGContext
*s
);
66 static void tcg_target_qemu_prologue(TCGContext
*s
);
67 static void patch_reloc(uint8_t *code_ptr
, int type
,
68 tcg_target_long value
, tcg_target_long addend
);
70 static TCGOpDef tcg_op_defs
[] = {
71 #define DEF(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags },
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 static 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
;
244 void tcg_prologue_init(TCGContext
*s
)
246 /* init global prologue and epilogue */
247 s
->code_buf
= code_gen_prologue
;
248 s
->code_ptr
= s
->code_buf
;
249 tcg_target_qemu_prologue(s
);
250 flush_icache_range((unsigned long)s
->code_buf
,
251 (unsigned long)s
->code_ptr
);
254 void tcg_set_frame(TCGContext
*s
, int reg
,
255 tcg_target_long start
, tcg_target_long size
)
257 s
->frame_start
= start
;
258 s
->frame_end
= start
+ size
;
262 void tcg_func_start(TCGContext
*s
)
266 s
->nb_temps
= s
->nb_globals
;
267 for(i
= 0; i
< (TCG_TYPE_COUNT
* 2); i
++)
268 s
->first_free_temp
[i
] = -1;
269 s
->labels
= tcg_malloc(sizeof(TCGLabel
) * TCG_MAX_LABELS
);
271 s
->current_frame_offset
= s
->frame_start
;
273 gen_opc_ptr
= gen_opc_buf
;
274 gen_opparam_ptr
= gen_opparam_buf
;
277 static inline void tcg_temp_alloc(TCGContext
*s
, int n
)
279 if (n
> TCG_MAX_TEMPS
)
283 static inline int tcg_global_reg_new_internal(TCGType type
, int reg
,
286 TCGContext
*s
= &tcg_ctx
;
290 #if TCG_TARGET_REG_BITS == 32
291 if (type
!= TCG_TYPE_I32
)
294 if (tcg_regset_test_reg(s
->reserved_regs
, reg
))
297 tcg_temp_alloc(s
, s
->nb_globals
+ 1);
298 ts
= &s
->temps
[s
->nb_globals
];
299 ts
->base_type
= type
;
305 tcg_regset_set_reg(s
->reserved_regs
, reg
);
309 TCGv_i32
tcg_global_reg_new_i32(int reg
, const char *name
)
313 idx
= tcg_global_reg_new_internal(TCG_TYPE_I32
, reg
, name
);
314 return MAKE_TCGV_I32(idx
);
317 TCGv_i64
tcg_global_reg_new_i64(int reg
, const char *name
)
321 idx
= tcg_global_reg_new_internal(TCG_TYPE_I64
, reg
, name
);
322 return MAKE_TCGV_I64(idx
);
325 static inline int tcg_global_mem_new_internal(TCGType type
, int reg
,
326 tcg_target_long offset
,
329 TCGContext
*s
= &tcg_ctx
;
334 #if TCG_TARGET_REG_BITS == 32
335 if (type
== TCG_TYPE_I64
) {
337 tcg_temp_alloc(s
, s
->nb_globals
+ 2);
338 ts
= &s
->temps
[s
->nb_globals
];
339 ts
->base_type
= type
;
340 ts
->type
= TCG_TYPE_I32
;
342 ts
->mem_allocated
= 1;
344 #ifdef TCG_TARGET_WORDS_BIGENDIAN
345 ts
->mem_offset
= offset
+ 4;
347 ts
->mem_offset
= offset
;
349 pstrcpy(buf
, sizeof(buf
), name
);
350 pstrcat(buf
, sizeof(buf
), "_0");
351 ts
->name
= strdup(buf
);
354 ts
->base_type
= type
;
355 ts
->type
= TCG_TYPE_I32
;
357 ts
->mem_allocated
= 1;
359 #ifdef TCG_TARGET_WORDS_BIGENDIAN
360 ts
->mem_offset
= offset
;
362 ts
->mem_offset
= offset
+ 4;
364 pstrcpy(buf
, sizeof(buf
), name
);
365 pstrcat(buf
, sizeof(buf
), "_1");
366 ts
->name
= strdup(buf
);
372 tcg_temp_alloc(s
, s
->nb_globals
+ 1);
373 ts
= &s
->temps
[s
->nb_globals
];
374 ts
->base_type
= type
;
377 ts
->mem_allocated
= 1;
379 ts
->mem_offset
= offset
;
386 TCGv_i32
tcg_global_mem_new_i32(int reg
, tcg_target_long offset
,
391 idx
= tcg_global_mem_new_internal(TCG_TYPE_I32
, reg
, offset
, name
);
392 return MAKE_TCGV_I32(idx
);
395 TCGv_i64
tcg_global_mem_new_i64(int reg
, tcg_target_long offset
,
400 idx
= tcg_global_mem_new_internal(TCG_TYPE_I64
, reg
, offset
, name
);
401 return MAKE_TCGV_I64(idx
);
404 static inline int tcg_temp_new_internal(TCGType type
, int temp_local
)
406 TCGContext
*s
= &tcg_ctx
;
413 idx
= s
->first_free_temp
[k
];
415 /* There is already an available temp with the
418 s
->first_free_temp
[k
] = ts
->next_free_temp
;
419 ts
->temp_allocated
= 1;
420 assert(ts
->temp_local
== temp_local
);
423 #if TCG_TARGET_REG_BITS == 32
424 if (type
== TCG_TYPE_I64
) {
425 tcg_temp_alloc(s
, s
->nb_temps
+ 2);
426 ts
= &s
->temps
[s
->nb_temps
];
427 ts
->base_type
= type
;
428 ts
->type
= TCG_TYPE_I32
;
429 ts
->temp_allocated
= 1;
430 ts
->temp_local
= temp_local
;
433 ts
->base_type
= TCG_TYPE_I32
;
434 ts
->type
= TCG_TYPE_I32
;
435 ts
->temp_allocated
= 1;
436 ts
->temp_local
= temp_local
;
442 tcg_temp_alloc(s
, s
->nb_temps
+ 1);
443 ts
= &s
->temps
[s
->nb_temps
];
444 ts
->base_type
= type
;
446 ts
->temp_allocated
= 1;
447 ts
->temp_local
= temp_local
;
453 #if defined(CONFIG_DEBUG_TCG)
459 TCGv_i32
tcg_temp_new_internal_i32(int temp_local
)
463 idx
= tcg_temp_new_internal(TCG_TYPE_I32
, temp_local
);
464 return MAKE_TCGV_I32(idx
);
467 TCGv_i64
tcg_temp_new_internal_i64(int temp_local
)
471 idx
= tcg_temp_new_internal(TCG_TYPE_I64
, temp_local
);
472 return MAKE_TCGV_I64(idx
);
475 static inline void tcg_temp_free_internal(int idx
)
477 TCGContext
*s
= &tcg_ctx
;
481 #if defined(CONFIG_DEBUG_TCG)
483 if (s
->temps_in_use
< 0) {
484 fprintf(stderr
, "More temporaries freed than allocated!\n");
488 assert(idx
>= s
->nb_globals
&& idx
< s
->nb_temps
);
490 assert(ts
->temp_allocated
!= 0);
491 ts
->temp_allocated
= 0;
495 ts
->next_free_temp
= s
->first_free_temp
[k
];
496 s
->first_free_temp
[k
] = idx
;
499 void tcg_temp_free_i32(TCGv_i32 arg
)
501 tcg_temp_free_internal(GET_TCGV_I32(arg
));
504 void tcg_temp_free_i64(TCGv_i64 arg
)
506 tcg_temp_free_internal(GET_TCGV_I64(arg
));
509 TCGv_i32
tcg_const_i32(int32_t val
)
512 t0
= tcg_temp_new_i32();
513 tcg_gen_movi_i32(t0
, val
);
517 TCGv_i64
tcg_const_i64(int64_t val
)
520 t0
= tcg_temp_new_i64();
521 tcg_gen_movi_i64(t0
, val
);
525 TCGv_i32
tcg_const_local_i32(int32_t val
)
528 t0
= tcg_temp_local_new_i32();
529 tcg_gen_movi_i32(t0
, val
);
533 TCGv_i64
tcg_const_local_i64(int64_t val
)
536 t0
= tcg_temp_local_new_i64();
537 tcg_gen_movi_i64(t0
, val
);
541 #if defined(CONFIG_DEBUG_TCG)
542 void tcg_clear_temp_count(void)
544 TCGContext
*s
= &tcg_ctx
;
548 int tcg_check_temp_count(void)
550 TCGContext
*s
= &tcg_ctx
;
551 if (s
->temps_in_use
) {
552 /* Clear the count so that we don't give another
553 * warning immediately next time around.
562 void tcg_register_helper(void *func
, const char *name
)
564 TCGContext
*s
= &tcg_ctx
;
566 if ((s
->nb_helpers
+ 1) > s
->allocated_helpers
) {
567 n
= s
->allocated_helpers
;
573 s
->helpers
= realloc(s
->helpers
, n
* sizeof(TCGHelperInfo
));
574 s
->allocated_helpers
= n
;
576 s
->helpers
[s
->nb_helpers
].func
= (tcg_target_ulong
)func
;
577 s
->helpers
[s
->nb_helpers
].name
= name
;
581 /* Note: we convert the 64 bit args to 32 bit and do some alignment
582 and endian swap. Maybe it would be better to do the alignment
583 and endian swap in tcg_reg_alloc_call(). */
584 void tcg_gen_callN(TCGContext
*s
, TCGv_ptr func
, unsigned int flags
,
585 int sizemask
, TCGArg ret
, int nargs
, TCGArg
*args
)
587 #if defined(TCG_TARGET_I386) && TCG_TARGET_REG_BITS < 64
595 #if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
596 for (i
= 0; i
< nargs
; ++i
) {
597 int is_64bit
= sizemask
& (1 << (i
+1)*2);
598 int is_signed
= sizemask
& (2 << (i
+1)*2);
600 TCGv_i64 temp
= tcg_temp_new_i64();
601 TCGv_i64 orig
= MAKE_TCGV_I64(args
[i
]);
603 tcg_gen_ext32s_i64(temp
, orig
);
605 tcg_gen_ext32u_i64(temp
, orig
);
607 args
[i
] = GET_TCGV_I64(temp
);
610 #endif /* TCG_TARGET_EXTEND_ARGS */
612 *gen_opc_ptr
++ = INDEX_op_call
;
613 nparam
= gen_opparam_ptr
++;
614 #if defined(TCG_TARGET_I386) && TCG_TARGET_REG_BITS < 64
615 call_type
= (flags
& TCG_CALL_TYPE_MASK
);
617 if (ret
!= TCG_CALL_DUMMY_ARG
) {
618 #if TCG_TARGET_REG_BITS < 64
620 #ifdef TCG_TARGET_WORDS_BIGENDIAN
621 *gen_opparam_ptr
++ = ret
+ 1;
622 *gen_opparam_ptr
++ = ret
;
624 *gen_opparam_ptr
++ = ret
;
625 *gen_opparam_ptr
++ = ret
+ 1;
631 *gen_opparam_ptr
++ = ret
;
638 for (i
= 0; i
< nargs
; i
++) {
639 #if TCG_TARGET_REG_BITS < 64
640 int is_64bit
= sizemask
& (1 << (i
+1)*2);
642 #ifdef TCG_TARGET_I386
643 /* REGPARM case: if the third parameter is 64 bit, it is
644 allocated on the stack */
645 if (i
== 2 && call_type
== TCG_CALL_TYPE_REGPARM
) {
646 call_type
= TCG_CALL_TYPE_REGPARM_2
;
647 flags
= (flags
& ~TCG_CALL_TYPE_MASK
) | call_type
;
650 #ifdef TCG_TARGET_CALL_ALIGN_ARGS
651 /* some targets want aligned 64 bit args */
653 *gen_opparam_ptr
++ = TCG_CALL_DUMMY_ARG
;
657 /* If stack grows up, then we will be placing successive
658 arguments at lower addresses, which means we need to
659 reverse the order compared to how we would normally
660 treat either big or little-endian. For those arguments
661 that will wind up in registers, this still works for
662 HPPA (the only current STACK_GROWSUP target) since the
663 argument registers are *also* allocated in decreasing
664 order. If another such target is added, this logic may
665 have to get more complicated to differentiate between
666 stack arguments and register arguments. */
667 #if defined(TCG_TARGET_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
668 *gen_opparam_ptr
++ = args
[i
] + 1;
669 *gen_opparam_ptr
++ = args
[i
];
671 *gen_opparam_ptr
++ = args
[i
];
672 *gen_opparam_ptr
++ = args
[i
] + 1;
677 #endif /* TCG_TARGET_REG_BITS < 64 */
679 *gen_opparam_ptr
++ = args
[i
];
682 *gen_opparam_ptr
++ = GET_TCGV_PTR(func
);
684 *gen_opparam_ptr
++ = flags
;
686 *nparam
= (nb_rets
<< 16) | (real_args
+ 1);
688 /* total parameters, needed to go backward in the instruction stream */
689 *gen_opparam_ptr
++ = 1 + nb_rets
+ real_args
+ 3;
691 #if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
692 for (i
= 0; i
< nargs
; ++i
) {
693 int is_64bit
= sizemask
& (1 << (i
+1)*2);
695 TCGv_i64 temp
= MAKE_TCGV_I64(args
[i
]);
696 tcg_temp_free_i64(temp
);
699 #endif /* TCG_TARGET_EXTEND_ARGS */
702 #if TCG_TARGET_REG_BITS == 32
703 void tcg_gen_shifti_i64(TCGv_i64 ret
, TCGv_i64 arg1
,
704 int c
, int right
, int arith
)
707 tcg_gen_mov_i32(TCGV_LOW(ret
), TCGV_LOW(arg1
));
708 tcg_gen_mov_i32(TCGV_HIGH(ret
), TCGV_HIGH(arg1
));
709 } else if (c
>= 32) {
713 tcg_gen_sari_i32(TCGV_LOW(ret
), TCGV_HIGH(arg1
), c
);
714 tcg_gen_sari_i32(TCGV_HIGH(ret
), TCGV_HIGH(arg1
), 31);
716 tcg_gen_shri_i32(TCGV_LOW(ret
), TCGV_HIGH(arg1
), c
);
717 tcg_gen_movi_i32(TCGV_HIGH(ret
), 0);
720 tcg_gen_shli_i32(TCGV_HIGH(ret
), TCGV_LOW(arg1
), c
);
721 tcg_gen_movi_i32(TCGV_LOW(ret
), 0);
726 t0
= tcg_temp_new_i32();
727 t1
= tcg_temp_new_i32();
729 tcg_gen_shli_i32(t0
, TCGV_HIGH(arg1
), 32 - c
);
731 tcg_gen_sari_i32(t1
, TCGV_HIGH(arg1
), c
);
733 tcg_gen_shri_i32(t1
, TCGV_HIGH(arg1
), c
);
734 tcg_gen_shri_i32(TCGV_LOW(ret
), TCGV_LOW(arg1
), c
);
735 tcg_gen_or_i32(TCGV_LOW(ret
), TCGV_LOW(ret
), t0
);
736 tcg_gen_mov_i32(TCGV_HIGH(ret
), t1
);
738 tcg_gen_shri_i32(t0
, TCGV_LOW(arg1
), 32 - c
);
739 /* Note: ret can be the same as arg1, so we use t1 */
740 tcg_gen_shli_i32(t1
, TCGV_LOW(arg1
), c
);
741 tcg_gen_shli_i32(TCGV_HIGH(ret
), TCGV_HIGH(arg1
), c
);
742 tcg_gen_or_i32(TCGV_HIGH(ret
), TCGV_HIGH(ret
), t0
);
743 tcg_gen_mov_i32(TCGV_LOW(ret
), t1
);
745 tcg_temp_free_i32(t0
);
746 tcg_temp_free_i32(t1
);
752 static void tcg_reg_alloc_start(TCGContext
*s
)
756 for(i
= 0; i
< s
->nb_globals
; i
++) {
759 ts
->val_type
= TEMP_VAL_REG
;
761 ts
->val_type
= TEMP_VAL_MEM
;
764 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
766 ts
->val_type
= TEMP_VAL_DEAD
;
767 ts
->mem_allocated
= 0;
770 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
771 s
->reg_to_temp
[i
] = -1;
775 static char *tcg_get_arg_str_idx(TCGContext
*s
, char *buf
, int buf_size
,
781 if (idx
< s
->nb_globals
) {
782 pstrcpy(buf
, buf_size
, ts
->name
);
785 snprintf(buf
, buf_size
, "loc%d", idx
- s
->nb_globals
);
787 snprintf(buf
, buf_size
, "tmp%d", idx
- s
->nb_globals
);
792 char *tcg_get_arg_str_i32(TCGContext
*s
, char *buf
, int buf_size
, TCGv_i32 arg
)
794 return tcg_get_arg_str_idx(s
, buf
, buf_size
, GET_TCGV_I32(arg
));
797 char *tcg_get_arg_str_i64(TCGContext
*s
, char *buf
, int buf_size
, TCGv_i64 arg
)
799 return tcg_get_arg_str_idx(s
, buf
, buf_size
, GET_TCGV_I64(arg
));
802 static int helper_cmp(const void *p1
, const void *p2
)
804 const TCGHelperInfo
*th1
= p1
;
805 const TCGHelperInfo
*th2
= p2
;
806 if (th1
->func
< th2
->func
)
808 else if (th1
->func
== th2
->func
)
814 /* find helper definition (Note: A hash table would be better) */
815 static TCGHelperInfo
*tcg_find_helper(TCGContext
*s
, tcg_target_ulong val
)
821 if (unlikely(!s
->helpers_sorted
)) {
822 qsort(s
->helpers
, s
->nb_helpers
, sizeof(TCGHelperInfo
),
824 s
->helpers_sorted
= 1;
829 m_max
= s
->nb_helpers
- 1;
830 while (m_min
<= m_max
) {
831 m
= (m_min
+ m_max
) >> 1;
845 static const char * const cond_name
[] =
847 [TCG_COND_EQ
] = "eq",
848 [TCG_COND_NE
] = "ne",
849 [TCG_COND_LT
] = "lt",
850 [TCG_COND_GE
] = "ge",
851 [TCG_COND_LE
] = "le",
852 [TCG_COND_GT
] = "gt",
853 [TCG_COND_LTU
] = "ltu",
854 [TCG_COND_GEU
] = "geu",
855 [TCG_COND_LEU
] = "leu",
856 [TCG_COND_GTU
] = "gtu"
859 void tcg_dump_ops(TCGContext
*s
, FILE *outfile
)
861 const uint16_t *opc_ptr
;
865 int i
, k
, nb_oargs
, nb_iargs
, nb_cargs
, first_insn
;
870 opc_ptr
= gen_opc_buf
;
871 args
= gen_opparam_buf
;
872 while (opc_ptr
< gen_opc_ptr
) {
874 def
= &tcg_op_defs
[c
];
875 if (c
== INDEX_op_debug_insn_start
) {
877 #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
878 pc
= ((uint64_t)args
[1] << 32) | args
[0];
883 fprintf(outfile
, "\n");
884 fprintf(outfile
, " ---- 0x%" PRIx64
, pc
);
886 nb_oargs
= def
->nb_oargs
;
887 nb_iargs
= def
->nb_iargs
;
888 nb_cargs
= def
->nb_cargs
;
889 } else if (c
== INDEX_op_call
) {
892 /* variable number of arguments */
894 nb_oargs
= arg
>> 16;
895 nb_iargs
= arg
& 0xffff;
896 nb_cargs
= def
->nb_cargs
;
898 fprintf(outfile
, " %s ", def
->name
);
901 fprintf(outfile
, "%s",
902 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[nb_oargs
+ nb_iargs
- 1]));
904 fprintf(outfile
, ",$0x%" TCG_PRIlx
,
905 args
[nb_oargs
+ nb_iargs
]);
907 fprintf(outfile
, ",$%d", nb_oargs
);
908 for(i
= 0; i
< nb_oargs
; i
++) {
909 fprintf(outfile
, ",");
910 fprintf(outfile
, "%s",
911 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[i
]));
913 for(i
= 0; i
< (nb_iargs
- 1); i
++) {
914 fprintf(outfile
, ",");
915 if (args
[nb_oargs
+ i
] == TCG_CALL_DUMMY_ARG
) {
916 fprintf(outfile
, "<dummy>");
918 fprintf(outfile
, "%s",
919 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[nb_oargs
+ i
]));
922 } else if (c
== INDEX_op_movi_i32
923 #if TCG_TARGET_REG_BITS == 64
924 || c
== INDEX_op_movi_i64
927 tcg_target_ulong val
;
930 nb_oargs
= def
->nb_oargs
;
931 nb_iargs
= def
->nb_iargs
;
932 nb_cargs
= def
->nb_cargs
;
933 fprintf(outfile
, " %s %s,$", def
->name
,
934 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[0]));
936 th
= tcg_find_helper(s
, val
);
938 fprintf(outfile
, "%s", th
->name
);
940 if (c
== INDEX_op_movi_i32
)
941 fprintf(outfile
, "0x%x", (uint32_t)val
);
943 fprintf(outfile
, "0x%" PRIx64
, (uint64_t)val
);
946 fprintf(outfile
, " %s ", def
->name
);
947 if (c
== INDEX_op_nopn
) {
948 /* variable number of arguments */
953 nb_oargs
= def
->nb_oargs
;
954 nb_iargs
= def
->nb_iargs
;
955 nb_cargs
= def
->nb_cargs
;
959 for(i
= 0; i
< nb_oargs
; i
++) {
961 fprintf(outfile
, ",");
962 fprintf(outfile
, "%s",
963 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[k
++]));
965 for(i
= 0; i
< nb_iargs
; i
++) {
967 fprintf(outfile
, ",");
968 fprintf(outfile
, "%s",
969 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[k
++]));
972 case INDEX_op_brcond_i32
:
973 #if TCG_TARGET_REG_BITS == 32
974 case INDEX_op_brcond2_i32
:
975 #elif TCG_TARGET_REG_BITS == 64
976 case INDEX_op_brcond_i64
:
978 case INDEX_op_setcond_i32
:
979 #if TCG_TARGET_REG_BITS == 32
980 case INDEX_op_setcond2_i32
:
981 #elif TCG_TARGET_REG_BITS == 64
982 case INDEX_op_setcond_i64
:
984 if (args
[k
] < ARRAY_SIZE(cond_name
) && cond_name
[args
[k
]])
985 fprintf(outfile
, ",%s", cond_name
[args
[k
++]]);
987 fprintf(outfile
, ",$0x%" TCG_PRIlx
, args
[k
++]);
994 for(; i
< nb_cargs
; i
++) {
996 fprintf(outfile
, ",");
998 fprintf(outfile
, "$0x%" TCG_PRIlx
, arg
);
1001 fprintf(outfile
, "\n");
1002 args
+= nb_iargs
+ nb_oargs
+ nb_cargs
;
1006 /* we give more priority to constraints with less registers */
1007 static int get_constraint_priority(const TCGOpDef
*def
, int k
)
1009 const TCGArgConstraint
*arg_ct
;
1012 arg_ct
= &def
->args_ct
[k
];
1013 if (arg_ct
->ct
& TCG_CT_ALIAS
) {
1014 /* an alias is equivalent to a single register */
1017 if (!(arg_ct
->ct
& TCG_CT_REG
))
1020 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
1021 if (tcg_regset_test_reg(arg_ct
->u
.regs
, i
))
1025 return TCG_TARGET_NB_REGS
- n
+ 1;
1028 /* sort from highest priority to lowest */
1029 static void sort_constraints(TCGOpDef
*def
, int start
, int n
)
1031 int i
, j
, p1
, p2
, tmp
;
1033 for(i
= 0; i
< n
; i
++)
1034 def
->sorted_args
[start
+ i
] = start
+ i
;
1037 for(i
= 0; i
< n
- 1; i
++) {
1038 for(j
= i
+ 1; j
< n
; j
++) {
1039 p1
= get_constraint_priority(def
, def
->sorted_args
[start
+ i
]);
1040 p2
= get_constraint_priority(def
, def
->sorted_args
[start
+ j
]);
1042 tmp
= def
->sorted_args
[start
+ i
];
1043 def
->sorted_args
[start
+ i
] = def
->sorted_args
[start
+ j
];
1044 def
->sorted_args
[start
+ j
] = tmp
;
1050 void tcg_add_target_add_op_defs(const TCGTargetOpDef
*tdefs
)
1058 if (tdefs
->op
== (TCGOpcode
)-1)
1061 assert((unsigned)op
< NB_OPS
);
1062 def
= &tcg_op_defs
[op
];
1063 #if defined(CONFIG_DEBUG_TCG)
1064 /* Duplicate entry in op definitions? */
1068 nb_args
= def
->nb_iargs
+ def
->nb_oargs
;
1069 for(i
= 0; i
< nb_args
; i
++) {
1070 ct_str
= tdefs
->args_ct_str
[i
];
1071 /* Incomplete TCGTargetOpDef entry? */
1072 assert(ct_str
!= NULL
);
1073 tcg_regset_clear(def
->args_ct
[i
].u
.regs
);
1074 def
->args_ct
[i
].ct
= 0;
1075 if (ct_str
[0] >= '0' && ct_str
[0] <= '9') {
1077 oarg
= ct_str
[0] - '0';
1078 assert(oarg
< def
->nb_oargs
);
1079 assert(def
->args_ct
[oarg
].ct
& TCG_CT_REG
);
1080 /* TCG_CT_ALIAS is for the output arguments. The input
1081 argument is tagged with TCG_CT_IALIAS. */
1082 def
->args_ct
[i
] = def
->args_ct
[oarg
];
1083 def
->args_ct
[oarg
].ct
= TCG_CT_ALIAS
;
1084 def
->args_ct
[oarg
].alias_index
= i
;
1085 def
->args_ct
[i
].ct
|= TCG_CT_IALIAS
;
1086 def
->args_ct
[i
].alias_index
= oarg
;
1089 if (*ct_str
== '\0')
1093 def
->args_ct
[i
].ct
|= TCG_CT_CONST
;
1097 if (target_parse_constraint(&def
->args_ct
[i
], &ct_str
) < 0) {
1098 fprintf(stderr
, "Invalid constraint '%s' for arg %d of operation '%s'\n",
1099 ct_str
, i
, def
->name
);
1107 /* TCGTargetOpDef entry with too much information? */
1108 assert(i
== TCG_MAX_OP_ARGS
|| tdefs
->args_ct_str
[i
] == NULL
);
1110 /* sort the constraints (XXX: this is just an heuristic) */
1111 sort_constraints(def
, 0, def
->nb_oargs
);
1112 sort_constraints(def
, def
->nb_oargs
, def
->nb_iargs
);
1118 printf("%s: sorted=", def
->name
);
1119 for(i
= 0; i
< def
->nb_oargs
+ def
->nb_iargs
; i
++)
1120 printf(" %d", def
->sorted_args
[i
]);
1127 #if defined(CONFIG_DEBUG_TCG)
1129 for (op
= 0; op
< ARRAY_SIZE(tcg_op_defs
); op
++) {
1130 if (op
< INDEX_op_call
|| op
== INDEX_op_debug_insn_start
) {
1131 /* Wrong entry in op definitions? */
1132 if (tcg_op_defs
[op
].used
) {
1133 fprintf(stderr
, "Invalid op definition for %s\n",
1134 tcg_op_defs
[op
].name
);
1138 /* Missing entry in op definitions? */
1139 if (!tcg_op_defs
[op
].used
) {
1140 fprintf(stderr
, "Missing op definition for %s\n",
1141 tcg_op_defs
[op
].name
);
1152 #ifdef USE_LIVENESS_ANALYSIS
1154 /* set a nop for an operation using 'nb_args' */
1155 static inline void tcg_set_nop(TCGContext
*s
, uint16_t *opc_ptr
,
1156 TCGArg
*args
, int nb_args
)
1159 *opc_ptr
= INDEX_op_nop
;
1161 *opc_ptr
= INDEX_op_nopn
;
1163 args
[nb_args
- 1] = nb_args
;
1167 /* liveness analysis: end of function: globals are live, temps are
1169 /* XXX: at this stage, not used as there would be little gains because
1170 most TBs end with a conditional jump. */
1171 static inline void tcg_la_func_end(TCGContext
*s
, uint8_t *dead_temps
)
1173 memset(dead_temps
, 0, s
->nb_globals
);
1174 memset(dead_temps
+ s
->nb_globals
, 1, s
->nb_temps
- s
->nb_globals
);
1177 /* liveness analysis: end of basic block: globals are live, temps are
1178 dead, local temps are live. */
1179 static inline void tcg_la_bb_end(TCGContext
*s
, uint8_t *dead_temps
)
1184 memset(dead_temps
, 0, s
->nb_globals
);
1185 ts
= &s
->temps
[s
->nb_globals
];
1186 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
1195 /* Liveness analysis : update the opc_dead_args array to tell if a
1196 given input arguments is dead. Instructions updating dead
1197 temporaries are removed. */
1198 static void tcg_liveness_analysis(TCGContext
*s
)
1200 int i
, op_index
, nb_args
, nb_iargs
, nb_oargs
, arg
, nb_ops
;
1203 const TCGOpDef
*def
;
1204 uint8_t *dead_temps
;
1205 unsigned int dead_args
;
1207 gen_opc_ptr
++; /* skip end */
1209 nb_ops
= gen_opc_ptr
- gen_opc_buf
;
1211 s
->op_dead_args
= tcg_malloc(nb_ops
* sizeof(uint16_t));
1213 dead_temps
= tcg_malloc(s
->nb_temps
);
1214 memset(dead_temps
, 1, s
->nb_temps
);
1216 args
= gen_opparam_ptr
;
1217 op_index
= nb_ops
- 1;
1218 while (op_index
>= 0) {
1219 op
= gen_opc_buf
[op_index
];
1220 def
= &tcg_op_defs
[op
];
1228 nb_iargs
= args
[0] & 0xffff;
1229 nb_oargs
= args
[0] >> 16;
1231 call_flags
= args
[nb_oargs
+ nb_iargs
];
1233 /* pure functions can be removed if their result is not
1235 if (call_flags
& TCG_CALL_PURE
) {
1236 for(i
= 0; i
< nb_oargs
; i
++) {
1238 if (!dead_temps
[arg
])
1239 goto do_not_remove_call
;
1241 tcg_set_nop(s
, gen_opc_buf
+ op_index
,
1246 /* output args are dead */
1248 for(i
= 0; i
< nb_oargs
; i
++) {
1250 if (dead_temps
[arg
]) {
1251 dead_args
|= (1 << i
);
1253 dead_temps
[arg
] = 1;
1256 if (!(call_flags
& TCG_CALL_CONST
)) {
1257 /* globals are live (they may be used by the call) */
1258 memset(dead_temps
, 0, s
->nb_globals
);
1261 /* input args are live */
1262 for(i
= nb_oargs
; i
< nb_iargs
+ nb_oargs
; i
++) {
1264 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1265 if (dead_temps
[arg
]) {
1266 dead_args
|= (1 << i
);
1268 dead_temps
[arg
] = 0;
1271 s
->op_dead_args
[op_index
] = dead_args
;
1276 case INDEX_op_set_label
:
1278 /* mark end of basic block */
1279 tcg_la_bb_end(s
, dead_temps
);
1281 case INDEX_op_debug_insn_start
:
1282 args
-= def
->nb_args
;
1288 case INDEX_op_discard
:
1290 /* mark the temporary as dead */
1291 dead_temps
[args
[0]] = 1;
1295 /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1297 args
-= def
->nb_args
;
1298 nb_iargs
= def
->nb_iargs
;
1299 nb_oargs
= def
->nb_oargs
;
1301 /* Test if the operation can be removed because all
1302 its outputs are dead. We assume that nb_oargs == 0
1303 implies side effects */
1304 if (!(def
->flags
& TCG_OPF_SIDE_EFFECTS
) && nb_oargs
!= 0) {
1305 for(i
= 0; i
< nb_oargs
; i
++) {
1307 if (!dead_temps
[arg
])
1310 tcg_set_nop(s
, gen_opc_buf
+ op_index
, args
, def
->nb_args
);
1311 #ifdef CONFIG_PROFILER
1317 /* output args are dead */
1319 for(i
= 0; i
< nb_oargs
; i
++) {
1321 if (dead_temps
[arg
]) {
1322 dead_args
|= (1 << i
);
1324 dead_temps
[arg
] = 1;
1327 /* if end of basic block, update */
1328 if (def
->flags
& TCG_OPF_BB_END
) {
1329 tcg_la_bb_end(s
, dead_temps
);
1330 } else if (def
->flags
& TCG_OPF_CALL_CLOBBER
) {
1331 /* globals are live */
1332 memset(dead_temps
, 0, s
->nb_globals
);
1335 /* input args are live */
1336 for(i
= nb_oargs
; i
< nb_oargs
+ nb_iargs
; i
++) {
1338 if (dead_temps
[arg
]) {
1339 dead_args
|= (1 << i
);
1341 dead_temps
[arg
] = 0;
1343 s
->op_dead_args
[op_index
] = dead_args
;
1350 if (args
!= gen_opparam_buf
)
1354 /* dummy liveness analysis */
1355 static void tcg_liveness_analysis(TCGContext
*s
)
1358 nb_ops
= gen_opc_ptr
- gen_opc_buf
;
1360 s
->op_dead_args
= tcg_malloc(nb_ops
* sizeof(uint16_t));
1361 memset(s
->op_dead_args
, 0, nb_ops
* sizeof(uint16_t));
1366 static void dump_regs(TCGContext
*s
)
1372 for(i
= 0; i
< s
->nb_temps
; i
++) {
1374 printf(" %10s: ", tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), i
));
1375 switch(ts
->val_type
) {
1377 printf("%s", tcg_target_reg_names
[ts
->reg
]);
1380 printf("%d(%s)", (int)ts
->mem_offset
, tcg_target_reg_names
[ts
->mem_reg
]);
1382 case TEMP_VAL_CONST
:
1383 printf("$0x%" TCG_PRIlx
, ts
->val
);
1395 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
1396 if (s
->reg_to_temp
[i
] >= 0) {
1398 tcg_target_reg_names
[i
],
1399 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), s
->reg_to_temp
[i
]));
1404 static void check_regs(TCGContext
*s
)
1410 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1411 k
= s
->reg_to_temp
[reg
];
1414 if (ts
->val_type
!= TEMP_VAL_REG
||
1416 printf("Inconsistency for register %s:\n",
1417 tcg_target_reg_names
[reg
]);
1422 for(k
= 0; k
< s
->nb_temps
; k
++) {
1424 if (ts
->val_type
== TEMP_VAL_REG
&&
1426 s
->reg_to_temp
[ts
->reg
] != k
) {
1427 printf("Inconsistency for temp %s:\n",
1428 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), k
));
1430 printf("reg state:\n");
1438 static void temp_allocate_frame(TCGContext
*s
, int temp
)
1441 ts
= &s
->temps
[temp
];
1442 s
->current_frame_offset
= (s
->current_frame_offset
+ sizeof(tcg_target_long
) - 1) & ~(sizeof(tcg_target_long
) - 1);
1443 if (s
->current_frame_offset
+ sizeof(tcg_target_long
) > s
->frame_end
)
1445 ts
->mem_offset
= s
->current_frame_offset
;
1446 ts
->mem_reg
= s
->frame_reg
;
1447 ts
->mem_allocated
= 1;
1448 s
->current_frame_offset
+= sizeof(tcg_target_long
);
1451 /* free register 'reg' by spilling the corresponding temporary if necessary */
1452 static void tcg_reg_free(TCGContext
*s
, int reg
)
1457 temp
= s
->reg_to_temp
[reg
];
1459 ts
= &s
->temps
[temp
];
1460 assert(ts
->val_type
== TEMP_VAL_REG
);
1461 if (!ts
->mem_coherent
) {
1462 if (!ts
->mem_allocated
)
1463 temp_allocate_frame(s
, temp
);
1464 tcg_out_st(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1466 ts
->val_type
= TEMP_VAL_MEM
;
1467 s
->reg_to_temp
[reg
] = -1;
1471 /* Allocate a register belonging to reg1 & ~reg2 */
1472 static int tcg_reg_alloc(TCGContext
*s
, TCGRegSet reg1
, TCGRegSet reg2
)
1477 tcg_regset_andnot(reg_ct
, reg1
, reg2
);
1479 /* first try free registers */
1480 for(i
= 0; i
< ARRAY_SIZE(tcg_target_reg_alloc_order
); i
++) {
1481 reg
= tcg_target_reg_alloc_order
[i
];
1482 if (tcg_regset_test_reg(reg_ct
, reg
) && s
->reg_to_temp
[reg
] == -1)
1486 /* XXX: do better spill choice */
1487 for(i
= 0; i
< ARRAY_SIZE(tcg_target_reg_alloc_order
); i
++) {
1488 reg
= tcg_target_reg_alloc_order
[i
];
1489 if (tcg_regset_test_reg(reg_ct
, reg
)) {
1490 tcg_reg_free(s
, reg
);
1498 /* save a temporary to memory. 'allocated_regs' is used in case a
1499 temporary registers needs to be allocated to store a constant. */
1500 static void temp_save(TCGContext
*s
, int temp
, TCGRegSet allocated_regs
)
1505 ts
= &s
->temps
[temp
];
1506 if (!ts
->fixed_reg
) {
1507 switch(ts
->val_type
) {
1509 tcg_reg_free(s
, ts
->reg
);
1512 ts
->val_type
= TEMP_VAL_MEM
;
1514 case TEMP_VAL_CONST
:
1515 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1517 if (!ts
->mem_allocated
)
1518 temp_allocate_frame(s
, temp
);
1519 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1520 tcg_out_st(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1521 ts
->val_type
= TEMP_VAL_MEM
;
1531 /* save globals to their cannonical location and assume they can be
1532 modified be the following code. 'allocated_regs' is used in case a
1533 temporary registers needs to be allocated to store a constant. */
1534 static void save_globals(TCGContext
*s
, TCGRegSet allocated_regs
)
1538 for(i
= 0; i
< s
->nb_globals
; i
++) {
1539 temp_save(s
, i
, allocated_regs
);
1543 /* at the end of a basic block, we assume all temporaries are dead and
1544 all globals are stored at their canonical location. */
1545 static void tcg_reg_alloc_bb_end(TCGContext
*s
, TCGRegSet allocated_regs
)
1550 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
1552 if (ts
->temp_local
) {
1553 temp_save(s
, i
, allocated_regs
);
1555 if (ts
->val_type
== TEMP_VAL_REG
) {
1556 s
->reg_to_temp
[ts
->reg
] = -1;
1558 ts
->val_type
= TEMP_VAL_DEAD
;
1562 save_globals(s
, allocated_regs
);
1565 #define IS_DEAD_ARG(n) ((dead_args >> (n)) & 1)
1567 static void tcg_reg_alloc_movi(TCGContext
*s
, const TCGArg
*args
)
1570 tcg_target_ulong val
;
1572 ots
= &s
->temps
[args
[0]];
1575 if (ots
->fixed_reg
) {
1576 /* for fixed registers, we do not do any constant
1578 tcg_out_movi(s
, ots
->type
, ots
->reg
, val
);
1580 /* The movi is not explicitly generated here */
1581 if (ots
->val_type
== TEMP_VAL_REG
)
1582 s
->reg_to_temp
[ots
->reg
] = -1;
1583 ots
->val_type
= TEMP_VAL_CONST
;
1588 static void tcg_reg_alloc_mov(TCGContext
*s
, const TCGOpDef
*def
,
1590 unsigned int dead_args
)
1594 const TCGArgConstraint
*arg_ct
;
1596 ots
= &s
->temps
[args
[0]];
1597 ts
= &s
->temps
[args
[1]];
1598 arg_ct
= &def
->args_ct
[0];
1600 /* XXX: always mark arg dead if IS_DEAD_ARG(1) */
1601 if (ts
->val_type
== TEMP_VAL_REG
) {
1602 if (IS_DEAD_ARG(1) && !ts
->fixed_reg
&& !ots
->fixed_reg
) {
1603 /* the mov can be suppressed */
1604 if (ots
->val_type
== TEMP_VAL_REG
)
1605 s
->reg_to_temp
[ots
->reg
] = -1;
1607 s
->reg_to_temp
[reg
] = -1;
1608 ts
->val_type
= TEMP_VAL_DEAD
;
1610 if (ots
->val_type
== TEMP_VAL_REG
) {
1613 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, s
->reserved_regs
);
1615 if (ts
->reg
!= reg
) {
1616 tcg_out_mov(s
, ots
->type
, reg
, ts
->reg
);
1619 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1620 if (ots
->val_type
== TEMP_VAL_REG
) {
1623 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, s
->reserved_regs
);
1625 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1626 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1627 if (ots
->fixed_reg
) {
1629 tcg_out_movi(s
, ots
->type
, reg
, ts
->val
);
1631 /* propagate constant */
1632 if (ots
->val_type
== TEMP_VAL_REG
)
1633 s
->reg_to_temp
[ots
->reg
] = -1;
1634 ots
->val_type
= TEMP_VAL_CONST
;
1641 s
->reg_to_temp
[reg
] = args
[0];
1643 ots
->val_type
= TEMP_VAL_REG
;
1644 ots
->mem_coherent
= 0;
1647 static void tcg_reg_alloc_op(TCGContext
*s
,
1648 const TCGOpDef
*def
, TCGOpcode opc
,
1650 unsigned int dead_args
)
1652 TCGRegSet allocated_regs
;
1653 int i
, k
, nb_iargs
, nb_oargs
, reg
;
1655 const TCGArgConstraint
*arg_ct
;
1657 TCGArg new_args
[TCG_MAX_OP_ARGS
];
1658 int const_args
[TCG_MAX_OP_ARGS
];
1660 nb_oargs
= def
->nb_oargs
;
1661 nb_iargs
= def
->nb_iargs
;
1663 /* copy constants */
1664 memcpy(new_args
+ nb_oargs
+ nb_iargs
,
1665 args
+ nb_oargs
+ nb_iargs
,
1666 sizeof(TCGArg
) * def
->nb_cargs
);
1668 /* satisfy input constraints */
1669 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1670 for(k
= 0; k
< nb_iargs
; k
++) {
1671 i
= def
->sorted_args
[nb_oargs
+ k
];
1673 arg_ct
= &def
->args_ct
[i
];
1674 ts
= &s
->temps
[arg
];
1675 if (ts
->val_type
== TEMP_VAL_MEM
) {
1676 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1677 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1678 ts
->val_type
= TEMP_VAL_REG
;
1680 ts
->mem_coherent
= 1;
1681 s
->reg_to_temp
[reg
] = arg
;
1682 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1683 if (tcg_target_const_match(ts
->val
, arg_ct
)) {
1684 /* constant is OK for instruction */
1686 new_args
[i
] = ts
->val
;
1689 /* need to move to a register */
1690 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1691 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1692 ts
->val_type
= TEMP_VAL_REG
;
1694 ts
->mem_coherent
= 0;
1695 s
->reg_to_temp
[reg
] = arg
;
1698 assert(ts
->val_type
== TEMP_VAL_REG
);
1699 if (arg_ct
->ct
& TCG_CT_IALIAS
) {
1700 if (ts
->fixed_reg
) {
1701 /* if fixed register, we must allocate a new register
1702 if the alias is not the same register */
1703 if (arg
!= args
[arg_ct
->alias_index
])
1704 goto allocate_in_reg
;
1706 /* if the input is aliased to an output and if it is
1707 not dead after the instruction, we must allocate
1708 a new register and move it */
1709 if (!IS_DEAD_ARG(i
)) {
1710 goto allocate_in_reg
;
1715 if (tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1716 /* nothing to do : the constraint is satisfied */
1719 /* allocate a new register matching the constraint
1720 and move the temporary register into it */
1721 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1722 tcg_out_mov(s
, ts
->type
, reg
, ts
->reg
);
1726 tcg_regset_set_reg(allocated_regs
, reg
);
1730 if (def
->flags
& TCG_OPF_BB_END
) {
1731 tcg_reg_alloc_bb_end(s
, allocated_regs
);
1733 /* mark dead temporaries and free the associated registers */
1734 for(i
= nb_oargs
; i
< nb_oargs
+ nb_iargs
; i
++) {
1736 if (IS_DEAD_ARG(i
)) {
1737 ts
= &s
->temps
[arg
];
1738 if (!ts
->fixed_reg
) {
1739 if (ts
->val_type
== TEMP_VAL_REG
)
1740 s
->reg_to_temp
[ts
->reg
] = -1;
1741 ts
->val_type
= TEMP_VAL_DEAD
;
1746 if (def
->flags
& TCG_OPF_CALL_CLOBBER
) {
1747 /* XXX: permit generic clobber register list ? */
1748 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1749 if (tcg_regset_test_reg(tcg_target_call_clobber_regs
, reg
)) {
1750 tcg_reg_free(s
, reg
);
1753 /* XXX: for load/store we could do that only for the slow path
1754 (i.e. when a memory callback is called) */
1756 /* store globals and free associated registers (we assume the insn
1757 can modify any global. */
1758 save_globals(s
, allocated_regs
);
1761 /* satisfy the output constraints */
1762 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1763 for(k
= 0; k
< nb_oargs
; k
++) {
1764 i
= def
->sorted_args
[k
];
1766 arg_ct
= &def
->args_ct
[i
];
1767 ts
= &s
->temps
[arg
];
1768 if (arg_ct
->ct
& TCG_CT_ALIAS
) {
1769 reg
= new_args
[arg_ct
->alias_index
];
1771 /* if fixed register, we try to use it */
1773 if (ts
->fixed_reg
&&
1774 tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1777 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1779 tcg_regset_set_reg(allocated_regs
, reg
);
1780 /* if a fixed register is used, then a move will be done afterwards */
1781 if (!ts
->fixed_reg
) {
1782 if (ts
->val_type
== TEMP_VAL_REG
)
1783 s
->reg_to_temp
[ts
->reg
] = -1;
1784 if (IS_DEAD_ARG(i
)) {
1785 ts
->val_type
= TEMP_VAL_DEAD
;
1787 ts
->val_type
= TEMP_VAL_REG
;
1789 /* temp value is modified, so the value kept in memory is
1790 potentially not the same */
1791 ts
->mem_coherent
= 0;
1792 s
->reg_to_temp
[reg
] = arg
;
1800 /* emit instruction */
1801 tcg_out_op(s
, opc
, new_args
, const_args
);
1803 /* move the outputs in the correct register if needed */
1804 for(i
= 0; i
< nb_oargs
; i
++) {
1805 ts
= &s
->temps
[args
[i
]];
1807 if (ts
->fixed_reg
&& ts
->reg
!= reg
) {
1808 tcg_out_mov(s
, ts
->type
, ts
->reg
, reg
);
1813 #ifdef TCG_TARGET_STACK_GROWSUP
1814 #define STACK_DIR(x) (-(x))
1816 #define STACK_DIR(x) (x)
1819 static int tcg_reg_alloc_call(TCGContext
*s
, const TCGOpDef
*def
,
1820 TCGOpcode opc
, const TCGArg
*args
,
1821 unsigned int dead_args
)
1823 int nb_iargs
, nb_oargs
, flags
, nb_regs
, i
, reg
, nb_params
;
1824 TCGArg arg
, func_arg
;
1826 tcg_target_long stack_offset
, call_stack_size
, func_addr
;
1827 int const_func_arg
, allocate_args
;
1828 TCGRegSet allocated_regs
;
1829 const TCGArgConstraint
*arg_ct
;
1833 nb_oargs
= arg
>> 16;
1834 nb_iargs
= arg
& 0xffff;
1835 nb_params
= nb_iargs
- 1;
1837 flags
= args
[nb_oargs
+ nb_iargs
];
1839 nb_regs
= tcg_target_get_call_iarg_regs_count(flags
);
1840 if (nb_regs
> nb_params
)
1841 nb_regs
= nb_params
;
1843 /* assign stack slots first */
1844 /* XXX: preallocate call stack */
1845 call_stack_size
= (nb_params
- nb_regs
) * sizeof(tcg_target_long
);
1846 call_stack_size
= (call_stack_size
+ TCG_TARGET_STACK_ALIGN
- 1) &
1847 ~(TCG_TARGET_STACK_ALIGN
- 1);
1848 allocate_args
= (call_stack_size
> TCG_STATIC_CALL_ARGS_SIZE
);
1849 if (allocate_args
) {
1850 tcg_out_addi(s
, TCG_REG_CALL_STACK
, -STACK_DIR(call_stack_size
));
1853 stack_offset
= TCG_TARGET_CALL_STACK_OFFSET
;
1854 for(i
= nb_regs
; i
< nb_params
; i
++) {
1855 arg
= args
[nb_oargs
+ i
];
1856 #ifdef TCG_TARGET_STACK_GROWSUP
1857 stack_offset
-= sizeof(tcg_target_long
);
1859 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1860 ts
= &s
->temps
[arg
];
1861 if (ts
->val_type
== TEMP_VAL_REG
) {
1862 tcg_out_st(s
, ts
->type
, ts
->reg
, TCG_REG_CALL_STACK
, stack_offset
);
1863 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1864 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1866 /* XXX: not correct if reading values from the stack */
1867 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1868 tcg_out_st(s
, ts
->type
, reg
, TCG_REG_CALL_STACK
, stack_offset
);
1869 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1870 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1872 /* XXX: sign extend may be needed on some targets */
1873 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1874 tcg_out_st(s
, ts
->type
, reg
, TCG_REG_CALL_STACK
, stack_offset
);
1879 #ifndef TCG_TARGET_STACK_GROWSUP
1880 stack_offset
+= sizeof(tcg_target_long
);
1884 /* assign input registers */
1885 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1886 for(i
= 0; i
< nb_regs
; i
++) {
1887 arg
= args
[nb_oargs
+ i
];
1888 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1889 ts
= &s
->temps
[arg
];
1890 reg
= tcg_target_call_iarg_regs
[i
];
1891 tcg_reg_free(s
, reg
);
1892 if (ts
->val_type
== TEMP_VAL_REG
) {
1893 if (ts
->reg
!= reg
) {
1894 tcg_out_mov(s
, ts
->type
, reg
, ts
->reg
);
1896 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1897 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1898 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1899 /* XXX: sign extend ? */
1900 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1904 tcg_regset_set_reg(allocated_regs
, reg
);
1908 /* assign function address */
1909 func_arg
= args
[nb_oargs
+ nb_iargs
- 1];
1910 arg_ct
= &def
->args_ct
[0];
1911 ts
= &s
->temps
[func_arg
];
1912 func_addr
= ts
->val
;
1914 if (ts
->val_type
== TEMP_VAL_MEM
) {
1915 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1916 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1918 tcg_regset_set_reg(allocated_regs
, reg
);
1919 } else if (ts
->val_type
== TEMP_VAL_REG
) {
1921 if (!tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1922 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1923 tcg_out_mov(s
, ts
->type
, reg
, ts
->reg
);
1926 tcg_regset_set_reg(allocated_regs
, reg
);
1927 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1928 if (tcg_target_const_match(func_addr
, arg_ct
)) {
1930 func_arg
= func_addr
;
1932 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1933 tcg_out_movi(s
, ts
->type
, reg
, func_addr
);
1935 tcg_regset_set_reg(allocated_regs
, reg
);
1942 /* mark dead temporaries and free the associated registers */
1943 for(i
= nb_oargs
; i
< nb_iargs
+ nb_oargs
; i
++) {
1945 if (IS_DEAD_ARG(i
)) {
1946 ts
= &s
->temps
[arg
];
1947 if (!ts
->fixed_reg
) {
1948 if (ts
->val_type
== TEMP_VAL_REG
)
1949 s
->reg_to_temp
[ts
->reg
] = -1;
1950 ts
->val_type
= TEMP_VAL_DEAD
;
1955 /* clobber call registers */
1956 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1957 if (tcg_regset_test_reg(tcg_target_call_clobber_regs
, reg
)) {
1958 tcg_reg_free(s
, reg
);
1962 /* store globals and free associated registers (we assume the call
1963 can modify any global. */
1964 if (!(flags
& TCG_CALL_CONST
)) {
1965 save_globals(s
, allocated_regs
);
1968 tcg_out_op(s
, opc
, &func_arg
, &const_func_arg
);
1970 if (allocate_args
) {
1971 tcg_out_addi(s
, TCG_REG_CALL_STACK
, STACK_DIR(call_stack_size
));
1974 /* assign output registers and emit moves if needed */
1975 for(i
= 0; i
< nb_oargs
; i
++) {
1977 ts
= &s
->temps
[arg
];
1978 reg
= tcg_target_call_oarg_regs
[i
];
1979 assert(s
->reg_to_temp
[reg
] == -1);
1980 if (ts
->fixed_reg
) {
1981 if (ts
->reg
!= reg
) {
1982 tcg_out_mov(s
, ts
->type
, ts
->reg
, reg
);
1985 if (ts
->val_type
== TEMP_VAL_REG
)
1986 s
->reg_to_temp
[ts
->reg
] = -1;
1987 if (IS_DEAD_ARG(i
)) {
1988 ts
->val_type
= TEMP_VAL_DEAD
;
1990 ts
->val_type
= TEMP_VAL_REG
;
1992 ts
->mem_coherent
= 0;
1993 s
->reg_to_temp
[reg
] = arg
;
1998 return nb_iargs
+ nb_oargs
+ def
->nb_cargs
+ 1;
2001 #ifdef CONFIG_PROFILER
2003 static int64_t tcg_table_op_count
[NB_OPS
];
2005 static void dump_op_count(void)
2009 f
= fopen("/tmp/op.log", "w");
2010 for(i
= INDEX_op_end
; i
< NB_OPS
; i
++) {
2011 fprintf(f
, "%s %" PRId64
"\n", tcg_op_defs
[i
].name
, tcg_table_op_count
[i
]);
2018 static inline int tcg_gen_code_common(TCGContext
*s
, uint8_t *gen_code_buf
,
2023 const TCGOpDef
*def
;
2024 unsigned int dead_args
;
2028 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP
))) {
2030 tcg_dump_ops(s
, logfile
);
2035 #ifdef CONFIG_PROFILER
2036 s
->la_time
-= profile_getclock();
2038 tcg_liveness_analysis(s
);
2039 #ifdef CONFIG_PROFILER
2040 s
->la_time
+= profile_getclock();
2044 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT
))) {
2045 qemu_log("OP after liveness analysis:\n");
2046 tcg_dump_ops(s
, logfile
);
2051 tcg_reg_alloc_start(s
);
2053 s
->code_buf
= gen_code_buf
;
2054 s
->code_ptr
= gen_code_buf
;
2056 args
= gen_opparam_buf
;
2060 opc
= gen_opc_buf
[op_index
];
2061 #ifdef CONFIG_PROFILER
2062 tcg_table_op_count
[opc
]++;
2064 def
= &tcg_op_defs
[opc
];
2066 printf("%s: %d %d %d\n", def
->name
,
2067 def
->nb_oargs
, def
->nb_iargs
, def
->nb_cargs
);
2071 case INDEX_op_mov_i32
:
2072 #if TCG_TARGET_REG_BITS == 64
2073 case INDEX_op_mov_i64
:
2075 dead_args
= s
->op_dead_args
[op_index
];
2076 tcg_reg_alloc_mov(s
, def
, args
, dead_args
);
2078 case INDEX_op_movi_i32
:
2079 #if TCG_TARGET_REG_BITS == 64
2080 case INDEX_op_movi_i64
:
2082 tcg_reg_alloc_movi(s
, args
);
2084 case INDEX_op_debug_insn_start
:
2085 /* debug instruction */
2095 case INDEX_op_discard
:
2098 ts
= &s
->temps
[args
[0]];
2099 /* mark the temporary as dead */
2100 if (!ts
->fixed_reg
) {
2101 if (ts
->val_type
== TEMP_VAL_REG
)
2102 s
->reg_to_temp
[ts
->reg
] = -1;
2103 ts
->val_type
= TEMP_VAL_DEAD
;
2107 case INDEX_op_set_label
:
2108 tcg_reg_alloc_bb_end(s
, s
->reserved_regs
);
2109 tcg_out_label(s
, args
[0], (long)s
->code_ptr
);
2112 dead_args
= s
->op_dead_args
[op_index
];
2113 args
+= tcg_reg_alloc_call(s
, def
, opc
, args
, dead_args
);
2118 /* Note: in order to speed up the code, it would be much
2119 faster to have specialized register allocator functions for
2120 some common argument patterns */
2121 dead_args
= s
->op_dead_args
[op_index
];
2122 tcg_reg_alloc_op(s
, def
, opc
, args
, dead_args
);
2125 args
+= def
->nb_args
;
2127 if (search_pc
>= 0 && search_pc
< s
->code_ptr
- gen_code_buf
) {
2139 int tcg_gen_code(TCGContext
*s
, uint8_t *gen_code_buf
)
2141 #ifdef CONFIG_PROFILER
2144 n
= (gen_opc_ptr
- gen_opc_buf
);
2146 if (n
> s
->op_count_max
)
2147 s
->op_count_max
= n
;
2149 s
->temp_count
+= s
->nb_temps
;
2150 if (s
->nb_temps
> s
->temp_count_max
)
2151 s
->temp_count_max
= s
->nb_temps
;
2155 tcg_gen_code_common(s
, gen_code_buf
, -1);
2157 /* flush instruction cache */
2158 flush_icache_range((unsigned long)gen_code_buf
,
2159 (unsigned long)s
->code_ptr
);
2160 return s
->code_ptr
- gen_code_buf
;
2163 /* Return the index of the micro operation such as the pc after is <
2164 offset bytes from the start of the TB. The contents of gen_code_buf must
2165 not be changed, though writing the same values is ok.
2166 Return -1 if not found. */
2167 int tcg_gen_code_search_pc(TCGContext
*s
, uint8_t *gen_code_buf
, long offset
)
2169 return tcg_gen_code_common(s
, gen_code_buf
, offset
);
2172 #ifdef CONFIG_PROFILER
2173 void tcg_dump_info(FILE *f
, fprintf_function cpu_fprintf
)
2175 TCGContext
*s
= &tcg_ctx
;
2178 tot
= s
->interm_time
+ s
->code_time
;
2179 cpu_fprintf(f
, "JIT cycles %" PRId64
" (%0.3f s at 2.4 GHz)\n",
2181 cpu_fprintf(f
, "translated TBs %" PRId64
" (aborted=%" PRId64
" %0.1f%%)\n",
2183 s
->tb_count1
- s
->tb_count
,
2184 s
->tb_count1
? (double)(s
->tb_count1
- s
->tb_count
) / s
->tb_count1
* 100.0 : 0);
2185 cpu_fprintf(f
, "avg ops/TB %0.1f max=%d\n",
2186 s
->tb_count
? (double)s
->op_count
/ s
->tb_count
: 0, s
->op_count_max
);
2187 cpu_fprintf(f
, "deleted ops/TB %0.2f\n",
2189 (double)s
->del_op_count
/ s
->tb_count
: 0);
2190 cpu_fprintf(f
, "avg temps/TB %0.2f max=%d\n",
2192 (double)s
->temp_count
/ s
->tb_count
: 0,
2195 cpu_fprintf(f
, "cycles/op %0.1f\n",
2196 s
->op_count
? (double)tot
/ s
->op_count
: 0);
2197 cpu_fprintf(f
, "cycles/in byte %0.1f\n",
2198 s
->code_in_len
? (double)tot
/ s
->code_in_len
: 0);
2199 cpu_fprintf(f
, "cycles/out byte %0.1f\n",
2200 s
->code_out_len
? (double)tot
/ s
->code_out_len
: 0);
2203 cpu_fprintf(f
, " gen_interm time %0.1f%%\n",
2204 (double)s
->interm_time
/ tot
* 100.0);
2205 cpu_fprintf(f
, " gen_code time %0.1f%%\n",
2206 (double)s
->code_time
/ tot
* 100.0);
2207 cpu_fprintf(f
, "liveness/code time %0.1f%%\n",
2208 (double)s
->la_time
/ (s
->code_time
? s
->code_time
: 1) * 100.0);
2209 cpu_fprintf(f
, "cpu_restore count %" PRId64
"\n",
2211 cpu_fprintf(f
, " avg cycles %0.1f\n",
2212 s
->restore_count
? (double)s
->restore_time
/ s
->restore_count
: 0);
2217 void tcg_dump_info(FILE *f
, fprintf_function cpu_fprintf
)
2219 cpu_fprintf(f
, "[TCG profiler not compiled]\n");