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
62 #if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
63 #error GUEST_BASE not supported on this host.
66 static void patch_reloc(uint8_t *code_ptr
, int type
,
67 tcg_target_long value
, tcg_target_long addend
);
69 static TCGOpDef tcg_op_defs
[] = {
70 #define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size },
71 #define DEF2(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags, 0 },
77 static TCGRegSet tcg_target_available_regs
[2];
78 static TCGRegSet tcg_target_call_clobber_regs
;
80 /* XXX: move that inside the context */
81 uint16_t *gen_opc_ptr
;
82 TCGArg
*gen_opparam_ptr
;
84 static inline void tcg_out8(TCGContext
*s
, uint8_t v
)
89 static inline void tcg_out16(TCGContext
*s
, uint16_t v
)
91 *(uint16_t *)s
->code_ptr
= v
;
95 static inline void tcg_out32(TCGContext
*s
, uint32_t v
)
97 *(uint32_t *)s
->code_ptr
= v
;
101 /* label relocation processing */
103 void tcg_out_reloc(TCGContext
*s
, uint8_t *code_ptr
, int type
,
104 int label_index
, long addend
)
109 l
= &s
->labels
[label_index
];
111 /* FIXME: This may break relocations on RISC targets that
112 modify instruction fields in place. The caller may not have
113 written the initial value. */
114 patch_reloc(code_ptr
, type
, l
->u
.value
, addend
);
116 /* add a new relocation entry */
117 r
= tcg_malloc(sizeof(TCGRelocation
));
121 r
->next
= l
->u
.first_reloc
;
122 l
->u
.first_reloc
= r
;
126 static void tcg_out_label(TCGContext
*s
, int label_index
,
127 tcg_target_long value
)
132 l
= &s
->labels
[label_index
];
135 r
= l
->u
.first_reloc
;
137 patch_reloc(r
->ptr
, r
->type
, value
, r
->addend
);
144 int gen_new_label(void)
146 TCGContext
*s
= &tcg_ctx
;
150 if (s
->nb_labels
>= TCG_MAX_LABELS
)
152 idx
= s
->nb_labels
++;
155 l
->u
.first_reloc
= NULL
;
159 #include "tcg-target.c"
161 /* pool based memory allocation */
162 void *tcg_malloc_internal(TCGContext
*s
, int size
)
167 if (size
> TCG_POOL_CHUNK_SIZE
) {
168 /* big malloc: insert a new pool (XXX: could optimize) */
169 p
= qemu_malloc(sizeof(TCGPool
) + size
);
172 s
->pool_current
->next
= p
;
175 p
->next
= s
->pool_current
;
185 pool_size
= TCG_POOL_CHUNK_SIZE
;
186 p
= qemu_malloc(sizeof(TCGPool
) + pool_size
);
190 s
->pool_current
->next
= p
;
199 s
->pool_cur
= p
->data
+ size
;
200 s
->pool_end
= p
->data
+ p
->size
;
204 void tcg_pool_reset(TCGContext
*s
)
206 s
->pool_cur
= s
->pool_end
= NULL
;
207 s
->pool_current
= NULL
;
210 void tcg_context_init(TCGContext
*s
)
212 int op
, total_args
, n
;
214 TCGArgConstraint
*args_ct
;
217 memset(s
, 0, sizeof(*s
));
218 s
->temps
= s
->static_temps
;
221 /* Count total number of arguments and allocate the corresponding
224 for(op
= 0; op
< NB_OPS
; op
++) {
225 def
= &tcg_op_defs
[op
];
226 n
= def
->nb_iargs
+ def
->nb_oargs
;
230 args_ct
= qemu_malloc(sizeof(TCGArgConstraint
) * total_args
);
231 sorted_args
= qemu_malloc(sizeof(int) * total_args
);
233 for(op
= 0; op
< NB_OPS
; op
++) {
234 def
= &tcg_op_defs
[op
];
235 def
->args_ct
= args_ct
;
236 def
->sorted_args
= sorted_args
;
237 n
= def
->nb_iargs
+ def
->nb_oargs
;
244 /* init global prologue and epilogue */
245 s
->code_buf
= code_gen_prologue
;
246 s
->code_ptr
= s
->code_buf
;
247 tcg_target_qemu_prologue(s
);
248 flush_icache_range((unsigned long)s
->code_buf
,
249 (unsigned long)s
->code_ptr
);
252 void tcg_set_frame(TCGContext
*s
, int reg
,
253 tcg_target_long start
, tcg_target_long size
)
255 s
->frame_start
= start
;
256 s
->frame_end
= start
+ size
;
260 void tcg_func_start(TCGContext
*s
)
264 s
->nb_temps
= s
->nb_globals
;
265 for(i
= 0; i
< (TCG_TYPE_COUNT
* 2); i
++)
266 s
->first_free_temp
[i
] = -1;
267 s
->labels
= tcg_malloc(sizeof(TCGLabel
) * TCG_MAX_LABELS
);
269 s
->current_frame_offset
= s
->frame_start
;
271 gen_opc_ptr
= gen_opc_buf
;
272 gen_opparam_ptr
= gen_opparam_buf
;
275 static inline void tcg_temp_alloc(TCGContext
*s
, int n
)
277 if (n
> TCG_MAX_TEMPS
)
281 static inline int tcg_global_reg_new_internal(TCGType type
, int reg
,
284 TCGContext
*s
= &tcg_ctx
;
288 #if TCG_TARGET_REG_BITS == 32
289 if (type
!= TCG_TYPE_I32
)
292 if (tcg_regset_test_reg(s
->reserved_regs
, reg
))
295 tcg_temp_alloc(s
, s
->nb_globals
+ 1);
296 ts
= &s
->temps
[s
->nb_globals
];
297 ts
->base_type
= type
;
303 tcg_regset_set_reg(s
->reserved_regs
, reg
);
307 TCGv_i32
tcg_global_reg_new_i32(int reg
, const char *name
)
311 idx
= tcg_global_reg_new_internal(TCG_TYPE_I32
, reg
, name
);
312 return MAKE_TCGV_I32(idx
);
315 TCGv_i64
tcg_global_reg_new_i64(int reg
, const char *name
)
319 idx
= tcg_global_reg_new_internal(TCG_TYPE_I64
, reg
, name
);
320 return MAKE_TCGV_I64(idx
);
323 static inline int tcg_global_mem_new_internal(TCGType type
, int reg
,
324 tcg_target_long offset
,
327 TCGContext
*s
= &tcg_ctx
;
332 #if TCG_TARGET_REG_BITS == 32
333 if (type
== TCG_TYPE_I64
) {
335 tcg_temp_alloc(s
, s
->nb_globals
+ 2);
336 ts
= &s
->temps
[s
->nb_globals
];
337 ts
->base_type
= type
;
338 ts
->type
= TCG_TYPE_I32
;
340 ts
->mem_allocated
= 1;
342 #ifdef TCG_TARGET_WORDS_BIGENDIAN
343 ts
->mem_offset
= offset
+ 4;
345 ts
->mem_offset
= offset
;
347 pstrcpy(buf
, sizeof(buf
), name
);
348 pstrcat(buf
, sizeof(buf
), "_0");
349 ts
->name
= strdup(buf
);
352 ts
->base_type
= type
;
353 ts
->type
= TCG_TYPE_I32
;
355 ts
->mem_allocated
= 1;
357 #ifdef TCG_TARGET_WORDS_BIGENDIAN
358 ts
->mem_offset
= offset
;
360 ts
->mem_offset
= offset
+ 4;
362 pstrcpy(buf
, sizeof(buf
), name
);
363 pstrcat(buf
, sizeof(buf
), "_1");
364 ts
->name
= strdup(buf
);
370 tcg_temp_alloc(s
, s
->nb_globals
+ 1);
371 ts
= &s
->temps
[s
->nb_globals
];
372 ts
->base_type
= type
;
375 ts
->mem_allocated
= 1;
377 ts
->mem_offset
= offset
;
384 TCGv_i32
tcg_global_mem_new_i32(int reg
, tcg_target_long offset
,
389 idx
= tcg_global_mem_new_internal(TCG_TYPE_I32
, reg
, offset
, name
);
390 return MAKE_TCGV_I32(idx
);
393 TCGv_i64
tcg_global_mem_new_i64(int reg
, tcg_target_long offset
,
398 idx
= tcg_global_mem_new_internal(TCG_TYPE_I64
, reg
, offset
, name
);
399 return MAKE_TCGV_I64(idx
);
402 static inline int tcg_temp_new_internal(TCGType type
, int temp_local
)
404 TCGContext
*s
= &tcg_ctx
;
411 idx
= s
->first_free_temp
[k
];
413 /* There is already an available temp with the
416 s
->first_free_temp
[k
] = ts
->next_free_temp
;
417 ts
->temp_allocated
= 1;
418 assert(ts
->temp_local
== temp_local
);
421 #if TCG_TARGET_REG_BITS == 32
422 if (type
== TCG_TYPE_I64
) {
423 tcg_temp_alloc(s
, s
->nb_temps
+ 2);
424 ts
= &s
->temps
[s
->nb_temps
];
425 ts
->base_type
= type
;
426 ts
->type
= TCG_TYPE_I32
;
427 ts
->temp_allocated
= 1;
428 ts
->temp_local
= temp_local
;
431 ts
->base_type
= TCG_TYPE_I32
;
432 ts
->type
= TCG_TYPE_I32
;
433 ts
->temp_allocated
= 1;
434 ts
->temp_local
= temp_local
;
440 tcg_temp_alloc(s
, s
->nb_temps
+ 1);
441 ts
= &s
->temps
[s
->nb_temps
];
442 ts
->base_type
= type
;
444 ts
->temp_allocated
= 1;
445 ts
->temp_local
= temp_local
;
453 TCGv_i32
tcg_temp_new_internal_i32(int temp_local
)
457 idx
= tcg_temp_new_internal(TCG_TYPE_I32
, temp_local
);
458 return MAKE_TCGV_I32(idx
);
461 TCGv_i64
tcg_temp_new_internal_i64(int temp_local
)
465 idx
= tcg_temp_new_internal(TCG_TYPE_I64
, temp_local
);
466 return MAKE_TCGV_I64(idx
);
469 static inline void tcg_temp_free_internal(int idx
)
471 TCGContext
*s
= &tcg_ctx
;
475 assert(idx
>= s
->nb_globals
&& idx
< s
->nb_temps
);
477 assert(ts
->temp_allocated
!= 0);
478 ts
->temp_allocated
= 0;
482 ts
->next_free_temp
= s
->first_free_temp
[k
];
483 s
->first_free_temp
[k
] = idx
;
486 void tcg_temp_free_i32(TCGv_i32 arg
)
488 tcg_temp_free_internal(GET_TCGV_I32(arg
));
491 void tcg_temp_free_i64(TCGv_i64 arg
)
493 tcg_temp_free_internal(GET_TCGV_I64(arg
));
496 TCGv_i32
tcg_const_i32(int32_t val
)
499 t0
= tcg_temp_new_i32();
500 tcg_gen_movi_i32(t0
, val
);
504 TCGv_i64
tcg_const_i64(int64_t val
)
507 t0
= tcg_temp_new_i64();
508 tcg_gen_movi_i64(t0
, val
);
512 TCGv_i32
tcg_const_local_i32(int32_t val
)
515 t0
= tcg_temp_local_new_i32();
516 tcg_gen_movi_i32(t0
, val
);
520 TCGv_i64
tcg_const_local_i64(int64_t val
)
523 t0
= tcg_temp_local_new_i64();
524 tcg_gen_movi_i64(t0
, val
);
528 void tcg_register_helper(void *func
, const char *name
)
530 TCGContext
*s
= &tcg_ctx
;
532 if ((s
->nb_helpers
+ 1) > s
->allocated_helpers
) {
533 n
= s
->allocated_helpers
;
539 s
->helpers
= realloc(s
->helpers
, n
* sizeof(TCGHelperInfo
));
540 s
->allocated_helpers
= n
;
542 s
->helpers
[s
->nb_helpers
].func
= (tcg_target_ulong
)func
;
543 s
->helpers
[s
->nb_helpers
].name
= name
;
547 /* Note: we convert the 64 bit args to 32 bit and do some alignment
548 and endian swap. Maybe it would be better to do the alignment
549 and endian swap in tcg_reg_alloc_call(). */
550 void tcg_gen_callN(TCGContext
*s
, TCGv_ptr func
, unsigned int flags
,
551 int sizemask
, TCGArg ret
, int nargs
, TCGArg
*args
)
553 #ifdef TCG_TARGET_I386
560 *gen_opc_ptr
++ = INDEX_op_call
;
561 nparam
= gen_opparam_ptr
++;
562 #ifdef TCG_TARGET_I386
563 call_type
= (flags
& TCG_CALL_TYPE_MASK
);
565 if (ret
!= TCG_CALL_DUMMY_ARG
) {
566 #if TCG_TARGET_REG_BITS < 64
568 #ifdef TCG_TARGET_WORDS_BIGENDIAN
569 *gen_opparam_ptr
++ = ret
+ 1;
570 *gen_opparam_ptr
++ = ret
;
572 *gen_opparam_ptr
++ = ret
;
573 *gen_opparam_ptr
++ = ret
+ 1;
579 *gen_opparam_ptr
++ = ret
;
586 for (i
= 0; i
< nargs
; i
++) {
587 #if TCG_TARGET_REG_BITS < 64
588 if (sizemask
& (2 << i
)) {
589 #ifdef TCG_TARGET_I386
590 /* REGPARM case: if the third parameter is 64 bit, it is
591 allocated on the stack */
592 if (i
== 2 && call_type
== TCG_CALL_TYPE_REGPARM
) {
593 call_type
= TCG_CALL_TYPE_REGPARM_2
;
594 flags
= (flags
& ~TCG_CALL_TYPE_MASK
) | call_type
;
597 #ifdef TCG_TARGET_CALL_ALIGN_ARGS
598 /* some targets want aligned 64 bit args */
600 *gen_opparam_ptr
++ = TCG_CALL_DUMMY_ARG
;
604 /* If stack grows up, then we will be placing successive
605 arguments at lower addresses, which means we need to
606 reverse the order compared to how we would normally
607 treat either big or little-endian. For those arguments
608 that will wind up in registers, this still works for
609 HPPA (the only current STACK_GROWSUP target) since the
610 argument registers are *also* allocated in decreasing
611 order. If another such target is added, this logic may
612 have to get more complicated to differentiate between
613 stack arguments and register arguments. */
614 #if defined(TCG_TARGET_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
615 *gen_opparam_ptr
++ = args
[i
] + 1;
616 *gen_opparam_ptr
++ = args
[i
];
618 *gen_opparam_ptr
++ = args
[i
];
619 *gen_opparam_ptr
++ = args
[i
] + 1;
625 *gen_opparam_ptr
++ = args
[i
];
629 *gen_opparam_ptr
++ = GET_TCGV_PTR(func
);
631 *gen_opparam_ptr
++ = flags
;
633 *nparam
= (nb_rets
<< 16) | (real_args
+ 1);
635 /* total parameters, needed to go backward in the instruction stream */
636 *gen_opparam_ptr
++ = 1 + nb_rets
+ real_args
+ 3;
639 #if TCG_TARGET_REG_BITS == 32
640 void tcg_gen_shifti_i64(TCGv_i64 ret
, TCGv_i64 arg1
,
641 int c
, int right
, int arith
)
644 tcg_gen_mov_i32(TCGV_LOW(ret
), TCGV_LOW(arg1
));
645 tcg_gen_mov_i32(TCGV_HIGH(ret
), TCGV_HIGH(arg1
));
646 } else if (c
>= 32) {
650 tcg_gen_sari_i32(TCGV_LOW(ret
), TCGV_HIGH(arg1
), c
);
651 tcg_gen_sari_i32(TCGV_HIGH(ret
), TCGV_HIGH(arg1
), 31);
653 tcg_gen_shri_i32(TCGV_LOW(ret
), TCGV_HIGH(arg1
), c
);
654 tcg_gen_movi_i32(TCGV_HIGH(ret
), 0);
657 tcg_gen_shli_i32(TCGV_HIGH(ret
), TCGV_LOW(arg1
), c
);
658 tcg_gen_movi_i32(TCGV_LOW(ret
), 0);
663 t0
= tcg_temp_new_i32();
664 t1
= tcg_temp_new_i32();
666 tcg_gen_shli_i32(t0
, TCGV_HIGH(arg1
), 32 - c
);
668 tcg_gen_sari_i32(t1
, TCGV_HIGH(arg1
), c
);
670 tcg_gen_shri_i32(t1
, TCGV_HIGH(arg1
), c
);
671 tcg_gen_shri_i32(TCGV_LOW(ret
), TCGV_LOW(arg1
), c
);
672 tcg_gen_or_i32(TCGV_LOW(ret
), TCGV_LOW(ret
), t0
);
673 tcg_gen_mov_i32(TCGV_HIGH(ret
), t1
);
675 tcg_gen_shri_i32(t0
, TCGV_LOW(arg1
), 32 - c
);
676 /* Note: ret can be the same as arg1, so we use t1 */
677 tcg_gen_shli_i32(t1
, TCGV_LOW(arg1
), c
);
678 tcg_gen_shli_i32(TCGV_HIGH(ret
), TCGV_HIGH(arg1
), c
);
679 tcg_gen_or_i32(TCGV_HIGH(ret
), TCGV_HIGH(ret
), t0
);
680 tcg_gen_mov_i32(TCGV_LOW(ret
), t1
);
682 tcg_temp_free_i32(t0
);
683 tcg_temp_free_i32(t1
);
689 static void tcg_reg_alloc_start(TCGContext
*s
)
693 for(i
= 0; i
< s
->nb_globals
; i
++) {
696 ts
->val_type
= TEMP_VAL_REG
;
698 ts
->val_type
= TEMP_VAL_MEM
;
701 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
703 ts
->val_type
= TEMP_VAL_DEAD
;
704 ts
->mem_allocated
= 0;
707 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
708 s
->reg_to_temp
[i
] = -1;
712 static char *tcg_get_arg_str_idx(TCGContext
*s
, char *buf
, int buf_size
,
718 if (idx
< s
->nb_globals
) {
719 pstrcpy(buf
, buf_size
, ts
->name
);
722 snprintf(buf
, buf_size
, "loc%d", idx
- s
->nb_globals
);
724 snprintf(buf
, buf_size
, "tmp%d", idx
- s
->nb_globals
);
729 char *tcg_get_arg_str_i32(TCGContext
*s
, char *buf
, int buf_size
, TCGv_i32 arg
)
731 return tcg_get_arg_str_idx(s
, buf
, buf_size
, GET_TCGV_I32(arg
));
734 char *tcg_get_arg_str_i64(TCGContext
*s
, char *buf
, int buf_size
, TCGv_i64 arg
)
736 return tcg_get_arg_str_idx(s
, buf
, buf_size
, GET_TCGV_I64(arg
));
739 static int helper_cmp(const void *p1
, const void *p2
)
741 const TCGHelperInfo
*th1
= p1
;
742 const TCGHelperInfo
*th2
= p2
;
743 if (th1
->func
< th2
->func
)
745 else if (th1
->func
== th2
->func
)
751 /* find helper definition (Note: A hash table would be better) */
752 static TCGHelperInfo
*tcg_find_helper(TCGContext
*s
, tcg_target_ulong val
)
758 if (unlikely(!s
->helpers_sorted
)) {
759 qsort(s
->helpers
, s
->nb_helpers
, sizeof(TCGHelperInfo
),
761 s
->helpers_sorted
= 1;
766 m_max
= s
->nb_helpers
- 1;
767 while (m_min
<= m_max
) {
768 m
= (m_min
+ m_max
) >> 1;
782 static const char * const cond_name
[] =
784 [TCG_COND_EQ
] = "eq",
785 [TCG_COND_NE
] = "ne",
786 [TCG_COND_LT
] = "lt",
787 [TCG_COND_GE
] = "ge",
788 [TCG_COND_LE
] = "le",
789 [TCG_COND_GT
] = "gt",
790 [TCG_COND_LTU
] = "ltu",
791 [TCG_COND_GEU
] = "geu",
792 [TCG_COND_LEU
] = "leu",
793 [TCG_COND_GTU
] = "gtu"
796 void tcg_dump_ops(TCGContext
*s
, FILE *outfile
)
798 const uint16_t *opc_ptr
;
802 int i
, k
, nb_oargs
, nb_iargs
, nb_cargs
, first_insn
;
807 opc_ptr
= gen_opc_buf
;
808 args
= gen_opparam_buf
;
809 while (opc_ptr
< gen_opc_ptr
) {
811 def
= &tcg_op_defs
[c
];
812 if (c
== INDEX_op_debug_insn_start
) {
814 #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
815 pc
= ((uint64_t)args
[1] << 32) | args
[0];
820 fprintf(outfile
, "\n");
821 fprintf(outfile
, " ---- 0x%" PRIx64
, pc
);
823 nb_oargs
= def
->nb_oargs
;
824 nb_iargs
= def
->nb_iargs
;
825 nb_cargs
= def
->nb_cargs
;
826 } else if (c
== INDEX_op_call
) {
829 /* variable number of arguments */
831 nb_oargs
= arg
>> 16;
832 nb_iargs
= arg
& 0xffff;
833 nb_cargs
= def
->nb_cargs
;
835 fprintf(outfile
, " %s ", def
->name
);
838 fprintf(outfile
, "%s",
839 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[nb_oargs
+ nb_iargs
- 1]));
841 fprintf(outfile
, ",$0x%" TCG_PRIlx
,
842 args
[nb_oargs
+ nb_iargs
]);
844 fprintf(outfile
, ",$%d", nb_oargs
);
845 for(i
= 0; i
< nb_oargs
; i
++) {
846 fprintf(outfile
, ",");
847 fprintf(outfile
, "%s",
848 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[i
]));
850 for(i
= 0; i
< (nb_iargs
- 1); i
++) {
851 fprintf(outfile
, ",");
852 if (args
[nb_oargs
+ i
] == TCG_CALL_DUMMY_ARG
) {
853 fprintf(outfile
, "<dummy>");
855 fprintf(outfile
, "%s",
856 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[nb_oargs
+ i
]));
859 } else if (c
== INDEX_op_movi_i32
860 #if TCG_TARGET_REG_BITS == 64
861 || c
== INDEX_op_movi_i64
864 tcg_target_ulong val
;
867 nb_oargs
= def
->nb_oargs
;
868 nb_iargs
= def
->nb_iargs
;
869 nb_cargs
= def
->nb_cargs
;
870 fprintf(outfile
, " %s %s,$", def
->name
,
871 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[0]));
873 th
= tcg_find_helper(s
, val
);
875 fprintf(outfile
, "%s", th
->name
);
877 if (c
== INDEX_op_movi_i32
)
878 fprintf(outfile
, "0x%x", (uint32_t)val
);
880 fprintf(outfile
, "0x%" PRIx64
, (uint64_t)val
);
883 fprintf(outfile
, " %s ", def
->name
);
884 if (c
== INDEX_op_nopn
) {
885 /* variable number of arguments */
890 nb_oargs
= def
->nb_oargs
;
891 nb_iargs
= def
->nb_iargs
;
892 nb_cargs
= def
->nb_cargs
;
896 for(i
= 0; i
< nb_oargs
; i
++) {
898 fprintf(outfile
, ",");
899 fprintf(outfile
, "%s",
900 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[k
++]));
902 for(i
= 0; i
< nb_iargs
; i
++) {
904 fprintf(outfile
, ",");
905 fprintf(outfile
, "%s",
906 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[k
++]));
909 case INDEX_op_brcond_i32
:
910 #if TCG_TARGET_REG_BITS == 32
911 case INDEX_op_brcond2_i32
:
912 #elif TCG_TARGET_REG_BITS == 64
913 case INDEX_op_brcond_i64
:
915 case INDEX_op_setcond_i32
:
916 #if TCG_TARGET_REG_BITS == 32
917 case INDEX_op_setcond2_i32
:
918 #elif TCG_TARGET_REG_BITS == 64
919 case INDEX_op_setcond_i64
:
921 if (args
[k
] < ARRAY_SIZE(cond_name
) && cond_name
[args
[k
]])
922 fprintf(outfile
, ",%s", cond_name
[args
[k
++]]);
924 fprintf(outfile
, ",$0x%" TCG_PRIlx
, args
[k
++]);
931 for(; i
< nb_cargs
; i
++) {
933 fprintf(outfile
, ",");
935 fprintf(outfile
, "$0x%" TCG_PRIlx
, arg
);
938 fprintf(outfile
, "\n");
939 args
+= nb_iargs
+ nb_oargs
+ nb_cargs
;
943 /* we give more priority to constraints with less registers */
944 static int get_constraint_priority(const TCGOpDef
*def
, int k
)
946 const TCGArgConstraint
*arg_ct
;
949 arg_ct
= &def
->args_ct
[k
];
950 if (arg_ct
->ct
& TCG_CT_ALIAS
) {
951 /* an alias is equivalent to a single register */
954 if (!(arg_ct
->ct
& TCG_CT_REG
))
957 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
958 if (tcg_regset_test_reg(arg_ct
->u
.regs
, i
))
962 return TCG_TARGET_NB_REGS
- n
+ 1;
965 /* sort from highest priority to lowest */
966 static void sort_constraints(TCGOpDef
*def
, int start
, int n
)
968 int i
, j
, p1
, p2
, tmp
;
970 for(i
= 0; i
< n
; i
++)
971 def
->sorted_args
[start
+ i
] = start
+ i
;
974 for(i
= 0; i
< n
- 1; i
++) {
975 for(j
= i
+ 1; j
< n
; j
++) {
976 p1
= get_constraint_priority(def
, def
->sorted_args
[start
+ i
]);
977 p2
= get_constraint_priority(def
, def
->sorted_args
[start
+ j
]);
979 tmp
= def
->sorted_args
[start
+ i
];
980 def
->sorted_args
[start
+ i
] = def
->sorted_args
[start
+ j
];
981 def
->sorted_args
[start
+ j
] = tmp
;
987 void tcg_add_target_add_op_defs(const TCGTargetOpDef
*tdefs
)
995 if (tdefs
->op
== (TCGOpcode
)-1)
998 assert(op
>= 0 && op
< NB_OPS
);
999 def
= &tcg_op_defs
[op
];
1000 #if defined(CONFIG_DEBUG_TCG)
1001 /* Duplicate entry in op definitions? */
1005 nb_args
= def
->nb_iargs
+ def
->nb_oargs
;
1006 for(i
= 0; i
< nb_args
; i
++) {
1007 ct_str
= tdefs
->args_ct_str
[i
];
1008 /* Incomplete TCGTargetOpDef entry? */
1009 assert(ct_str
!= NULL
);
1010 tcg_regset_clear(def
->args_ct
[i
].u
.regs
);
1011 def
->args_ct
[i
].ct
= 0;
1012 if (ct_str
[0] >= '0' && ct_str
[0] <= '9') {
1014 oarg
= ct_str
[0] - '0';
1015 assert(oarg
< def
->nb_oargs
);
1016 assert(def
->args_ct
[oarg
].ct
& TCG_CT_REG
);
1017 /* TCG_CT_ALIAS is for the output arguments. The input
1018 argument is tagged with TCG_CT_IALIAS. */
1019 def
->args_ct
[i
] = def
->args_ct
[oarg
];
1020 def
->args_ct
[oarg
].ct
= TCG_CT_ALIAS
;
1021 def
->args_ct
[oarg
].alias_index
= i
;
1022 def
->args_ct
[i
].ct
|= TCG_CT_IALIAS
;
1023 def
->args_ct
[i
].alias_index
= oarg
;
1026 if (*ct_str
== '\0')
1030 def
->args_ct
[i
].ct
|= TCG_CT_CONST
;
1034 if (target_parse_constraint(&def
->args_ct
[i
], &ct_str
) < 0) {
1035 fprintf(stderr
, "Invalid constraint '%s' for arg %d of operation '%s'\n",
1036 ct_str
, i
, def
->name
);
1044 /* TCGTargetOpDef entry with too much information? */
1045 assert(i
== TCG_MAX_OP_ARGS
|| tdefs
->args_ct_str
[i
] == NULL
);
1047 /* sort the constraints (XXX: this is just an heuristic) */
1048 sort_constraints(def
, 0, def
->nb_oargs
);
1049 sort_constraints(def
, def
->nb_oargs
, def
->nb_iargs
);
1055 printf("%s: sorted=", def
->name
);
1056 for(i
= 0; i
< def
->nb_oargs
+ def
->nb_iargs
; i
++)
1057 printf(" %d", def
->sorted_args
[i
]);
1064 #if defined(CONFIG_DEBUG_TCG)
1066 for (op
= 0; op
< ARRAY_SIZE(tcg_op_defs
); op
++) {
1067 if (op
< INDEX_op_call
|| op
== INDEX_op_debug_insn_start
) {
1068 /* Wrong entry in op definitions? */
1069 if (tcg_op_defs
[op
].used
) {
1070 fprintf(stderr
, "Invalid op definition for %s\n",
1071 tcg_op_defs
[op
].name
);
1075 /* Missing entry in op definitions? */
1076 if (!tcg_op_defs
[op
].used
) {
1077 fprintf(stderr
, "Missing op definition for %s\n",
1078 tcg_op_defs
[op
].name
);
1089 #ifdef USE_LIVENESS_ANALYSIS
1091 /* set a nop for an operation using 'nb_args' */
1092 static inline void tcg_set_nop(TCGContext
*s
, uint16_t *opc_ptr
,
1093 TCGArg
*args
, int nb_args
)
1096 *opc_ptr
= INDEX_op_nop
;
1098 *opc_ptr
= INDEX_op_nopn
;
1100 args
[nb_args
- 1] = nb_args
;
1104 /* liveness analysis: end of function: globals are live, temps are
1106 /* XXX: at this stage, not used as there would be little gains because
1107 most TBs end with a conditional jump. */
1108 static inline void tcg_la_func_end(TCGContext
*s
, uint8_t *dead_temps
)
1110 memset(dead_temps
, 0, s
->nb_globals
);
1111 memset(dead_temps
+ s
->nb_globals
, 1, s
->nb_temps
- s
->nb_globals
);
1114 /* liveness analysis: end of basic block: globals are live, temps are
1115 dead, local temps are live. */
1116 static inline void tcg_la_bb_end(TCGContext
*s
, uint8_t *dead_temps
)
1121 memset(dead_temps
, 0, s
->nb_globals
);
1122 ts
= &s
->temps
[s
->nb_globals
];
1123 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
1132 /* Liveness analysis : update the opc_dead_iargs array to tell if a
1133 given input arguments is dead. Instructions updating dead
1134 temporaries are removed. */
1135 static void tcg_liveness_analysis(TCGContext
*s
)
1137 int i
, op_index
, nb_args
, nb_iargs
, nb_oargs
, arg
, nb_ops
;
1140 const TCGOpDef
*def
;
1141 uint8_t *dead_temps
;
1142 unsigned int dead_iargs
;
1144 gen_opc_ptr
++; /* skip end */
1146 nb_ops
= gen_opc_ptr
- gen_opc_buf
;
1148 s
->op_dead_iargs
= tcg_malloc(nb_ops
* sizeof(uint16_t));
1150 dead_temps
= tcg_malloc(s
->nb_temps
);
1151 memset(dead_temps
, 1, s
->nb_temps
);
1153 args
= gen_opparam_ptr
;
1154 op_index
= nb_ops
- 1;
1155 while (op_index
>= 0) {
1156 op
= gen_opc_buf
[op_index
];
1157 def
= &tcg_op_defs
[op
];
1165 nb_iargs
= args
[0] & 0xffff;
1166 nb_oargs
= args
[0] >> 16;
1168 call_flags
= args
[nb_oargs
+ nb_iargs
];
1170 /* pure functions can be removed if their result is not
1172 if (call_flags
& TCG_CALL_PURE
) {
1173 for(i
= 0; i
< nb_oargs
; i
++) {
1175 if (!dead_temps
[arg
])
1176 goto do_not_remove_call
;
1178 tcg_set_nop(s
, gen_opc_buf
+ op_index
,
1183 /* output args are dead */
1184 for(i
= 0; i
< nb_oargs
; i
++) {
1186 dead_temps
[arg
] = 1;
1189 if (!(call_flags
& TCG_CALL_CONST
)) {
1190 /* globals are live (they may be used by the call) */
1191 memset(dead_temps
, 0, s
->nb_globals
);
1194 /* input args are live */
1196 for(i
= 0; i
< nb_iargs
; i
++) {
1197 arg
= args
[i
+ nb_oargs
];
1198 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1199 if (dead_temps
[arg
]) {
1200 dead_iargs
|= (1 << i
);
1202 dead_temps
[arg
] = 0;
1205 s
->op_dead_iargs
[op_index
] = dead_iargs
;
1210 case INDEX_op_set_label
:
1212 /* mark end of basic block */
1213 tcg_la_bb_end(s
, dead_temps
);
1215 case INDEX_op_debug_insn_start
:
1216 args
-= def
->nb_args
;
1222 case INDEX_op_discard
:
1224 /* mark the temporary as dead */
1225 dead_temps
[args
[0]] = 1;
1229 /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1231 args
-= def
->nb_args
;
1232 nb_iargs
= def
->nb_iargs
;
1233 nb_oargs
= def
->nb_oargs
;
1235 /* Test if the operation can be removed because all
1236 its outputs are dead. We assume that nb_oargs == 0
1237 implies side effects */
1238 if (!(def
->flags
& TCG_OPF_SIDE_EFFECTS
) && nb_oargs
!= 0) {
1239 for(i
= 0; i
< nb_oargs
; i
++) {
1241 if (!dead_temps
[arg
])
1244 tcg_set_nop(s
, gen_opc_buf
+ op_index
, args
, def
->nb_args
);
1245 #ifdef CONFIG_PROFILER
1251 /* output args are dead */
1252 for(i
= 0; i
< nb_oargs
; i
++) {
1254 dead_temps
[arg
] = 1;
1257 /* if end of basic block, update */
1258 if (def
->flags
& TCG_OPF_BB_END
) {
1259 tcg_la_bb_end(s
, dead_temps
);
1260 } else if (def
->flags
& TCG_OPF_CALL_CLOBBER
) {
1261 /* globals are live */
1262 memset(dead_temps
, 0, s
->nb_globals
);
1265 /* input args are live */
1267 for(i
= 0; i
< nb_iargs
; i
++) {
1268 arg
= args
[i
+ nb_oargs
];
1269 if (dead_temps
[arg
]) {
1270 dead_iargs
|= (1 << i
);
1272 dead_temps
[arg
] = 0;
1274 s
->op_dead_iargs
[op_index
] = dead_iargs
;
1281 if (args
!= gen_opparam_buf
)
1285 /* dummy liveness analysis */
1286 static void tcg_liveness_analysis(TCGContext
*s
)
1289 nb_ops
= gen_opc_ptr
- gen_opc_buf
;
1291 s
->op_dead_iargs
= tcg_malloc(nb_ops
* sizeof(uint16_t));
1292 memset(s
->op_dead_iargs
, 0, nb_ops
* sizeof(uint16_t));
1297 static void dump_regs(TCGContext
*s
)
1303 for(i
= 0; i
< s
->nb_temps
; i
++) {
1305 printf(" %10s: ", tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), i
));
1306 switch(ts
->val_type
) {
1308 printf("%s", tcg_target_reg_names
[ts
->reg
]);
1311 printf("%d(%s)", (int)ts
->mem_offset
, tcg_target_reg_names
[ts
->mem_reg
]);
1313 case TEMP_VAL_CONST
:
1314 printf("$0x%" TCG_PRIlx
, ts
->val
);
1326 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
1327 if (s
->reg_to_temp
[i
] >= 0) {
1329 tcg_target_reg_names
[i
],
1330 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), s
->reg_to_temp
[i
]));
1335 static void check_regs(TCGContext
*s
)
1341 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1342 k
= s
->reg_to_temp
[reg
];
1345 if (ts
->val_type
!= TEMP_VAL_REG
||
1347 printf("Inconsistency for register %s:\n",
1348 tcg_target_reg_names
[reg
]);
1353 for(k
= 0; k
< s
->nb_temps
; k
++) {
1355 if (ts
->val_type
== TEMP_VAL_REG
&&
1357 s
->reg_to_temp
[ts
->reg
] != k
) {
1358 printf("Inconsistency for temp %s:\n",
1359 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), k
));
1361 printf("reg state:\n");
1369 static void temp_allocate_frame(TCGContext
*s
, int temp
)
1372 ts
= &s
->temps
[temp
];
1373 s
->current_frame_offset
= (s
->current_frame_offset
+ sizeof(tcg_target_long
) - 1) & ~(sizeof(tcg_target_long
) - 1);
1374 if (s
->current_frame_offset
+ sizeof(tcg_target_long
) > s
->frame_end
)
1376 ts
->mem_offset
= s
->current_frame_offset
;
1377 ts
->mem_reg
= s
->frame_reg
;
1378 ts
->mem_allocated
= 1;
1379 s
->current_frame_offset
+= sizeof(tcg_target_long
);
1382 /* free register 'reg' by spilling the corresponding temporary if necessary */
1383 static void tcg_reg_free(TCGContext
*s
, int reg
)
1388 temp
= s
->reg_to_temp
[reg
];
1390 ts
= &s
->temps
[temp
];
1391 assert(ts
->val_type
== TEMP_VAL_REG
);
1392 if (!ts
->mem_coherent
) {
1393 if (!ts
->mem_allocated
)
1394 temp_allocate_frame(s
, temp
);
1395 tcg_out_st(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1397 ts
->val_type
= TEMP_VAL_MEM
;
1398 s
->reg_to_temp
[reg
] = -1;
1402 /* Allocate a register belonging to reg1 & ~reg2 */
1403 static int tcg_reg_alloc(TCGContext
*s
, TCGRegSet reg1
, TCGRegSet reg2
)
1408 tcg_regset_andnot(reg_ct
, reg1
, reg2
);
1410 /* first try free registers */
1411 for(i
= 0; i
< ARRAY_SIZE(tcg_target_reg_alloc_order
); i
++) {
1412 reg
= tcg_target_reg_alloc_order
[i
];
1413 if (tcg_regset_test_reg(reg_ct
, reg
) && s
->reg_to_temp
[reg
] == -1)
1417 /* XXX: do better spill choice */
1418 for(i
= 0; i
< ARRAY_SIZE(tcg_target_reg_alloc_order
); i
++) {
1419 reg
= tcg_target_reg_alloc_order
[i
];
1420 if (tcg_regset_test_reg(reg_ct
, reg
)) {
1421 tcg_reg_free(s
, reg
);
1429 /* save a temporary to memory. 'allocated_regs' is used in case a
1430 temporary registers needs to be allocated to store a constant. */
1431 static void temp_save(TCGContext
*s
, int temp
, TCGRegSet allocated_regs
)
1436 ts
= &s
->temps
[temp
];
1437 if (!ts
->fixed_reg
) {
1438 switch(ts
->val_type
) {
1440 tcg_reg_free(s
, ts
->reg
);
1443 ts
->val_type
= TEMP_VAL_MEM
;
1445 case TEMP_VAL_CONST
:
1446 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1448 if (!ts
->mem_allocated
)
1449 temp_allocate_frame(s
, temp
);
1450 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1451 tcg_out_st(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1452 ts
->val_type
= TEMP_VAL_MEM
;
1462 /* save globals to their cannonical location and assume they can be
1463 modified be the following code. 'allocated_regs' is used in case a
1464 temporary registers needs to be allocated to store a constant. */
1465 static void save_globals(TCGContext
*s
, TCGRegSet allocated_regs
)
1469 for(i
= 0; i
< s
->nb_globals
; i
++) {
1470 temp_save(s
, i
, allocated_regs
);
1474 /* at the end of a basic block, we assume all temporaries are dead and
1475 all globals are stored at their canonical location. */
1476 static void tcg_reg_alloc_bb_end(TCGContext
*s
, TCGRegSet allocated_regs
)
1481 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
1483 if (ts
->temp_local
) {
1484 temp_save(s
, i
, allocated_regs
);
1486 if (ts
->val_type
== TEMP_VAL_REG
) {
1487 s
->reg_to_temp
[ts
->reg
] = -1;
1489 ts
->val_type
= TEMP_VAL_DEAD
;
1493 save_globals(s
, allocated_regs
);
1496 #define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
1498 static void tcg_reg_alloc_movi(TCGContext
*s
, const TCGArg
*args
)
1501 tcg_target_ulong val
;
1503 ots
= &s
->temps
[args
[0]];
1506 if (ots
->fixed_reg
) {
1507 /* for fixed registers, we do not do any constant
1509 tcg_out_movi(s
, ots
->type
, ots
->reg
, val
);
1511 /* The movi is not explicitly generated here */
1512 if (ots
->val_type
== TEMP_VAL_REG
)
1513 s
->reg_to_temp
[ots
->reg
] = -1;
1514 ots
->val_type
= TEMP_VAL_CONST
;
1519 static void tcg_reg_alloc_mov(TCGContext
*s
, const TCGOpDef
*def
,
1521 unsigned int dead_iargs
)
1525 const TCGArgConstraint
*arg_ct
;
1527 ots
= &s
->temps
[args
[0]];
1528 ts
= &s
->temps
[args
[1]];
1529 arg_ct
= &def
->args_ct
[0];
1531 /* XXX: always mark arg dead if IS_DEAD_IARG(0) */
1532 if (ts
->val_type
== TEMP_VAL_REG
) {
1533 if (IS_DEAD_IARG(0) && !ts
->fixed_reg
&& !ots
->fixed_reg
) {
1534 /* the mov can be suppressed */
1535 if (ots
->val_type
== TEMP_VAL_REG
)
1536 s
->reg_to_temp
[ots
->reg
] = -1;
1538 s
->reg_to_temp
[reg
] = -1;
1539 ts
->val_type
= TEMP_VAL_DEAD
;
1541 if (ots
->val_type
== TEMP_VAL_REG
) {
1544 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, s
->reserved_regs
);
1546 if (ts
->reg
!= reg
) {
1547 tcg_out_mov(s
, reg
, ts
->reg
);
1550 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1551 if (ots
->val_type
== TEMP_VAL_REG
) {
1554 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, s
->reserved_regs
);
1556 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1557 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1558 if (ots
->fixed_reg
) {
1560 tcg_out_movi(s
, ots
->type
, reg
, ts
->val
);
1562 /* propagate constant */
1563 if (ots
->val_type
== TEMP_VAL_REG
)
1564 s
->reg_to_temp
[ots
->reg
] = -1;
1565 ots
->val_type
= TEMP_VAL_CONST
;
1572 s
->reg_to_temp
[reg
] = args
[0];
1574 ots
->val_type
= TEMP_VAL_REG
;
1575 ots
->mem_coherent
= 0;
1578 static void tcg_reg_alloc_op(TCGContext
*s
,
1579 const TCGOpDef
*def
, TCGOpcode opc
,
1581 unsigned int dead_iargs
)
1583 TCGRegSet allocated_regs
;
1584 int i
, k
, nb_iargs
, nb_oargs
, reg
;
1586 const TCGArgConstraint
*arg_ct
;
1588 TCGArg new_args
[TCG_MAX_OP_ARGS
];
1589 int const_args
[TCG_MAX_OP_ARGS
];
1591 nb_oargs
= def
->nb_oargs
;
1592 nb_iargs
= def
->nb_iargs
;
1594 /* copy constants */
1595 memcpy(new_args
+ nb_oargs
+ nb_iargs
,
1596 args
+ nb_oargs
+ nb_iargs
,
1597 sizeof(TCGArg
) * def
->nb_cargs
);
1599 /* satisfy input constraints */
1600 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1601 for(k
= 0; k
< nb_iargs
; k
++) {
1602 i
= def
->sorted_args
[nb_oargs
+ k
];
1604 arg_ct
= &def
->args_ct
[i
];
1605 ts
= &s
->temps
[arg
];
1606 if (ts
->val_type
== TEMP_VAL_MEM
) {
1607 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1608 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1609 ts
->val_type
= TEMP_VAL_REG
;
1611 ts
->mem_coherent
= 1;
1612 s
->reg_to_temp
[reg
] = arg
;
1613 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1614 if (tcg_target_const_match(ts
->val
, arg_ct
)) {
1615 /* constant is OK for instruction */
1617 new_args
[i
] = ts
->val
;
1620 /* need to move to a register */
1621 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1622 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1623 ts
->val_type
= TEMP_VAL_REG
;
1625 ts
->mem_coherent
= 0;
1626 s
->reg_to_temp
[reg
] = arg
;
1629 assert(ts
->val_type
== TEMP_VAL_REG
);
1630 if (arg_ct
->ct
& TCG_CT_IALIAS
) {
1631 if (ts
->fixed_reg
) {
1632 /* if fixed register, we must allocate a new register
1633 if the alias is not the same register */
1634 if (arg
!= args
[arg_ct
->alias_index
])
1635 goto allocate_in_reg
;
1637 /* if the input is aliased to an output and if it is
1638 not dead after the instruction, we must allocate
1639 a new register and move it */
1640 if (!IS_DEAD_IARG(i
- nb_oargs
))
1641 goto allocate_in_reg
;
1645 if (tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1646 /* nothing to do : the constraint is satisfied */
1649 /* allocate a new register matching the constraint
1650 and move the temporary register into it */
1651 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1652 tcg_out_mov(s
, reg
, ts
->reg
);
1656 tcg_regset_set_reg(allocated_regs
, reg
);
1660 if (def
->flags
& TCG_OPF_BB_END
) {
1661 tcg_reg_alloc_bb_end(s
, allocated_regs
);
1663 /* mark dead temporaries and free the associated registers */
1664 for(i
= 0; i
< nb_iargs
; i
++) {
1665 arg
= args
[nb_oargs
+ i
];
1666 if (IS_DEAD_IARG(i
)) {
1667 ts
= &s
->temps
[arg
];
1668 if (!ts
->fixed_reg
) {
1669 if (ts
->val_type
== TEMP_VAL_REG
)
1670 s
->reg_to_temp
[ts
->reg
] = -1;
1671 ts
->val_type
= TEMP_VAL_DEAD
;
1676 if (def
->flags
& TCG_OPF_CALL_CLOBBER
) {
1677 /* XXX: permit generic clobber register list ? */
1678 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1679 if (tcg_regset_test_reg(tcg_target_call_clobber_regs
, reg
)) {
1680 tcg_reg_free(s
, reg
);
1683 /* XXX: for load/store we could do that only for the slow path
1684 (i.e. when a memory callback is called) */
1686 /* store globals and free associated registers (we assume the insn
1687 can modify any global. */
1688 save_globals(s
, allocated_regs
);
1691 /* satisfy the output constraints */
1692 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1693 for(k
= 0; k
< nb_oargs
; k
++) {
1694 i
= def
->sorted_args
[k
];
1696 arg_ct
= &def
->args_ct
[i
];
1697 ts
= &s
->temps
[arg
];
1698 if (arg_ct
->ct
& TCG_CT_ALIAS
) {
1699 reg
= new_args
[arg_ct
->alias_index
];
1701 /* if fixed register, we try to use it */
1703 if (ts
->fixed_reg
&&
1704 tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1707 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1709 tcg_regset_set_reg(allocated_regs
, reg
);
1710 /* if a fixed register is used, then a move will be done afterwards */
1711 if (!ts
->fixed_reg
) {
1712 if (ts
->val_type
== TEMP_VAL_REG
)
1713 s
->reg_to_temp
[ts
->reg
] = -1;
1714 ts
->val_type
= TEMP_VAL_REG
;
1716 /* temp value is modified, so the value kept in memory is
1717 potentially not the same */
1718 ts
->mem_coherent
= 0;
1719 s
->reg_to_temp
[reg
] = arg
;
1726 /* emit instruction */
1727 tcg_out_op(s
, opc
, new_args
, const_args
);
1729 /* move the outputs in the correct register if needed */
1730 for(i
= 0; i
< nb_oargs
; i
++) {
1731 ts
= &s
->temps
[args
[i
]];
1733 if (ts
->fixed_reg
&& ts
->reg
!= reg
) {
1734 tcg_out_mov(s
, ts
->reg
, reg
);
1739 #ifdef TCG_TARGET_STACK_GROWSUP
1740 #define STACK_DIR(x) (-(x))
1742 #define STACK_DIR(x) (x)
1745 static int tcg_reg_alloc_call(TCGContext
*s
, const TCGOpDef
*def
,
1746 TCGOpcode opc
, const TCGArg
*args
,
1747 unsigned int dead_iargs
)
1749 int nb_iargs
, nb_oargs
, flags
, nb_regs
, i
, reg
, nb_params
;
1750 TCGArg arg
, func_arg
;
1752 tcg_target_long stack_offset
, call_stack_size
, func_addr
;
1753 int const_func_arg
, allocate_args
;
1754 TCGRegSet allocated_regs
;
1755 const TCGArgConstraint
*arg_ct
;
1759 nb_oargs
= arg
>> 16;
1760 nb_iargs
= arg
& 0xffff;
1761 nb_params
= nb_iargs
- 1;
1763 flags
= args
[nb_oargs
+ nb_iargs
];
1765 nb_regs
= tcg_target_get_call_iarg_regs_count(flags
);
1766 if (nb_regs
> nb_params
)
1767 nb_regs
= nb_params
;
1769 /* assign stack slots first */
1770 /* XXX: preallocate call stack */
1771 call_stack_size
= (nb_params
- nb_regs
) * sizeof(tcg_target_long
);
1772 call_stack_size
= (call_stack_size
+ TCG_TARGET_STACK_ALIGN
- 1) &
1773 ~(TCG_TARGET_STACK_ALIGN
- 1);
1774 allocate_args
= (call_stack_size
> TCG_STATIC_CALL_ARGS_SIZE
);
1775 if (allocate_args
) {
1776 tcg_out_addi(s
, TCG_REG_CALL_STACK
, -STACK_DIR(call_stack_size
));
1779 stack_offset
= TCG_TARGET_CALL_STACK_OFFSET
;
1780 for(i
= nb_regs
; i
< nb_params
; i
++) {
1781 arg
= args
[nb_oargs
+ i
];
1782 #ifdef TCG_TARGET_STACK_GROWSUP
1783 stack_offset
-= sizeof(tcg_target_long
);
1785 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1786 ts
= &s
->temps
[arg
];
1787 if (ts
->val_type
== TEMP_VAL_REG
) {
1788 tcg_out_st(s
, ts
->type
, ts
->reg
, TCG_REG_CALL_STACK
, stack_offset
);
1789 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1790 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1792 /* XXX: not correct if reading values from the stack */
1793 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1794 tcg_out_st(s
, ts
->type
, reg
, TCG_REG_CALL_STACK
, stack_offset
);
1795 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1796 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1798 /* XXX: sign extend may be needed on some targets */
1799 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1800 tcg_out_st(s
, ts
->type
, reg
, TCG_REG_CALL_STACK
, stack_offset
);
1805 #ifndef TCG_TARGET_STACK_GROWSUP
1806 stack_offset
+= sizeof(tcg_target_long
);
1810 /* assign input registers */
1811 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1812 for(i
= 0; i
< nb_regs
; i
++) {
1813 arg
= args
[nb_oargs
+ i
];
1814 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1815 ts
= &s
->temps
[arg
];
1816 reg
= tcg_target_call_iarg_regs
[i
];
1817 tcg_reg_free(s
, reg
);
1818 if (ts
->val_type
== TEMP_VAL_REG
) {
1819 if (ts
->reg
!= reg
) {
1820 tcg_out_mov(s
, reg
, ts
->reg
);
1822 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1823 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1824 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1825 /* XXX: sign extend ? */
1826 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1830 tcg_regset_set_reg(allocated_regs
, reg
);
1834 /* assign function address */
1835 func_arg
= args
[nb_oargs
+ nb_iargs
- 1];
1836 arg_ct
= &def
->args_ct
[0];
1837 ts
= &s
->temps
[func_arg
];
1838 func_addr
= ts
->val
;
1840 if (ts
->val_type
== TEMP_VAL_MEM
) {
1841 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1842 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1844 tcg_regset_set_reg(allocated_regs
, reg
);
1845 } else if (ts
->val_type
== TEMP_VAL_REG
) {
1847 if (!tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1848 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1849 tcg_out_mov(s
, reg
, ts
->reg
);
1852 tcg_regset_set_reg(allocated_regs
, reg
);
1853 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1854 if (tcg_target_const_match(func_addr
, arg_ct
)) {
1856 func_arg
= func_addr
;
1858 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1859 tcg_out_movi(s
, ts
->type
, reg
, func_addr
);
1861 tcg_regset_set_reg(allocated_regs
, reg
);
1868 /* mark dead temporaries and free the associated registers */
1869 for(i
= 0; i
< nb_iargs
; i
++) {
1870 arg
= args
[nb_oargs
+ i
];
1871 if (IS_DEAD_IARG(i
)) {
1872 ts
= &s
->temps
[arg
];
1873 if (!ts
->fixed_reg
) {
1874 if (ts
->val_type
== TEMP_VAL_REG
)
1875 s
->reg_to_temp
[ts
->reg
] = -1;
1876 ts
->val_type
= TEMP_VAL_DEAD
;
1881 /* clobber call registers */
1882 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1883 if (tcg_regset_test_reg(tcg_target_call_clobber_regs
, reg
)) {
1884 tcg_reg_free(s
, reg
);
1888 /* store globals and free associated registers (we assume the call
1889 can modify any global. */
1890 if (!(flags
& TCG_CALL_CONST
)) {
1891 save_globals(s
, allocated_regs
);
1894 tcg_out_op(s
, opc
, &func_arg
, &const_func_arg
);
1896 if (allocate_args
) {
1897 tcg_out_addi(s
, TCG_REG_CALL_STACK
, STACK_DIR(call_stack_size
));
1900 /* assign output registers and emit moves if needed */
1901 for(i
= 0; i
< nb_oargs
; i
++) {
1903 ts
= &s
->temps
[arg
];
1904 reg
= tcg_target_call_oarg_regs
[i
];
1905 assert(s
->reg_to_temp
[reg
] == -1);
1906 if (ts
->fixed_reg
) {
1907 if (ts
->reg
!= reg
) {
1908 tcg_out_mov(s
, ts
->reg
, reg
);
1911 if (ts
->val_type
== TEMP_VAL_REG
)
1912 s
->reg_to_temp
[ts
->reg
] = -1;
1913 ts
->val_type
= TEMP_VAL_REG
;
1915 ts
->mem_coherent
= 0;
1916 s
->reg_to_temp
[reg
] = arg
;
1920 return nb_iargs
+ nb_oargs
+ def
->nb_cargs
+ 1;
1923 #ifdef CONFIG_PROFILER
1925 static int64_t tcg_table_op_count
[NB_OPS
];
1927 static void dump_op_count(void)
1931 f
= fopen("/tmp/op.log", "w");
1932 for(i
= INDEX_op_end
; i
< NB_OPS
; i
++) {
1933 fprintf(f
, "%s %" PRId64
"\n", tcg_op_defs
[i
].name
, tcg_table_op_count
[i
]);
1940 static inline int tcg_gen_code_common(TCGContext
*s
, uint8_t *gen_code_buf
,
1945 const TCGOpDef
*def
;
1946 unsigned int dead_iargs
;
1950 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP
))) {
1952 tcg_dump_ops(s
, logfile
);
1957 #ifdef CONFIG_PROFILER
1958 s
->la_time
-= profile_getclock();
1960 tcg_liveness_analysis(s
);
1961 #ifdef CONFIG_PROFILER
1962 s
->la_time
+= profile_getclock();
1966 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT
))) {
1967 qemu_log("OP after liveness analysis:\n");
1968 tcg_dump_ops(s
, logfile
);
1973 tcg_reg_alloc_start(s
);
1975 s
->code_buf
= gen_code_buf
;
1976 s
->code_ptr
= gen_code_buf
;
1978 args
= gen_opparam_buf
;
1982 opc
= gen_opc_buf
[op_index
];
1983 #ifdef CONFIG_PROFILER
1984 tcg_table_op_count
[opc
]++;
1986 def
= &tcg_op_defs
[opc
];
1988 printf("%s: %d %d %d\n", def
->name
,
1989 def
->nb_oargs
, def
->nb_iargs
, def
->nb_cargs
);
1993 case INDEX_op_mov_i32
:
1994 #if TCG_TARGET_REG_BITS == 64
1995 case INDEX_op_mov_i64
:
1997 dead_iargs
= s
->op_dead_iargs
[op_index
];
1998 tcg_reg_alloc_mov(s
, def
, args
, dead_iargs
);
2000 case INDEX_op_movi_i32
:
2001 #if TCG_TARGET_REG_BITS == 64
2002 case INDEX_op_movi_i64
:
2004 tcg_reg_alloc_movi(s
, args
);
2006 case INDEX_op_debug_insn_start
:
2007 /* debug instruction */
2017 case INDEX_op_discard
:
2020 ts
= &s
->temps
[args
[0]];
2021 /* mark the temporary as dead */
2022 if (!ts
->fixed_reg
) {
2023 if (ts
->val_type
== TEMP_VAL_REG
)
2024 s
->reg_to_temp
[ts
->reg
] = -1;
2025 ts
->val_type
= TEMP_VAL_DEAD
;
2029 case INDEX_op_set_label
:
2030 tcg_reg_alloc_bb_end(s
, s
->reserved_regs
);
2031 tcg_out_label(s
, args
[0], (long)s
->code_ptr
);
2034 dead_iargs
= s
->op_dead_iargs
[op_index
];
2035 args
+= tcg_reg_alloc_call(s
, def
, opc
, args
, dead_iargs
);
2040 /* Note: in order to speed up the code, it would be much
2041 faster to have specialized register allocator functions for
2042 some common argument patterns */
2043 dead_iargs
= s
->op_dead_iargs
[op_index
];
2044 tcg_reg_alloc_op(s
, def
, opc
, args
, dead_iargs
);
2047 args
+= def
->nb_args
;
2049 if (search_pc
>= 0 && search_pc
< s
->code_ptr
- gen_code_buf
) {
2061 int tcg_gen_code(TCGContext
*s
, uint8_t *gen_code_buf
)
2063 #ifdef CONFIG_PROFILER
2066 n
= (gen_opc_ptr
- gen_opc_buf
);
2068 if (n
> s
->op_count_max
)
2069 s
->op_count_max
= n
;
2071 s
->temp_count
+= s
->nb_temps
;
2072 if (s
->nb_temps
> s
->temp_count_max
)
2073 s
->temp_count_max
= s
->nb_temps
;
2077 tcg_gen_code_common(s
, gen_code_buf
, -1);
2079 /* flush instruction cache */
2080 flush_icache_range((unsigned long)gen_code_buf
,
2081 (unsigned long)s
->code_ptr
);
2082 return s
->code_ptr
- gen_code_buf
;
2085 /* Return the index of the micro operation such as the pc after is <
2086 offset bytes from the start of the TB. The contents of gen_code_buf must
2087 not be changed, though writing the same values is ok.
2088 Return -1 if not found. */
2089 int tcg_gen_code_search_pc(TCGContext
*s
, uint8_t *gen_code_buf
, long offset
)
2091 return tcg_gen_code_common(s
, gen_code_buf
, offset
);
2094 #ifdef CONFIG_PROFILER
2095 void tcg_dump_info(FILE *f
,
2096 int (*cpu_fprintf
)(FILE *f
, const char *fmt
, ...))
2098 TCGContext
*s
= &tcg_ctx
;
2101 tot
= s
->interm_time
+ s
->code_time
;
2102 cpu_fprintf(f
, "JIT cycles %" PRId64
" (%0.3f s at 2.4 GHz)\n",
2104 cpu_fprintf(f
, "translated TBs %" PRId64
" (aborted=%" PRId64
" %0.1f%%)\n",
2106 s
->tb_count1
- s
->tb_count
,
2107 s
->tb_count1
? (double)(s
->tb_count1
- s
->tb_count
) / s
->tb_count1
* 100.0 : 0);
2108 cpu_fprintf(f
, "avg ops/TB %0.1f max=%d\n",
2109 s
->tb_count
? (double)s
->op_count
/ s
->tb_count
: 0, s
->op_count_max
);
2110 cpu_fprintf(f
, "deleted ops/TB %0.2f\n",
2112 (double)s
->del_op_count
/ s
->tb_count
: 0);
2113 cpu_fprintf(f
, "avg temps/TB %0.2f max=%d\n",
2115 (double)s
->temp_count
/ s
->tb_count
: 0,
2118 cpu_fprintf(f
, "cycles/op %0.1f\n",
2119 s
->op_count
? (double)tot
/ s
->op_count
: 0);
2120 cpu_fprintf(f
, "cycles/in byte %0.1f\n",
2121 s
->code_in_len
? (double)tot
/ s
->code_in_len
: 0);
2122 cpu_fprintf(f
, "cycles/out byte %0.1f\n",
2123 s
->code_out_len
? (double)tot
/ s
->code_out_len
: 0);
2126 cpu_fprintf(f
, " gen_interm time %0.1f%%\n",
2127 (double)s
->interm_time
/ tot
* 100.0);
2128 cpu_fprintf(f
, " gen_code time %0.1f%%\n",
2129 (double)s
->code_time
/ tot
* 100.0);
2130 cpu_fprintf(f
, "liveness/code time %0.1f%%\n",
2131 (double)s
->la_time
/ (s
->code_time
? s
->code_time
: 1) * 100.0);
2132 cpu_fprintf(f
, "cpu_restore count %" PRId64
"\n",
2134 cpu_fprintf(f
, " avg cycles %0.1f\n",
2135 s
->restore_count
? (double)s
->restore_time
/ s
->restore_count
: 0);
2140 void tcg_dump_info(FILE *f
,
2141 int (*cpu_fprintf
)(FILE *f
, const char *fmt
, ...))
2143 cpu_fprintf(f
, "[TCG profiler not compiled]\n");