2 * Tiny Code Generator for QEMU
4 * Copyright (c) 2008 Fabrice Bellard
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 /* define it to use liveness analysis (better code) */
26 #define USE_LIVENESS_ANALYSIS
30 #ifndef CONFIG_DEBUG_TCG
31 /* define it to suppress various consistency checks (faster) */
47 #include "qemu-common.h"
48 #include "cache-utils.h"
49 #include "host-utils.h"
51 /* Note: the long term plan is to reduce the dependancies on the QEMU
52 CPU definitions. Currently they are used for qemu_ld/st
54 #define NO_CPU_IO_DEFS
61 #if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
62 #error GUEST_BASE not supported on this host.
65 static void patch_reloc(uint8_t *code_ptr
, int type
,
66 tcg_target_long value
, tcg_target_long addend
);
68 static TCGOpDef tcg_op_defs
[] = {
69 #define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size },
70 #define DEF2(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags, 0 },
76 static TCGRegSet tcg_target_available_regs
[2];
77 static TCGRegSet tcg_target_call_clobber_regs
;
79 /* XXX: move that inside the context */
80 uint16_t *gen_opc_ptr
;
81 TCGArg
*gen_opparam_ptr
;
83 static inline void tcg_out8(TCGContext
*s
, uint8_t v
)
88 static inline void tcg_out16(TCGContext
*s
, uint16_t v
)
90 *(uint16_t *)s
->code_ptr
= v
;
94 static inline void tcg_out32(TCGContext
*s
, uint32_t v
)
96 *(uint32_t *)s
->code_ptr
= v
;
100 /* label relocation processing */
102 void tcg_out_reloc(TCGContext
*s
, uint8_t *code_ptr
, int type
,
103 int label_index
, long addend
)
108 l
= &s
->labels
[label_index
];
110 /* FIXME: This may break relocations on RISC targets that
111 modify instruction fields in place. The caller may not have
112 written the initial value. */
113 patch_reloc(code_ptr
, type
, l
->u
.value
, addend
);
115 /* add a new relocation entry */
116 r
= tcg_malloc(sizeof(TCGRelocation
));
120 r
->next
= l
->u
.first_reloc
;
121 l
->u
.first_reloc
= r
;
125 static void tcg_out_label(TCGContext
*s
, int label_index
,
126 tcg_target_long value
)
131 l
= &s
->labels
[label_index
];
134 r
= l
->u
.first_reloc
;
136 patch_reloc(r
->ptr
, r
->type
, value
, r
->addend
);
143 int gen_new_label(void)
145 TCGContext
*s
= &tcg_ctx
;
149 if (s
->nb_labels
>= TCG_MAX_LABELS
)
151 idx
= s
->nb_labels
++;
154 l
->u
.first_reloc
= NULL
;
158 #include "tcg-target.c"
160 /* pool based memory allocation */
161 void *tcg_malloc_internal(TCGContext
*s
, int size
)
166 if (size
> TCG_POOL_CHUNK_SIZE
) {
167 /* big malloc: insert a new pool (XXX: could optimize) */
168 p
= qemu_malloc(sizeof(TCGPool
) + size
);
171 s
->pool_current
->next
= p
;
174 p
->next
= s
->pool_current
;
184 pool_size
= TCG_POOL_CHUNK_SIZE
;
185 p
= qemu_malloc(sizeof(TCGPool
) + pool_size
);
189 s
->pool_current
->next
= p
;
198 s
->pool_cur
= p
->data
+ size
;
199 s
->pool_end
= p
->data
+ p
->size
;
203 void tcg_pool_reset(TCGContext
*s
)
205 s
->pool_cur
= s
->pool_end
= NULL
;
206 s
->pool_current
= NULL
;
209 void tcg_context_init(TCGContext
*s
)
211 int op
, total_args
, n
;
213 TCGArgConstraint
*args_ct
;
216 memset(s
, 0, sizeof(*s
));
217 s
->temps
= s
->static_temps
;
220 /* Count total number of arguments and allocate the corresponding
223 for(op
= 0; op
< NB_OPS
; op
++) {
224 def
= &tcg_op_defs
[op
];
225 n
= def
->nb_iargs
+ def
->nb_oargs
;
229 args_ct
= qemu_malloc(sizeof(TCGArgConstraint
) * total_args
);
230 sorted_args
= qemu_malloc(sizeof(int) * total_args
);
232 for(op
= 0; op
< NB_OPS
; op
++) {
233 def
= &tcg_op_defs
[op
];
234 def
->args_ct
= args_ct
;
235 def
->sorted_args
= sorted_args
;
236 n
= def
->nb_iargs
+ def
->nb_oargs
;
243 /* init global prologue and epilogue */
244 s
->code_buf
= code_gen_prologue
;
245 s
->code_ptr
= s
->code_buf
;
246 tcg_target_qemu_prologue(s
);
247 flush_icache_range((unsigned long)s
->code_buf
,
248 (unsigned long)s
->code_ptr
);
251 void tcg_set_frame(TCGContext
*s
, int reg
,
252 tcg_target_long start
, tcg_target_long size
)
254 s
->frame_start
= start
;
255 s
->frame_end
= start
+ size
;
259 void tcg_func_start(TCGContext
*s
)
263 s
->nb_temps
= s
->nb_globals
;
264 for(i
= 0; i
< (TCG_TYPE_COUNT
* 2); i
++)
265 s
->first_free_temp
[i
] = -1;
266 s
->labels
= tcg_malloc(sizeof(TCGLabel
) * TCG_MAX_LABELS
);
268 s
->current_frame_offset
= s
->frame_start
;
270 gen_opc_ptr
= gen_opc_buf
;
271 gen_opparam_ptr
= gen_opparam_buf
;
274 static inline void tcg_temp_alloc(TCGContext
*s
, int n
)
276 if (n
> TCG_MAX_TEMPS
)
280 static inline int tcg_global_reg_new_internal(TCGType type
, int reg
,
283 TCGContext
*s
= &tcg_ctx
;
287 #if TCG_TARGET_REG_BITS == 32
288 if (type
!= TCG_TYPE_I32
)
291 if (tcg_regset_test_reg(s
->reserved_regs
, reg
))
294 tcg_temp_alloc(s
, s
->nb_globals
+ 1);
295 ts
= &s
->temps
[s
->nb_globals
];
296 ts
->base_type
= type
;
302 tcg_regset_set_reg(s
->reserved_regs
, reg
);
306 TCGv_i32
tcg_global_reg_new_i32(int reg
, const char *name
)
310 idx
= tcg_global_reg_new_internal(TCG_TYPE_I32
, reg
, name
);
311 return MAKE_TCGV_I32(idx
);
314 TCGv_i64
tcg_global_reg_new_i64(int reg
, const char *name
)
318 idx
= tcg_global_reg_new_internal(TCG_TYPE_I64
, reg
, name
);
319 return MAKE_TCGV_I64(idx
);
322 static inline int tcg_global_mem_new_internal(TCGType type
, int reg
,
323 tcg_target_long offset
,
326 TCGContext
*s
= &tcg_ctx
;
331 #if TCG_TARGET_REG_BITS == 32
332 if (type
== TCG_TYPE_I64
) {
334 tcg_temp_alloc(s
, s
->nb_globals
+ 2);
335 ts
= &s
->temps
[s
->nb_globals
];
336 ts
->base_type
= type
;
337 ts
->type
= TCG_TYPE_I32
;
339 ts
->mem_allocated
= 1;
341 #ifdef TCG_TARGET_WORDS_BIGENDIAN
342 ts
->mem_offset
= offset
+ 4;
344 ts
->mem_offset
= offset
;
346 pstrcpy(buf
, sizeof(buf
), name
);
347 pstrcat(buf
, sizeof(buf
), "_0");
348 ts
->name
= strdup(buf
);
351 ts
->base_type
= type
;
352 ts
->type
= TCG_TYPE_I32
;
354 ts
->mem_allocated
= 1;
356 #ifdef TCG_TARGET_WORDS_BIGENDIAN
357 ts
->mem_offset
= offset
;
359 ts
->mem_offset
= offset
+ 4;
361 pstrcpy(buf
, sizeof(buf
), name
);
362 pstrcat(buf
, sizeof(buf
), "_1");
363 ts
->name
= strdup(buf
);
369 tcg_temp_alloc(s
, s
->nb_globals
+ 1);
370 ts
= &s
->temps
[s
->nb_globals
];
371 ts
->base_type
= type
;
374 ts
->mem_allocated
= 1;
376 ts
->mem_offset
= offset
;
383 TCGv_i32
tcg_global_mem_new_i32(int reg
, tcg_target_long offset
,
388 idx
= tcg_global_mem_new_internal(TCG_TYPE_I32
, reg
, offset
, name
);
389 return MAKE_TCGV_I32(idx
);
392 TCGv_i64
tcg_global_mem_new_i64(int reg
, tcg_target_long offset
,
397 idx
= tcg_global_mem_new_internal(TCG_TYPE_I64
, reg
, offset
, name
);
398 return MAKE_TCGV_I64(idx
);
401 static inline int tcg_temp_new_internal(TCGType type
, int temp_local
)
403 TCGContext
*s
= &tcg_ctx
;
410 idx
= s
->first_free_temp
[k
];
412 /* There is already an available temp with the
415 s
->first_free_temp
[k
] = ts
->next_free_temp
;
416 ts
->temp_allocated
= 1;
417 assert(ts
->temp_local
== temp_local
);
420 #if TCG_TARGET_REG_BITS == 32
421 if (type
== TCG_TYPE_I64
) {
422 tcg_temp_alloc(s
, s
->nb_temps
+ 2);
423 ts
= &s
->temps
[s
->nb_temps
];
424 ts
->base_type
= type
;
425 ts
->type
= TCG_TYPE_I32
;
426 ts
->temp_allocated
= 1;
427 ts
->temp_local
= temp_local
;
430 ts
->base_type
= TCG_TYPE_I32
;
431 ts
->type
= TCG_TYPE_I32
;
432 ts
->temp_allocated
= 1;
433 ts
->temp_local
= temp_local
;
439 tcg_temp_alloc(s
, s
->nb_temps
+ 1);
440 ts
= &s
->temps
[s
->nb_temps
];
441 ts
->base_type
= type
;
443 ts
->temp_allocated
= 1;
444 ts
->temp_local
= temp_local
;
452 TCGv_i32
tcg_temp_new_internal_i32(int temp_local
)
456 idx
= tcg_temp_new_internal(TCG_TYPE_I32
, temp_local
);
457 return MAKE_TCGV_I32(idx
);
460 TCGv_i64
tcg_temp_new_internal_i64(int temp_local
)
464 idx
= tcg_temp_new_internal(TCG_TYPE_I64
, temp_local
);
465 return MAKE_TCGV_I64(idx
);
468 static inline void tcg_temp_free_internal(int idx
)
470 TCGContext
*s
= &tcg_ctx
;
474 assert(idx
>= s
->nb_globals
&& idx
< s
->nb_temps
);
476 assert(ts
->temp_allocated
!= 0);
477 ts
->temp_allocated
= 0;
481 ts
->next_free_temp
= s
->first_free_temp
[k
];
482 s
->first_free_temp
[k
] = idx
;
485 void tcg_temp_free_i32(TCGv_i32 arg
)
487 tcg_temp_free_internal(GET_TCGV_I32(arg
));
490 void tcg_temp_free_i64(TCGv_i64 arg
)
492 tcg_temp_free_internal(GET_TCGV_I64(arg
));
495 TCGv_i32
tcg_const_i32(int32_t val
)
498 t0
= tcg_temp_new_i32();
499 tcg_gen_movi_i32(t0
, val
);
503 TCGv_i64
tcg_const_i64(int64_t val
)
506 t0
= tcg_temp_new_i64();
507 tcg_gen_movi_i64(t0
, val
);
511 TCGv_i32
tcg_const_local_i32(int32_t val
)
514 t0
= tcg_temp_local_new_i32();
515 tcg_gen_movi_i32(t0
, val
);
519 TCGv_i64
tcg_const_local_i64(int64_t val
)
522 t0
= tcg_temp_local_new_i64();
523 tcg_gen_movi_i64(t0
, val
);
527 void tcg_register_helper(void *func
, const char *name
)
529 TCGContext
*s
= &tcg_ctx
;
531 if ((s
->nb_helpers
+ 1) > s
->allocated_helpers
) {
532 n
= s
->allocated_helpers
;
538 s
->helpers
= realloc(s
->helpers
, n
* sizeof(TCGHelperInfo
));
539 s
->allocated_helpers
= n
;
541 s
->helpers
[s
->nb_helpers
].func
= (tcg_target_ulong
)func
;
542 s
->helpers
[s
->nb_helpers
].name
= name
;
546 /* Note: we convert the 64 bit args to 32 bit and do some alignment
547 and endian swap. Maybe it would be better to do the alignment
548 and endian swap in tcg_reg_alloc_call(). */
549 void tcg_gen_callN(TCGContext
*s
, TCGv_ptr func
, unsigned int flags
,
550 int sizemask
, TCGArg ret
, int nargs
, TCGArg
*args
)
557 *gen_opc_ptr
++ = INDEX_op_call
;
558 nparam
= gen_opparam_ptr
++;
559 call_type
= (flags
& TCG_CALL_TYPE_MASK
);
560 if (ret
!= TCG_CALL_DUMMY_ARG
) {
561 #if TCG_TARGET_REG_BITS < 64
563 #ifdef TCG_TARGET_WORDS_BIGENDIAN
564 *gen_opparam_ptr
++ = ret
+ 1;
565 *gen_opparam_ptr
++ = ret
;
567 *gen_opparam_ptr
++ = ret
;
568 *gen_opparam_ptr
++ = ret
+ 1;
574 *gen_opparam_ptr
++ = ret
;
581 for (i
= 0; i
< nargs
; i
++) {
582 #if TCG_TARGET_REG_BITS < 64
583 if (sizemask
& (2 << i
)) {
584 #ifdef TCG_TARGET_I386
585 /* REGPARM case: if the third parameter is 64 bit, it is
586 allocated on the stack */
587 if (i
== 2 && call_type
== TCG_CALL_TYPE_REGPARM
) {
588 call_type
= TCG_CALL_TYPE_REGPARM_2
;
589 flags
= (flags
& ~TCG_CALL_TYPE_MASK
) | call_type
;
592 #ifdef TCG_TARGET_CALL_ALIGN_ARGS
593 /* some targets want aligned 64 bit args */
595 *gen_opparam_ptr
++ = TCG_CALL_DUMMY_ARG
;
599 #ifdef TCG_TARGET_WORDS_BIGENDIAN
600 *gen_opparam_ptr
++ = args
[i
] + 1;
601 *gen_opparam_ptr
++ = args
[i
];
603 *gen_opparam_ptr
++ = args
[i
];
604 *gen_opparam_ptr
++ = args
[i
] + 1;
610 *gen_opparam_ptr
++ = args
[i
];
614 *gen_opparam_ptr
++ = GET_TCGV_PTR(func
);
616 *gen_opparam_ptr
++ = flags
;
618 *nparam
= (nb_rets
<< 16) | (real_args
+ 1);
620 /* total parameters, needed to go backward in the instruction stream */
621 *gen_opparam_ptr
++ = 1 + nb_rets
+ real_args
+ 3;
624 #if TCG_TARGET_REG_BITS == 32
625 void tcg_gen_shifti_i64(TCGv_i64 ret
, TCGv_i64 arg1
,
626 int c
, int right
, int arith
)
629 tcg_gen_mov_i32(TCGV_LOW(ret
), TCGV_LOW(arg1
));
630 tcg_gen_mov_i32(TCGV_HIGH(ret
), TCGV_HIGH(arg1
));
631 } else if (c
>= 32) {
635 tcg_gen_sari_i32(TCGV_LOW(ret
), TCGV_HIGH(arg1
), c
);
636 tcg_gen_sari_i32(TCGV_HIGH(ret
), TCGV_HIGH(arg1
), 31);
638 tcg_gen_shri_i32(TCGV_LOW(ret
), TCGV_HIGH(arg1
), c
);
639 tcg_gen_movi_i32(TCGV_HIGH(ret
), 0);
642 tcg_gen_shli_i32(TCGV_HIGH(ret
), TCGV_LOW(arg1
), c
);
643 tcg_gen_movi_i32(TCGV_LOW(ret
), 0);
648 t0
= tcg_temp_new_i32();
649 t1
= tcg_temp_new_i32();
651 tcg_gen_shli_i32(t0
, TCGV_HIGH(arg1
), 32 - c
);
653 tcg_gen_sari_i32(t1
, TCGV_HIGH(arg1
), c
);
655 tcg_gen_shri_i32(t1
, TCGV_HIGH(arg1
), c
);
656 tcg_gen_shri_i32(TCGV_LOW(ret
), TCGV_LOW(arg1
), c
);
657 tcg_gen_or_i32(TCGV_LOW(ret
), TCGV_LOW(ret
), t0
);
658 tcg_gen_mov_i32(TCGV_HIGH(ret
), t1
);
660 tcg_gen_shri_i32(t0
, TCGV_LOW(arg1
), 32 - c
);
661 /* Note: ret can be the same as arg1, so we use t1 */
662 tcg_gen_shli_i32(t1
, TCGV_LOW(arg1
), c
);
663 tcg_gen_shli_i32(TCGV_HIGH(ret
), TCGV_HIGH(arg1
), c
);
664 tcg_gen_or_i32(TCGV_HIGH(ret
), TCGV_HIGH(ret
), t0
);
665 tcg_gen_mov_i32(TCGV_LOW(ret
), t1
);
667 tcg_temp_free_i32(t0
);
668 tcg_temp_free_i32(t1
);
674 static void tcg_reg_alloc_start(TCGContext
*s
)
678 for(i
= 0; i
< s
->nb_globals
; i
++) {
681 ts
->val_type
= TEMP_VAL_REG
;
683 ts
->val_type
= TEMP_VAL_MEM
;
686 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
688 ts
->val_type
= TEMP_VAL_DEAD
;
689 ts
->mem_allocated
= 0;
692 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
693 s
->reg_to_temp
[i
] = -1;
697 static char *tcg_get_arg_str_idx(TCGContext
*s
, char *buf
, int buf_size
,
703 if (idx
< s
->nb_globals
) {
704 pstrcpy(buf
, buf_size
, ts
->name
);
707 snprintf(buf
, buf_size
, "loc%d", idx
- s
->nb_globals
);
709 snprintf(buf
, buf_size
, "tmp%d", idx
- s
->nb_globals
);
714 char *tcg_get_arg_str_i32(TCGContext
*s
, char *buf
, int buf_size
, TCGv_i32 arg
)
716 return tcg_get_arg_str_idx(s
, buf
, buf_size
, GET_TCGV_I32(arg
));
719 char *tcg_get_arg_str_i64(TCGContext
*s
, char *buf
, int buf_size
, TCGv_i64 arg
)
721 return tcg_get_arg_str_idx(s
, buf
, buf_size
, GET_TCGV_I64(arg
));
724 static int helper_cmp(const void *p1
, const void *p2
)
726 const TCGHelperInfo
*th1
= p1
;
727 const TCGHelperInfo
*th2
= p2
;
728 if (th1
->func
< th2
->func
)
730 else if (th1
->func
== th2
->func
)
736 /* find helper definition (Note: A hash table would be better) */
737 static TCGHelperInfo
*tcg_find_helper(TCGContext
*s
, tcg_target_ulong val
)
743 if (unlikely(!s
->helpers_sorted
)) {
744 qsort(s
->helpers
, s
->nb_helpers
, sizeof(TCGHelperInfo
),
746 s
->helpers_sorted
= 1;
751 m_max
= s
->nb_helpers
- 1;
752 while (m_min
<= m_max
) {
753 m
= (m_min
+ m_max
) >> 1;
767 static const char * const cond_name
[] =
769 [TCG_COND_EQ
] = "eq",
770 [TCG_COND_NE
] = "ne",
771 [TCG_COND_LT
] = "lt",
772 [TCG_COND_GE
] = "ge",
773 [TCG_COND_LE
] = "le",
774 [TCG_COND_GT
] = "gt",
775 [TCG_COND_LTU
] = "ltu",
776 [TCG_COND_GEU
] = "geu",
777 [TCG_COND_LEU
] = "leu",
778 [TCG_COND_GTU
] = "gtu"
781 void tcg_dump_ops(TCGContext
*s
, FILE *outfile
)
783 const uint16_t *opc_ptr
;
786 int c
, i
, k
, nb_oargs
, nb_iargs
, nb_cargs
, first_insn
;
791 opc_ptr
= gen_opc_buf
;
792 args
= gen_opparam_buf
;
793 while (opc_ptr
< gen_opc_ptr
) {
795 def
= &tcg_op_defs
[c
];
796 if (c
== INDEX_op_debug_insn_start
) {
798 #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
799 pc
= ((uint64_t)args
[1] << 32) | args
[0];
804 fprintf(outfile
, "\n");
805 fprintf(outfile
, " ---- 0x%" PRIx64
, pc
);
807 nb_oargs
= def
->nb_oargs
;
808 nb_iargs
= def
->nb_iargs
;
809 nb_cargs
= def
->nb_cargs
;
810 } else if (c
== INDEX_op_call
) {
813 /* variable number of arguments */
815 nb_oargs
= arg
>> 16;
816 nb_iargs
= arg
& 0xffff;
817 nb_cargs
= def
->nb_cargs
;
819 fprintf(outfile
, " %s ", def
->name
);
822 fprintf(outfile
, "%s",
823 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[nb_oargs
+ nb_iargs
- 1]));
825 fprintf(outfile
, ",$0x%" TCG_PRIlx
,
826 args
[nb_oargs
+ nb_iargs
]);
828 fprintf(outfile
, ",$%d", nb_oargs
);
829 for(i
= 0; i
< nb_oargs
; i
++) {
830 fprintf(outfile
, ",");
831 fprintf(outfile
, "%s",
832 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[i
]));
834 for(i
= 0; i
< (nb_iargs
- 1); i
++) {
835 fprintf(outfile
, ",");
836 if (args
[nb_oargs
+ i
] == TCG_CALL_DUMMY_ARG
) {
837 fprintf(outfile
, "<dummy>");
839 fprintf(outfile
, "%s",
840 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[nb_oargs
+ i
]));
843 } else if (c
== INDEX_op_movi_i32
844 #if TCG_TARGET_REG_BITS == 64
845 || c
== INDEX_op_movi_i64
848 tcg_target_ulong val
;
851 nb_oargs
= def
->nb_oargs
;
852 nb_iargs
= def
->nb_iargs
;
853 nb_cargs
= def
->nb_cargs
;
854 fprintf(outfile
, " %s %s,$", def
->name
,
855 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[0]));
857 th
= tcg_find_helper(s
, val
);
859 fprintf(outfile
, "%s", th
->name
);
861 if (c
== INDEX_op_movi_i32
)
862 fprintf(outfile
, "0x%x", (uint32_t)val
);
864 fprintf(outfile
, "0x%" PRIx64
, (uint64_t)val
);
867 fprintf(outfile
, " %s ", def
->name
);
868 if (c
== INDEX_op_nopn
) {
869 /* variable number of arguments */
874 nb_oargs
= def
->nb_oargs
;
875 nb_iargs
= def
->nb_iargs
;
876 nb_cargs
= def
->nb_cargs
;
880 for(i
= 0; i
< nb_oargs
; i
++) {
882 fprintf(outfile
, ",");
883 fprintf(outfile
, "%s",
884 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[k
++]));
886 for(i
= 0; i
< nb_iargs
; i
++) {
888 fprintf(outfile
, ",");
889 fprintf(outfile
, "%s",
890 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[k
++]));
893 case INDEX_op_brcond_i32
:
894 #if TCG_TARGET_REG_BITS == 32
895 case INDEX_op_brcond2_i32
:
896 #elif TCG_TARGET_REG_BITS == 64
897 case INDEX_op_brcond_i64
:
899 case INDEX_op_setcond_i32
:
900 #if TCG_TARGET_REG_BITS == 32
901 case INDEX_op_setcond2_i32
:
902 #elif TCG_TARGET_REG_BITS == 64
903 case INDEX_op_setcond_i64
:
905 if (args
[k
] < ARRAY_SIZE(cond_name
) && cond_name
[args
[k
]])
906 fprintf(outfile
, ",%s", cond_name
[args
[k
++]]);
908 fprintf(outfile
, ",$0x%" TCG_PRIlx
, args
[k
++]);
915 for(; i
< nb_cargs
; i
++) {
917 fprintf(outfile
, ",");
919 fprintf(outfile
, "$0x%" TCG_PRIlx
, arg
);
922 fprintf(outfile
, "\n");
923 args
+= nb_iargs
+ nb_oargs
+ nb_cargs
;
927 /* we give more priority to constraints with less registers */
928 static int get_constraint_priority(const TCGOpDef
*def
, int k
)
930 const TCGArgConstraint
*arg_ct
;
933 arg_ct
= &def
->args_ct
[k
];
934 if (arg_ct
->ct
& TCG_CT_ALIAS
) {
935 /* an alias is equivalent to a single register */
938 if (!(arg_ct
->ct
& TCG_CT_REG
))
941 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
942 if (tcg_regset_test_reg(arg_ct
->u
.regs
, i
))
946 return TCG_TARGET_NB_REGS
- n
+ 1;
949 /* sort from highest priority to lowest */
950 static void sort_constraints(TCGOpDef
*def
, int start
, int n
)
952 int i
, j
, p1
, p2
, tmp
;
954 for(i
= 0; i
< n
; i
++)
955 def
->sorted_args
[start
+ i
] = start
+ i
;
958 for(i
= 0; i
< n
- 1; i
++) {
959 for(j
= i
+ 1; j
< n
; j
++) {
960 p1
= get_constraint_priority(def
, def
->sorted_args
[start
+ i
]);
961 p2
= get_constraint_priority(def
, def
->sorted_args
[start
+ j
]);
963 tmp
= def
->sorted_args
[start
+ i
];
964 def
->sorted_args
[start
+ i
] = def
->sorted_args
[start
+ j
];
965 def
->sorted_args
[start
+ j
] = tmp
;
971 void tcg_add_target_add_op_defs(const TCGTargetOpDef
*tdefs
)
982 assert(op
>= 0 && op
< NB_OPS
);
983 def
= &tcg_op_defs
[op
];
984 nb_args
= def
->nb_iargs
+ def
->nb_oargs
;
985 for(i
= 0; i
< nb_args
; i
++) {
986 ct_str
= tdefs
->args_ct_str
[i
];
987 tcg_regset_clear(def
->args_ct
[i
].u
.regs
);
988 def
->args_ct
[i
].ct
= 0;
989 if (ct_str
[0] >= '0' && ct_str
[0] <= '9') {
991 oarg
= ct_str
[0] - '0';
992 assert(oarg
< def
->nb_oargs
);
993 assert(def
->args_ct
[oarg
].ct
& TCG_CT_REG
);
994 /* TCG_CT_ALIAS is for the output arguments. The input
995 argument is tagged with TCG_CT_IALIAS. */
996 def
->args_ct
[i
] = def
->args_ct
[oarg
];
997 def
->args_ct
[oarg
].ct
= TCG_CT_ALIAS
;
998 def
->args_ct
[oarg
].alias_index
= i
;
999 def
->args_ct
[i
].ct
|= TCG_CT_IALIAS
;
1000 def
->args_ct
[i
].alias_index
= oarg
;
1003 if (*ct_str
== '\0')
1007 def
->args_ct
[i
].ct
|= TCG_CT_CONST
;
1011 if (target_parse_constraint(&def
->args_ct
[i
], &ct_str
) < 0) {
1012 fprintf(stderr
, "Invalid constraint '%s' for arg %d of operation '%s'\n",
1013 ct_str
, i
, def
->name
);
1021 /* sort the constraints (XXX: this is just an heuristic) */
1022 sort_constraints(def
, 0, def
->nb_oargs
);
1023 sort_constraints(def
, def
->nb_oargs
, def
->nb_iargs
);
1029 printf("%s: sorted=", def
->name
);
1030 for(i
= 0; i
< def
->nb_oargs
+ def
->nb_iargs
; i
++)
1031 printf(" %d", def
->sorted_args
[i
]);
1040 #ifdef USE_LIVENESS_ANALYSIS
1042 /* set a nop for an operation using 'nb_args' */
1043 static inline void tcg_set_nop(TCGContext
*s
, uint16_t *opc_ptr
,
1044 TCGArg
*args
, int nb_args
)
1047 *opc_ptr
= INDEX_op_nop
;
1049 *opc_ptr
= INDEX_op_nopn
;
1051 args
[nb_args
- 1] = nb_args
;
1055 /* liveness analysis: end of function: globals are live, temps are
1057 /* XXX: at this stage, not used as there would be little gains because
1058 most TBs end with a conditional jump. */
1059 static inline void tcg_la_func_end(TCGContext
*s
, uint8_t *dead_temps
)
1061 memset(dead_temps
, 0, s
->nb_globals
);
1062 memset(dead_temps
+ s
->nb_globals
, 1, s
->nb_temps
- s
->nb_globals
);
1065 /* liveness analysis: end of basic block: globals are live, temps are
1066 dead, local temps are live. */
1067 static inline void tcg_la_bb_end(TCGContext
*s
, uint8_t *dead_temps
)
1072 memset(dead_temps
, 0, s
->nb_globals
);
1073 ts
= &s
->temps
[s
->nb_globals
];
1074 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
1083 /* Liveness analysis : update the opc_dead_iargs array to tell if a
1084 given input arguments is dead. Instructions updating dead
1085 temporaries are removed. */
1086 static void tcg_liveness_analysis(TCGContext
*s
)
1088 int i
, op_index
, op
, nb_args
, nb_iargs
, nb_oargs
, arg
, nb_ops
;
1090 const TCGOpDef
*def
;
1091 uint8_t *dead_temps
;
1092 unsigned int dead_iargs
;
1094 gen_opc_ptr
++; /* skip end */
1096 nb_ops
= gen_opc_ptr
- gen_opc_buf
;
1098 s
->op_dead_iargs
= tcg_malloc(nb_ops
* sizeof(uint16_t));
1100 dead_temps
= tcg_malloc(s
->nb_temps
);
1101 memset(dead_temps
, 1, s
->nb_temps
);
1103 args
= gen_opparam_ptr
;
1104 op_index
= nb_ops
- 1;
1105 while (op_index
>= 0) {
1106 op
= gen_opc_buf
[op_index
];
1107 def
= &tcg_op_defs
[op
];
1115 nb_iargs
= args
[0] & 0xffff;
1116 nb_oargs
= args
[0] >> 16;
1118 call_flags
= args
[nb_oargs
+ nb_iargs
];
1120 /* pure functions can be removed if their result is not
1122 if (call_flags
& TCG_CALL_PURE
) {
1123 for(i
= 0; i
< nb_oargs
; i
++) {
1125 if (!dead_temps
[arg
])
1126 goto do_not_remove_call
;
1128 tcg_set_nop(s
, gen_opc_buf
+ op_index
,
1133 /* output args are dead */
1134 for(i
= 0; i
< nb_oargs
; i
++) {
1136 dead_temps
[arg
] = 1;
1139 if (!(call_flags
& TCG_CALL_CONST
)) {
1140 /* globals are live (they may be used by the call) */
1141 memset(dead_temps
, 0, s
->nb_globals
);
1144 /* input args are live */
1146 for(i
= 0; i
< nb_iargs
; i
++) {
1147 arg
= args
[i
+ nb_oargs
];
1148 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1149 if (dead_temps
[arg
]) {
1150 dead_iargs
|= (1 << i
);
1152 dead_temps
[arg
] = 0;
1155 s
->op_dead_iargs
[op_index
] = dead_iargs
;
1160 case INDEX_op_set_label
:
1162 /* mark end of basic block */
1163 tcg_la_bb_end(s
, dead_temps
);
1165 case INDEX_op_debug_insn_start
:
1166 args
-= def
->nb_args
;
1172 case INDEX_op_discard
:
1174 /* mark the temporary as dead */
1175 dead_temps
[args
[0]] = 1;
1179 /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1181 args
-= def
->nb_args
;
1182 nb_iargs
= def
->nb_iargs
;
1183 nb_oargs
= def
->nb_oargs
;
1185 /* Test if the operation can be removed because all
1186 its outputs are dead. We assume that nb_oargs == 0
1187 implies side effects */
1188 if (!(def
->flags
& TCG_OPF_SIDE_EFFECTS
) && nb_oargs
!= 0) {
1189 for(i
= 0; i
< nb_oargs
; i
++) {
1191 if (!dead_temps
[arg
])
1194 tcg_set_nop(s
, gen_opc_buf
+ op_index
, args
, def
->nb_args
);
1195 #ifdef CONFIG_PROFILER
1201 /* output args are dead */
1202 for(i
= 0; i
< nb_oargs
; i
++) {
1204 dead_temps
[arg
] = 1;
1207 /* if end of basic block, update */
1208 if (def
->flags
& TCG_OPF_BB_END
) {
1209 tcg_la_bb_end(s
, dead_temps
);
1210 } else if (def
->flags
& TCG_OPF_CALL_CLOBBER
) {
1211 /* globals are live */
1212 memset(dead_temps
, 0, s
->nb_globals
);
1215 /* input args are live */
1217 for(i
= 0; i
< nb_iargs
; i
++) {
1218 arg
= args
[i
+ nb_oargs
];
1219 if (dead_temps
[arg
]) {
1220 dead_iargs
|= (1 << i
);
1222 dead_temps
[arg
] = 0;
1224 s
->op_dead_iargs
[op_index
] = dead_iargs
;
1231 if (args
!= gen_opparam_buf
)
1235 /* dummy liveness analysis */
1236 void tcg_liveness_analysis(TCGContext
*s
)
1239 nb_ops
= gen_opc_ptr
- gen_opc_buf
;
1241 s
->op_dead_iargs
= tcg_malloc(nb_ops
* sizeof(uint16_t));
1242 memset(s
->op_dead_iargs
, 0, nb_ops
* sizeof(uint16_t));
1247 static void dump_regs(TCGContext
*s
)
1253 for(i
= 0; i
< s
->nb_temps
; i
++) {
1255 printf(" %10s: ", tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), i
));
1256 switch(ts
->val_type
) {
1258 printf("%s", tcg_target_reg_names
[ts
->reg
]);
1261 printf("%d(%s)", (int)ts
->mem_offset
, tcg_target_reg_names
[ts
->mem_reg
]);
1263 case TEMP_VAL_CONST
:
1264 printf("$0x%" TCG_PRIlx
, ts
->val
);
1276 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
1277 if (s
->reg_to_temp
[i
] >= 0) {
1279 tcg_target_reg_names
[i
],
1280 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), s
->reg_to_temp
[i
]));
1285 static void check_regs(TCGContext
*s
)
1291 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1292 k
= s
->reg_to_temp
[reg
];
1295 if (ts
->val_type
!= TEMP_VAL_REG
||
1297 printf("Inconsistency for register %s:\n",
1298 tcg_target_reg_names
[reg
]);
1303 for(k
= 0; k
< s
->nb_temps
; k
++) {
1305 if (ts
->val_type
== TEMP_VAL_REG
&&
1307 s
->reg_to_temp
[ts
->reg
] != k
) {
1308 printf("Inconsistency for temp %s:\n",
1309 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), k
));
1311 printf("reg state:\n");
1319 static void temp_allocate_frame(TCGContext
*s
, int temp
)
1322 ts
= &s
->temps
[temp
];
1323 s
->current_frame_offset
= (s
->current_frame_offset
+ sizeof(tcg_target_long
) - 1) & ~(sizeof(tcg_target_long
) - 1);
1324 if (s
->current_frame_offset
+ sizeof(tcg_target_long
) > s
->frame_end
)
1326 ts
->mem_offset
= s
->current_frame_offset
;
1327 ts
->mem_reg
= s
->frame_reg
;
1328 ts
->mem_allocated
= 1;
1329 s
->current_frame_offset
+= sizeof(tcg_target_long
);
1332 /* free register 'reg' by spilling the corresponding temporary if necessary */
1333 static void tcg_reg_free(TCGContext
*s
, int reg
)
1338 temp
= s
->reg_to_temp
[reg
];
1340 ts
= &s
->temps
[temp
];
1341 assert(ts
->val_type
== TEMP_VAL_REG
);
1342 if (!ts
->mem_coherent
) {
1343 if (!ts
->mem_allocated
)
1344 temp_allocate_frame(s
, temp
);
1345 tcg_out_st(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1347 ts
->val_type
= TEMP_VAL_MEM
;
1348 s
->reg_to_temp
[reg
] = -1;
1352 /* Allocate a register belonging to reg1 & ~reg2 */
1353 static int tcg_reg_alloc(TCGContext
*s
, TCGRegSet reg1
, TCGRegSet reg2
)
1358 tcg_regset_andnot(reg_ct
, reg1
, reg2
);
1360 /* first try free registers */
1361 for(i
= 0; i
< ARRAY_SIZE(tcg_target_reg_alloc_order
); i
++) {
1362 reg
= tcg_target_reg_alloc_order
[i
];
1363 if (tcg_regset_test_reg(reg_ct
, reg
) && s
->reg_to_temp
[reg
] == -1)
1367 /* XXX: do better spill choice */
1368 for(i
= 0; i
< ARRAY_SIZE(tcg_target_reg_alloc_order
); i
++) {
1369 reg
= tcg_target_reg_alloc_order
[i
];
1370 if (tcg_regset_test_reg(reg_ct
, reg
)) {
1371 tcg_reg_free(s
, reg
);
1379 /* save a temporary to memory. 'allocated_regs' is used in case a
1380 temporary registers needs to be allocated to store a constant. */
1381 static void temp_save(TCGContext
*s
, int temp
, TCGRegSet allocated_regs
)
1386 ts
= &s
->temps
[temp
];
1387 if (!ts
->fixed_reg
) {
1388 switch(ts
->val_type
) {
1390 tcg_reg_free(s
, ts
->reg
);
1393 ts
->val_type
= TEMP_VAL_MEM
;
1395 case TEMP_VAL_CONST
:
1396 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1398 if (!ts
->mem_allocated
)
1399 temp_allocate_frame(s
, temp
);
1400 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1401 tcg_out_st(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1402 ts
->val_type
= TEMP_VAL_MEM
;
1412 /* save globals to their cannonical location and assume they can be
1413 modified be the following code. 'allocated_regs' is used in case a
1414 temporary registers needs to be allocated to store a constant. */
1415 static void save_globals(TCGContext
*s
, TCGRegSet allocated_regs
)
1419 for(i
= 0; i
< s
->nb_globals
; i
++) {
1420 temp_save(s
, i
, allocated_regs
);
1424 /* at the end of a basic block, we assume all temporaries are dead and
1425 all globals are stored at their canonical location. */
1426 static void tcg_reg_alloc_bb_end(TCGContext
*s
, TCGRegSet allocated_regs
)
1431 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
1433 if (ts
->temp_local
) {
1434 temp_save(s
, i
, allocated_regs
);
1436 if (ts
->val_type
== TEMP_VAL_REG
) {
1437 s
->reg_to_temp
[ts
->reg
] = -1;
1439 ts
->val_type
= TEMP_VAL_DEAD
;
1443 save_globals(s
, allocated_regs
);
1446 #define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
1448 static void tcg_reg_alloc_movi(TCGContext
*s
, const TCGArg
*args
)
1451 tcg_target_ulong val
;
1453 ots
= &s
->temps
[args
[0]];
1456 if (ots
->fixed_reg
) {
1457 /* for fixed registers, we do not do any constant
1459 tcg_out_movi(s
, ots
->type
, ots
->reg
, val
);
1461 /* The movi is not explicitly generated here */
1462 if (ots
->val_type
== TEMP_VAL_REG
)
1463 s
->reg_to_temp
[ots
->reg
] = -1;
1464 ots
->val_type
= TEMP_VAL_CONST
;
1469 static void tcg_reg_alloc_mov(TCGContext
*s
, const TCGOpDef
*def
,
1471 unsigned int dead_iargs
)
1475 const TCGArgConstraint
*arg_ct
;
1477 ots
= &s
->temps
[args
[0]];
1478 ts
= &s
->temps
[args
[1]];
1479 arg_ct
= &def
->args_ct
[0];
1481 /* XXX: always mark arg dead if IS_DEAD_IARG(0) */
1482 if (ts
->val_type
== TEMP_VAL_REG
) {
1483 if (IS_DEAD_IARG(0) && !ts
->fixed_reg
&& !ots
->fixed_reg
) {
1484 /* the mov can be suppressed */
1485 if (ots
->val_type
== TEMP_VAL_REG
)
1486 s
->reg_to_temp
[ots
->reg
] = -1;
1488 s
->reg_to_temp
[reg
] = -1;
1489 ts
->val_type
= TEMP_VAL_DEAD
;
1491 if (ots
->val_type
== TEMP_VAL_REG
) {
1494 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, s
->reserved_regs
);
1496 if (ts
->reg
!= reg
) {
1497 tcg_out_mov(s
, reg
, ts
->reg
);
1500 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1501 if (ots
->val_type
== TEMP_VAL_REG
) {
1504 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, s
->reserved_regs
);
1506 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1507 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1508 if (ots
->fixed_reg
) {
1510 tcg_out_movi(s
, ots
->type
, reg
, ts
->val
);
1512 /* propagate constant */
1513 if (ots
->val_type
== TEMP_VAL_REG
)
1514 s
->reg_to_temp
[ots
->reg
] = -1;
1515 ots
->val_type
= TEMP_VAL_CONST
;
1522 s
->reg_to_temp
[reg
] = args
[0];
1524 ots
->val_type
= TEMP_VAL_REG
;
1525 ots
->mem_coherent
= 0;
1528 static void tcg_reg_alloc_op(TCGContext
*s
,
1529 const TCGOpDef
*def
, int opc
,
1531 unsigned int dead_iargs
)
1533 TCGRegSet allocated_regs
;
1534 int i
, k
, nb_iargs
, nb_oargs
, reg
;
1536 const TCGArgConstraint
*arg_ct
;
1538 TCGArg new_args
[TCG_MAX_OP_ARGS
];
1539 int const_args
[TCG_MAX_OP_ARGS
];
1541 nb_oargs
= def
->nb_oargs
;
1542 nb_iargs
= def
->nb_iargs
;
1544 /* copy constants */
1545 memcpy(new_args
+ nb_oargs
+ nb_iargs
,
1546 args
+ nb_oargs
+ nb_iargs
,
1547 sizeof(TCGArg
) * def
->nb_cargs
);
1549 /* satisfy input constraints */
1550 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1551 for(k
= 0; k
< nb_iargs
; k
++) {
1552 i
= def
->sorted_args
[nb_oargs
+ k
];
1554 arg_ct
= &def
->args_ct
[i
];
1555 ts
= &s
->temps
[arg
];
1556 if (ts
->val_type
== TEMP_VAL_MEM
) {
1557 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1558 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1559 ts
->val_type
= TEMP_VAL_REG
;
1561 ts
->mem_coherent
= 1;
1562 s
->reg_to_temp
[reg
] = arg
;
1563 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1564 if (tcg_target_const_match(ts
->val
, arg_ct
)) {
1565 /* constant is OK for instruction */
1567 new_args
[i
] = ts
->val
;
1570 /* need to move to a register */
1571 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1572 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1573 ts
->val_type
= TEMP_VAL_REG
;
1575 ts
->mem_coherent
= 0;
1576 s
->reg_to_temp
[reg
] = arg
;
1579 assert(ts
->val_type
== TEMP_VAL_REG
);
1580 if (arg_ct
->ct
& TCG_CT_IALIAS
) {
1581 if (ts
->fixed_reg
) {
1582 /* if fixed register, we must allocate a new register
1583 if the alias is not the same register */
1584 if (arg
!= args
[arg_ct
->alias_index
])
1585 goto allocate_in_reg
;
1587 /* if the input is aliased to an output and if it is
1588 not dead after the instruction, we must allocate
1589 a new register and move it */
1590 if (!IS_DEAD_IARG(i
- nb_oargs
))
1591 goto allocate_in_reg
;
1595 if (tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1596 /* nothing to do : the constraint is satisfied */
1599 /* allocate a new register matching the constraint
1600 and move the temporary register into it */
1601 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1602 tcg_out_mov(s
, reg
, ts
->reg
);
1606 tcg_regset_set_reg(allocated_regs
, reg
);
1610 if (def
->flags
& TCG_OPF_BB_END
) {
1611 tcg_reg_alloc_bb_end(s
, allocated_regs
);
1613 /* mark dead temporaries and free the associated registers */
1614 for(i
= 0; i
< nb_iargs
; i
++) {
1615 arg
= args
[nb_oargs
+ i
];
1616 if (IS_DEAD_IARG(i
)) {
1617 ts
= &s
->temps
[arg
];
1618 if (!ts
->fixed_reg
) {
1619 if (ts
->val_type
== TEMP_VAL_REG
)
1620 s
->reg_to_temp
[ts
->reg
] = -1;
1621 ts
->val_type
= TEMP_VAL_DEAD
;
1626 if (def
->flags
& TCG_OPF_CALL_CLOBBER
) {
1627 /* XXX: permit generic clobber register list ? */
1628 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1629 if (tcg_regset_test_reg(tcg_target_call_clobber_regs
, reg
)) {
1630 tcg_reg_free(s
, reg
);
1633 /* XXX: for load/store we could do that only for the slow path
1634 (i.e. when a memory callback is called) */
1636 /* store globals and free associated registers (we assume the insn
1637 can modify any global. */
1638 save_globals(s
, allocated_regs
);
1641 /* satisfy the output constraints */
1642 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1643 for(k
= 0; k
< nb_oargs
; k
++) {
1644 i
= def
->sorted_args
[k
];
1646 arg_ct
= &def
->args_ct
[i
];
1647 ts
= &s
->temps
[arg
];
1648 if (arg_ct
->ct
& TCG_CT_ALIAS
) {
1649 reg
= new_args
[arg_ct
->alias_index
];
1651 /* if fixed register, we try to use it */
1653 if (ts
->fixed_reg
&&
1654 tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1657 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1659 tcg_regset_set_reg(allocated_regs
, reg
);
1660 /* if a fixed register is used, then a move will be done afterwards */
1661 if (!ts
->fixed_reg
) {
1662 if (ts
->val_type
== TEMP_VAL_REG
)
1663 s
->reg_to_temp
[ts
->reg
] = -1;
1664 ts
->val_type
= TEMP_VAL_REG
;
1666 /* temp value is modified, so the value kept in memory is
1667 potentially not the same */
1668 ts
->mem_coherent
= 0;
1669 s
->reg_to_temp
[reg
] = arg
;
1676 /* emit instruction */
1677 tcg_out_op(s
, opc
, new_args
, const_args
);
1679 /* move the outputs in the correct register if needed */
1680 for(i
= 0; i
< nb_oargs
; i
++) {
1681 ts
= &s
->temps
[args
[i
]];
1683 if (ts
->fixed_reg
&& ts
->reg
!= reg
) {
1684 tcg_out_mov(s
, ts
->reg
, reg
);
1689 #ifdef TCG_TARGET_STACK_GROWSUP
1690 #define STACK_DIR(x) (-(x))
1692 #define STACK_DIR(x) (x)
1695 static int tcg_reg_alloc_call(TCGContext
*s
, const TCGOpDef
*def
,
1696 int opc
, const TCGArg
*args
,
1697 unsigned int dead_iargs
)
1699 int nb_iargs
, nb_oargs
, flags
, nb_regs
, i
, reg
, nb_params
;
1700 TCGArg arg
, func_arg
;
1702 tcg_target_long stack_offset
, call_stack_size
, func_addr
;
1703 int const_func_arg
, allocate_args
;
1704 TCGRegSet allocated_regs
;
1705 const TCGArgConstraint
*arg_ct
;
1709 nb_oargs
= arg
>> 16;
1710 nb_iargs
= arg
& 0xffff;
1711 nb_params
= nb_iargs
- 1;
1713 flags
= args
[nb_oargs
+ nb_iargs
];
1715 nb_regs
= tcg_target_get_call_iarg_regs_count(flags
);
1716 if (nb_regs
> nb_params
)
1717 nb_regs
= nb_params
;
1719 /* assign stack slots first */
1720 /* XXX: preallocate call stack */
1721 call_stack_size
= (nb_params
- nb_regs
) * sizeof(tcg_target_long
);
1722 call_stack_size
= (call_stack_size
+ TCG_TARGET_STACK_ALIGN
- 1) &
1723 ~(TCG_TARGET_STACK_ALIGN
- 1);
1724 allocate_args
= (call_stack_size
> TCG_STATIC_CALL_ARGS_SIZE
);
1725 if (allocate_args
) {
1726 tcg_out_addi(s
, TCG_REG_CALL_STACK
, -STACK_DIR(call_stack_size
));
1729 stack_offset
= TCG_TARGET_CALL_STACK_OFFSET
;
1730 for(i
= nb_regs
; i
< nb_params
; i
++) {
1731 arg
= args
[nb_oargs
+ i
];
1732 #ifdef TCG_TARGET_STACK_GROWSUP
1733 stack_offset
-= sizeof(tcg_target_long
);
1735 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1736 ts
= &s
->temps
[arg
];
1737 if (ts
->val_type
== TEMP_VAL_REG
) {
1738 tcg_out_st(s
, ts
->type
, ts
->reg
, TCG_REG_CALL_STACK
, stack_offset
);
1739 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1740 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1742 /* XXX: not correct if reading values from the stack */
1743 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1744 tcg_out_st(s
, ts
->type
, reg
, TCG_REG_CALL_STACK
, stack_offset
);
1745 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1746 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1748 /* XXX: sign extend may be needed on some targets */
1749 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1750 tcg_out_st(s
, ts
->type
, reg
, TCG_REG_CALL_STACK
, stack_offset
);
1755 #ifndef TCG_TARGET_STACK_GROWSUP
1756 stack_offset
+= sizeof(tcg_target_long
);
1760 /* assign input registers */
1761 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1762 for(i
= 0; i
< nb_regs
; i
++) {
1763 arg
= args
[nb_oargs
+ i
];
1764 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1765 ts
= &s
->temps
[arg
];
1766 reg
= tcg_target_call_iarg_regs
[i
];
1767 tcg_reg_free(s
, reg
);
1768 if (ts
->val_type
== TEMP_VAL_REG
) {
1769 if (ts
->reg
!= reg
) {
1770 tcg_out_mov(s
, reg
, ts
->reg
);
1772 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1773 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1774 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1775 /* XXX: sign extend ? */
1776 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1780 tcg_regset_set_reg(allocated_regs
, reg
);
1784 /* assign function address */
1785 func_arg
= args
[nb_oargs
+ nb_iargs
- 1];
1786 arg_ct
= &def
->args_ct
[0];
1787 ts
= &s
->temps
[func_arg
];
1788 func_addr
= ts
->val
;
1790 if (ts
->val_type
== TEMP_VAL_MEM
) {
1791 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1792 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1794 tcg_regset_set_reg(allocated_regs
, reg
);
1795 } else if (ts
->val_type
== TEMP_VAL_REG
) {
1797 if (!tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1798 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1799 tcg_out_mov(s
, reg
, ts
->reg
);
1802 tcg_regset_set_reg(allocated_regs
, reg
);
1803 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1804 if (tcg_target_const_match(func_addr
, arg_ct
)) {
1806 func_arg
= func_addr
;
1808 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1809 tcg_out_movi(s
, ts
->type
, reg
, func_addr
);
1811 tcg_regset_set_reg(allocated_regs
, reg
);
1818 /* mark dead temporaries and free the associated registers */
1819 for(i
= 0; i
< nb_iargs
; i
++) {
1820 arg
= args
[nb_oargs
+ i
];
1821 if (IS_DEAD_IARG(i
)) {
1822 ts
= &s
->temps
[arg
];
1823 if (!ts
->fixed_reg
) {
1824 if (ts
->val_type
== TEMP_VAL_REG
)
1825 s
->reg_to_temp
[ts
->reg
] = -1;
1826 ts
->val_type
= TEMP_VAL_DEAD
;
1831 /* clobber call registers */
1832 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1833 if (tcg_regset_test_reg(tcg_target_call_clobber_regs
, reg
)) {
1834 tcg_reg_free(s
, reg
);
1838 /* store globals and free associated registers (we assume the call
1839 can modify any global. */
1840 if (!(flags
& TCG_CALL_CONST
)) {
1841 save_globals(s
, allocated_regs
);
1844 tcg_out_op(s
, opc
, &func_arg
, &const_func_arg
);
1846 if (allocate_args
) {
1847 tcg_out_addi(s
, TCG_REG_CALL_STACK
, STACK_DIR(call_stack_size
));
1850 /* assign output registers and emit moves if needed */
1851 for(i
= 0; i
< nb_oargs
; i
++) {
1853 ts
= &s
->temps
[arg
];
1854 reg
= tcg_target_call_oarg_regs
[i
];
1855 assert(s
->reg_to_temp
[reg
] == -1);
1856 if (ts
->fixed_reg
) {
1857 if (ts
->reg
!= reg
) {
1858 tcg_out_mov(s
, ts
->reg
, reg
);
1861 if (ts
->val_type
== TEMP_VAL_REG
)
1862 s
->reg_to_temp
[ts
->reg
] = -1;
1863 ts
->val_type
= TEMP_VAL_REG
;
1865 ts
->mem_coherent
= 0;
1866 s
->reg_to_temp
[reg
] = arg
;
1870 return nb_iargs
+ nb_oargs
+ def
->nb_cargs
+ 1;
1873 #ifdef CONFIG_PROFILER
1875 static int64_t tcg_table_op_count
[NB_OPS
];
1877 static void dump_op_count(void)
1881 f
= fopen("/tmp/op.log", "w");
1882 for(i
= INDEX_op_end
; i
< NB_OPS
; i
++) {
1883 fprintf(f
, "%s %" PRId64
"\n", tcg_op_defs
[i
].name
, tcg_table_op_count
[i
]);
1890 static inline int tcg_gen_code_common(TCGContext
*s
, uint8_t *gen_code_buf
,
1894 const TCGOpDef
*def
;
1895 unsigned int dead_iargs
;
1899 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP
))) {
1901 tcg_dump_ops(s
, logfile
);
1906 #ifdef CONFIG_PROFILER
1907 s
->la_time
-= profile_getclock();
1909 tcg_liveness_analysis(s
);
1910 #ifdef CONFIG_PROFILER
1911 s
->la_time
+= profile_getclock();
1915 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT
))) {
1916 qemu_log("OP after liveness analysis:\n");
1917 tcg_dump_ops(s
, logfile
);
1922 tcg_reg_alloc_start(s
);
1924 s
->code_buf
= gen_code_buf
;
1925 s
->code_ptr
= gen_code_buf
;
1927 args
= gen_opparam_buf
;
1931 opc
= gen_opc_buf
[op_index
];
1932 #ifdef CONFIG_PROFILER
1933 tcg_table_op_count
[opc
]++;
1935 def
= &tcg_op_defs
[opc
];
1937 printf("%s: %d %d %d\n", def
->name
,
1938 def
->nb_oargs
, def
->nb_iargs
, def
->nb_cargs
);
1942 case INDEX_op_mov_i32
:
1943 #if TCG_TARGET_REG_BITS == 64
1944 case INDEX_op_mov_i64
:
1946 dead_iargs
= s
->op_dead_iargs
[op_index
];
1947 tcg_reg_alloc_mov(s
, def
, args
, dead_iargs
);
1949 case INDEX_op_movi_i32
:
1950 #if TCG_TARGET_REG_BITS == 64
1951 case INDEX_op_movi_i64
:
1953 tcg_reg_alloc_movi(s
, args
);
1955 case INDEX_op_debug_insn_start
:
1956 /* debug instruction */
1966 case INDEX_op_discard
:
1969 ts
= &s
->temps
[args
[0]];
1970 /* mark the temporary as dead */
1971 if (!ts
->fixed_reg
) {
1972 if (ts
->val_type
== TEMP_VAL_REG
)
1973 s
->reg_to_temp
[ts
->reg
] = -1;
1974 ts
->val_type
= TEMP_VAL_DEAD
;
1978 case INDEX_op_set_label
:
1979 tcg_reg_alloc_bb_end(s
, s
->reserved_regs
);
1980 tcg_out_label(s
, args
[0], (long)s
->code_ptr
);
1983 dead_iargs
= s
->op_dead_iargs
[op_index
];
1984 args
+= tcg_reg_alloc_call(s
, def
, opc
, args
, dead_iargs
);
1989 /* Note: in order to speed up the code, it would be much
1990 faster to have specialized register allocator functions for
1991 some common argument patterns */
1992 dead_iargs
= s
->op_dead_iargs
[op_index
];
1993 tcg_reg_alloc_op(s
, def
, opc
, args
, dead_iargs
);
1996 args
+= def
->nb_args
;
1998 if (search_pc
>= 0 && search_pc
< s
->code_ptr
- gen_code_buf
) {
2010 int tcg_gen_code(TCGContext
*s
, uint8_t *gen_code_buf
)
2012 #ifdef CONFIG_PROFILER
2015 n
= (gen_opc_ptr
- gen_opc_buf
);
2017 if (n
> s
->op_count_max
)
2018 s
->op_count_max
= n
;
2020 s
->temp_count
+= s
->nb_temps
;
2021 if (s
->nb_temps
> s
->temp_count_max
)
2022 s
->temp_count_max
= s
->nb_temps
;
2026 tcg_gen_code_common(s
, gen_code_buf
, -1);
2028 /* flush instruction cache */
2029 flush_icache_range((unsigned long)gen_code_buf
,
2030 (unsigned long)s
->code_ptr
);
2031 return s
->code_ptr
- gen_code_buf
;
2034 /* Return the index of the micro operation such as the pc after is <
2035 offset bytes from the start of the TB. The contents of gen_code_buf must
2036 not be changed, though writing the same values is ok.
2037 Return -1 if not found. */
2038 int tcg_gen_code_search_pc(TCGContext
*s
, uint8_t *gen_code_buf
, long offset
)
2040 return tcg_gen_code_common(s
, gen_code_buf
, offset
);
2043 #ifdef CONFIG_PROFILER
2044 void tcg_dump_info(FILE *f
,
2045 int (*cpu_fprintf
)(FILE *f
, const char *fmt
, ...))
2047 TCGContext
*s
= &tcg_ctx
;
2050 tot
= s
->interm_time
+ s
->code_time
;
2051 cpu_fprintf(f
, "JIT cycles %" PRId64
" (%0.3f s at 2.4 GHz)\n",
2053 cpu_fprintf(f
, "translated TBs %" PRId64
" (aborted=%" PRId64
" %0.1f%%)\n",
2055 s
->tb_count1
- s
->tb_count
,
2056 s
->tb_count1
? (double)(s
->tb_count1
- s
->tb_count
) / s
->tb_count1
* 100.0 : 0);
2057 cpu_fprintf(f
, "avg ops/TB %0.1f max=%d\n",
2058 s
->tb_count
? (double)s
->op_count
/ s
->tb_count
: 0, s
->op_count_max
);
2059 cpu_fprintf(f
, "deleted ops/TB %0.2f\n",
2061 (double)s
->del_op_count
/ s
->tb_count
: 0);
2062 cpu_fprintf(f
, "avg temps/TB %0.2f max=%d\n",
2064 (double)s
->temp_count
/ s
->tb_count
: 0,
2067 cpu_fprintf(f
, "cycles/op %0.1f\n",
2068 s
->op_count
? (double)tot
/ s
->op_count
: 0);
2069 cpu_fprintf(f
, "cycles/in byte %0.1f\n",
2070 s
->code_in_len
? (double)tot
/ s
->code_in_len
: 0);
2071 cpu_fprintf(f
, "cycles/out byte %0.1f\n",
2072 s
->code_out_len
? (double)tot
/ s
->code_out_len
: 0);
2075 cpu_fprintf(f
, " gen_interm time %0.1f%%\n",
2076 (double)s
->interm_time
/ tot
* 100.0);
2077 cpu_fprintf(f
, " gen_code time %0.1f%%\n",
2078 (double)s
->code_time
/ tot
* 100.0);
2079 cpu_fprintf(f
, "liveness/code time %0.1f%%\n",
2080 (double)s
->la_time
/ (s
->code_time
? s
->code_time
: 1) * 100.0);
2081 cpu_fprintf(f
, "cpu_restore count %" PRId64
"\n",
2083 cpu_fprintf(f
, " avg cycles %0.1f\n",
2084 s
->restore_count
? (double)s
->restore_time
/ s
->restore_count
: 0);
2089 void tcg_dump_info(FILE *f
,
2090 int (*cpu_fprintf
)(FILE *f
, const char *fmt
, ...))
2092 cpu_fprintf(f
, "[TCG profiler not compiled]\n");