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 suppress various consistency checks (faster) */
28 /* define it to use liveness analysis (better code) */
29 #define USE_LIVENESS_ANALYSIS
42 #include "qemu-common.h"
44 /* Note: the long term plan is to reduce the dependancies on the QEMU
45 CPU definitions. Currently they are used for qemu_ld/st
47 #define NO_CPU_IO_DEFS
55 static void patch_reloc(uint8_t *code_ptr
, int type
,
56 tcg_target_long value
, tcg_target_long addend
);
58 TCGOpDef tcg_op_defs
[] = {
59 #define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size },
60 #define DEF2(s, iargs, oargs, cargs, flags) { #s, iargs, oargs, cargs, iargs + oargs + cargs, flags, 0 },
66 static TCGRegSet tcg_target_available_regs
[2];
67 static TCGRegSet tcg_target_call_clobber_regs
;
69 /* XXX: move that inside the context */
70 uint16_t *gen_opc_ptr
;
71 TCGArg
*gen_opparam_ptr
;
73 static inline void tcg_out8(TCGContext
*s
, uint8_t v
)
78 static inline void tcg_out16(TCGContext
*s
, uint16_t v
)
80 *(uint16_t *)s
->code_ptr
= v
;
84 static inline void tcg_out32(TCGContext
*s
, uint32_t v
)
86 *(uint32_t *)s
->code_ptr
= v
;
90 /* label relocation processing */
92 void tcg_out_reloc(TCGContext
*s
, uint8_t *code_ptr
, int type
,
93 int label_index
, long addend
)
98 l
= &s
->labels
[label_index
];
100 /* FIXME: This may break relocations on RISC targets that
101 modify instruction fields in place. The caller may not have
102 written the initial value. */
103 patch_reloc(code_ptr
, type
, l
->u
.value
, addend
);
105 /* add a new relocation entry */
106 r
= tcg_malloc(sizeof(TCGRelocation
));
110 r
->next
= l
->u
.first_reloc
;
111 l
->u
.first_reloc
= r
;
115 static void tcg_out_label(TCGContext
*s
, int label_index
,
116 tcg_target_long value
)
121 l
= &s
->labels
[label_index
];
124 r
= l
->u
.first_reloc
;
126 patch_reloc(r
->ptr
, r
->type
, value
, r
->addend
);
133 int gen_new_label(void)
135 TCGContext
*s
= &tcg_ctx
;
139 if (s
->nb_labels
>= TCG_MAX_LABELS
)
141 idx
= s
->nb_labels
++;
144 l
->u
.first_reloc
= NULL
;
148 #include "tcg-target.c"
150 /* pool based memory allocation */
151 void *tcg_malloc_internal(TCGContext
*s
, int size
)
156 if (size
> TCG_POOL_CHUNK_SIZE
) {
157 /* big malloc: insert a new pool (XXX: could optimize) */
158 p
= qemu_malloc(sizeof(TCGPool
) + size
);
161 s
->pool_current
->next
= p
;
164 p
->next
= s
->pool_current
;
174 pool_size
= TCG_POOL_CHUNK_SIZE
;
175 p
= qemu_malloc(sizeof(TCGPool
) + pool_size
);
179 s
->pool_current
->next
= p
;
188 s
->pool_cur
= p
->data
+ size
;
189 s
->pool_end
= p
->data
+ p
->size
;
193 void tcg_pool_reset(TCGContext
*s
)
195 s
->pool_cur
= s
->pool_end
= NULL
;
196 s
->pool_current
= NULL
;
199 void tcg_context_init(TCGContext
*s
)
201 int op
, total_args
, n
;
203 TCGArgConstraint
*args_ct
;
206 memset(s
, 0, sizeof(*s
));
207 s
->temps
= s
->static_temps
;
210 /* Count total number of arguments and allocate the corresponding
213 for(op
= 0; op
< NB_OPS
; op
++) {
214 def
= &tcg_op_defs
[op
];
215 n
= def
->nb_iargs
+ def
->nb_oargs
;
219 args_ct
= qemu_malloc(sizeof(TCGArgConstraint
) * total_args
);
220 sorted_args
= qemu_malloc(sizeof(int) * total_args
);
222 for(op
= 0; op
< NB_OPS
; op
++) {
223 def
= &tcg_op_defs
[op
];
224 def
->args_ct
= args_ct
;
225 def
->sorted_args
= sorted_args
;
226 n
= def
->nb_iargs
+ def
->nb_oargs
;
233 /* init global prologue and epilogue */
234 s
->code_buf
= code_gen_prologue
;
235 s
->code_ptr
= s
->code_buf
;
236 tcg_target_qemu_prologue(s
);
237 flush_icache_range((unsigned long)s
->code_buf
,
238 (unsigned long)s
->code_ptr
);
241 void tcg_set_frame(TCGContext
*s
, int reg
,
242 tcg_target_long start
, tcg_target_long size
)
244 s
->frame_start
= start
;
245 s
->frame_end
= start
+ size
;
249 void tcg_func_start(TCGContext
*s
)
253 s
->nb_temps
= s
->nb_globals
;
254 for(i
= 0; i
< (TCG_TYPE_COUNT
* 2); i
++)
255 s
->first_free_temp
[i
] = -1;
256 s
->labels
= tcg_malloc(sizeof(TCGLabel
) * TCG_MAX_LABELS
);
258 s
->current_frame_offset
= s
->frame_start
;
260 gen_opc_ptr
= gen_opc_buf
;
261 gen_opparam_ptr
= gen_opparam_buf
;
264 static inline void tcg_temp_alloc(TCGContext
*s
, int n
)
266 if (n
> TCG_MAX_TEMPS
)
270 static inline int tcg_global_reg_new_internal(TCGType type
, int reg
,
273 TCGContext
*s
= &tcg_ctx
;
277 #if TCG_TARGET_REG_BITS == 32
278 if (type
!= TCG_TYPE_I32
)
281 if (tcg_regset_test_reg(s
->reserved_regs
, reg
))
284 tcg_temp_alloc(s
, s
->nb_globals
+ 1);
285 ts
= &s
->temps
[s
->nb_globals
];
286 ts
->base_type
= type
;
292 tcg_regset_set_reg(s
->reserved_regs
, reg
);
296 TCGv_i32
tcg_global_reg_new_i32(int reg
, const char *name
)
300 idx
= tcg_global_reg_new_internal(TCG_TYPE_I32
, reg
, name
);
301 return MAKE_TCGV_I32(idx
);
304 TCGv_i64
tcg_global_reg_new_i64(int reg
, const char *name
)
308 idx
= tcg_global_reg_new_internal(TCG_TYPE_I64
, reg
, name
);
309 return MAKE_TCGV_I64(idx
);
312 #if TCG_TARGET_REG_BITS == 32
313 /* temporary hack to avoid register shortage for tcg_qemu_st64() */
314 TCGv_i64
tcg_global_reg2_new_hack(TCGType type
, int reg1
, int reg2
,
317 TCGContext
*s
= &tcg_ctx
;
322 if (type
!= TCG_TYPE_I64
)
325 tcg_temp_alloc(s
, s
->nb_globals
+ 2);
326 ts
= &s
->temps
[s
->nb_globals
];
327 ts
->base_type
= type
;
328 ts
->type
= TCG_TYPE_I32
;
331 pstrcpy(buf
, sizeof(buf
), name
);
332 pstrcat(buf
, sizeof(buf
), "_0");
333 ts
->name
= strdup(buf
);
336 ts
->base_type
= type
;
337 ts
->type
= TCG_TYPE_I32
;
340 pstrcpy(buf
, sizeof(buf
), name
);
341 pstrcat(buf
, sizeof(buf
), "_1");
342 ts
->name
= strdup(buf
);
345 return MAKE_TCGV_I64(idx
);
349 static inline int tcg_global_mem_new_internal(TCGType type
, int reg
,
350 tcg_target_long offset
,
353 TCGContext
*s
= &tcg_ctx
;
358 #if TCG_TARGET_REG_BITS == 32
359 if (type
== TCG_TYPE_I64
) {
361 tcg_temp_alloc(s
, s
->nb_globals
+ 2);
362 ts
= &s
->temps
[s
->nb_globals
];
363 ts
->base_type
= type
;
364 ts
->type
= TCG_TYPE_I32
;
366 ts
->mem_allocated
= 1;
368 #ifdef TCG_TARGET_WORDS_BIGENDIAN
369 ts
->mem_offset
= offset
+ 4;
371 ts
->mem_offset
= offset
;
373 pstrcpy(buf
, sizeof(buf
), name
);
374 pstrcat(buf
, sizeof(buf
), "_0");
375 ts
->name
= strdup(buf
);
378 ts
->base_type
= type
;
379 ts
->type
= TCG_TYPE_I32
;
381 ts
->mem_allocated
= 1;
383 #ifdef TCG_TARGET_WORDS_BIGENDIAN
384 ts
->mem_offset
= offset
;
386 ts
->mem_offset
= offset
+ 4;
388 pstrcpy(buf
, sizeof(buf
), name
);
389 pstrcat(buf
, sizeof(buf
), "_1");
390 ts
->name
= strdup(buf
);
396 tcg_temp_alloc(s
, s
->nb_globals
+ 1);
397 ts
= &s
->temps
[s
->nb_globals
];
398 ts
->base_type
= type
;
401 ts
->mem_allocated
= 1;
403 ts
->mem_offset
= offset
;
410 TCGv_i32
tcg_global_mem_new_i32(int reg
, tcg_target_long offset
,
415 idx
= tcg_global_mem_new_internal(TCG_TYPE_I32
, reg
, offset
, name
);
416 return MAKE_TCGV_I32(idx
);
419 TCGv_i64
tcg_global_mem_new_i64(int reg
, tcg_target_long offset
,
424 idx
= tcg_global_mem_new_internal(TCG_TYPE_I64
, reg
, offset
, name
);
425 return MAKE_TCGV_I64(idx
);
428 static inline int tcg_temp_new_internal(TCGType type
, int temp_local
)
430 TCGContext
*s
= &tcg_ctx
;
437 idx
= s
->first_free_temp
[k
];
439 /* There is already an available temp with the
442 s
->first_free_temp
[k
] = ts
->next_free_temp
;
443 ts
->temp_allocated
= 1;
444 assert(ts
->temp_local
== temp_local
);
447 #if TCG_TARGET_REG_BITS == 32
448 if (type
== TCG_TYPE_I64
) {
449 tcg_temp_alloc(s
, s
->nb_temps
+ 2);
450 ts
= &s
->temps
[s
->nb_temps
];
451 ts
->base_type
= type
;
452 ts
->type
= TCG_TYPE_I32
;
453 ts
->temp_allocated
= 1;
454 ts
->temp_local
= temp_local
;
457 ts
->base_type
= TCG_TYPE_I32
;
458 ts
->type
= TCG_TYPE_I32
;
459 ts
->temp_allocated
= 1;
460 ts
->temp_local
= temp_local
;
466 tcg_temp_alloc(s
, s
->nb_temps
+ 1);
467 ts
= &s
->temps
[s
->nb_temps
];
468 ts
->base_type
= type
;
470 ts
->temp_allocated
= 1;
471 ts
->temp_local
= temp_local
;
479 TCGv_i32
tcg_temp_new_internal_i32(int temp_local
)
483 idx
= tcg_temp_new_internal(TCG_TYPE_I32
, temp_local
);
484 return MAKE_TCGV_I32(idx
);
487 TCGv_i64
tcg_temp_new_internal_i64(int temp_local
)
491 idx
= tcg_temp_new_internal(TCG_TYPE_I64
, temp_local
);
492 return MAKE_TCGV_I64(idx
);
495 static inline void tcg_temp_free_internal(int idx
)
497 TCGContext
*s
= &tcg_ctx
;
501 assert(idx
>= s
->nb_globals
&& idx
< s
->nb_temps
);
503 assert(ts
->temp_allocated
!= 0);
504 ts
->temp_allocated
= 0;
508 ts
->next_free_temp
= s
->first_free_temp
[k
];
509 s
->first_free_temp
[k
] = idx
;
512 void tcg_temp_free_i32(TCGv_i32 arg
)
514 tcg_temp_free_internal(GET_TCGV_I32(arg
));
517 void tcg_temp_free_i64(TCGv_i64 arg
)
519 tcg_temp_free_internal(GET_TCGV_I64(arg
));
522 TCGv_i32
tcg_const_i32(int32_t val
)
525 t0
= tcg_temp_new_i32();
526 tcg_gen_movi_i32(t0
, val
);
530 TCGv_i64
tcg_const_i64(int64_t val
)
533 t0
= tcg_temp_new_i64();
534 tcg_gen_movi_i64(t0
, val
);
538 TCGv_i32
tcg_const_local_i32(int32_t val
)
541 t0
= tcg_temp_local_new_i32();
542 tcg_gen_movi_i32(t0
, val
);
546 TCGv_i64
tcg_const_local_i64(int64_t val
)
549 t0
= tcg_temp_local_new_i64();
550 tcg_gen_movi_i64(t0
, val
);
554 void tcg_register_helper(void *func
, const char *name
)
556 TCGContext
*s
= &tcg_ctx
;
558 if ((s
->nb_helpers
+ 1) > s
->allocated_helpers
) {
559 n
= s
->allocated_helpers
;
565 s
->helpers
= realloc(s
->helpers
, n
* sizeof(TCGHelperInfo
));
566 s
->allocated_helpers
= n
;
568 s
->helpers
[s
->nb_helpers
].func
= (tcg_target_ulong
)func
;
569 s
->helpers
[s
->nb_helpers
].name
= name
;
573 /* Note: we convert the 64 bit args to 32 bit and do some alignment
574 and endian swap. Maybe it would be better to do the alignment
575 and endian swap in tcg_reg_alloc_call(). */
576 void tcg_gen_callN(TCGContext
*s
, TCGv_ptr func
, unsigned int flags
,
577 int sizemask
, TCGArg ret
, int nargs
, TCGArg
*args
)
584 *gen_opc_ptr
++ = INDEX_op_call
;
585 nparam
= gen_opparam_ptr
++;
586 call_type
= (flags
& TCG_CALL_TYPE_MASK
);
587 if (ret
!= TCG_CALL_DUMMY_ARG
) {
588 #if TCG_TARGET_REG_BITS < 64
590 #ifdef TCG_TARGET_WORDS_BIGENDIAN
591 *gen_opparam_ptr
++ = ret
+ 1;
592 *gen_opparam_ptr
++ = ret
;
594 *gen_opparam_ptr
++ = ret
;
595 *gen_opparam_ptr
++ = ret
+ 1;
601 *gen_opparam_ptr
++ = ret
;
608 for (i
= 0; i
< nargs
; i
++) {
609 #if TCG_TARGET_REG_BITS < 64
610 if (sizemask
& (2 << i
)) {
611 #ifdef TCG_TARGET_I386
612 /* REGPARM case: if the third parameter is 64 bit, it is
613 allocated on the stack */
614 if (i
== 2 && call_type
== TCG_CALL_TYPE_REGPARM
) {
615 call_type
= TCG_CALL_TYPE_REGPARM_2
;
616 flags
= (flags
& ~TCG_CALL_TYPE_MASK
) | call_type
;
619 #ifdef TCG_TARGET_CALL_ALIGN_ARGS
620 /* some targets want aligned 64 bit args */
622 *gen_opparam_ptr
++ = TCG_CALL_DUMMY_ARG
;
625 #ifdef TCG_TARGET_WORDS_BIGENDIAN
626 *gen_opparam_ptr
++ = args
[i
] + 1;
627 *gen_opparam_ptr
++ = args
[i
];
629 *gen_opparam_ptr
++ = args
[i
];
630 *gen_opparam_ptr
++ = args
[i
] + 1;
636 *gen_opparam_ptr
++ = args
[i
];
640 *gen_opparam_ptr
++ = GET_TCGV_PTR(func
);
642 *gen_opparam_ptr
++ = flags
;
644 *nparam
= (nb_rets
<< 16) | (real_args
+ 1);
646 /* total parameters, needed to go backward in the instruction stream */
647 *gen_opparam_ptr
++ = 1 + nb_rets
+ real_args
+ 3;
650 #if TCG_TARGET_REG_BITS == 32
651 void tcg_gen_shifti_i64(TCGv_i64 ret
, TCGv_i64 arg1
,
652 int c
, int right
, int arith
)
655 tcg_gen_mov_i32(TCGV_LOW(ret
), TCGV_LOW(arg1
));
656 tcg_gen_mov_i32(TCGV_HIGH(ret
), TCGV_HIGH(arg1
));
657 } else if (c
>= 32) {
661 tcg_gen_sari_i32(TCGV_LOW(ret
), TCGV_HIGH(arg1
), c
);
662 tcg_gen_sari_i32(TCGV_HIGH(ret
), TCGV_HIGH(arg1
), 31);
664 tcg_gen_shri_i32(TCGV_LOW(ret
), TCGV_HIGH(arg1
), c
);
665 tcg_gen_movi_i32(TCGV_HIGH(ret
), 0);
668 tcg_gen_shli_i32(TCGV_HIGH(ret
), TCGV_LOW(arg1
), c
);
669 tcg_gen_movi_i32(TCGV_LOW(ret
), 0);
674 t0
= tcg_temp_new_i32();
675 t1
= tcg_temp_new_i32();
677 tcg_gen_shli_i32(t0
, TCGV_HIGH(arg1
), 32 - c
);
679 tcg_gen_sari_i32(t1
, TCGV_HIGH(arg1
), c
);
681 tcg_gen_shri_i32(t1
, TCGV_HIGH(arg1
), c
);
682 tcg_gen_shri_i32(TCGV_LOW(ret
), TCGV_LOW(arg1
), c
);
683 tcg_gen_or_i32(TCGV_LOW(ret
), TCGV_LOW(ret
), t0
);
684 tcg_gen_mov_i32(TCGV_HIGH(ret
), t1
);
686 tcg_gen_shri_i32(t0
, TCGV_LOW(arg1
), 32 - c
);
687 /* Note: ret can be the same as arg1, so we use t1 */
688 tcg_gen_shli_i32(t1
, TCGV_LOW(arg1
), c
);
689 tcg_gen_shli_i32(TCGV_HIGH(ret
), TCGV_HIGH(arg1
), c
);
690 tcg_gen_or_i32(TCGV_HIGH(ret
), TCGV_HIGH(ret
), t0
);
691 tcg_gen_mov_i32(TCGV_LOW(ret
), t1
);
693 tcg_temp_free_i32(t0
);
694 tcg_temp_free_i32(t1
);
699 static void tcg_reg_alloc_start(TCGContext
*s
)
703 for(i
= 0; i
< s
->nb_globals
; i
++) {
706 ts
->val_type
= TEMP_VAL_REG
;
708 ts
->val_type
= TEMP_VAL_MEM
;
711 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
713 ts
->val_type
= TEMP_VAL_DEAD
;
714 ts
->mem_allocated
= 0;
717 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
718 s
->reg_to_temp
[i
] = -1;
722 static char *tcg_get_arg_str_idx(TCGContext
*s
, char *buf
, int buf_size
,
728 if (idx
< s
->nb_globals
) {
729 pstrcpy(buf
, buf_size
, ts
->name
);
732 snprintf(buf
, buf_size
, "loc%d", idx
- s
->nb_globals
);
734 snprintf(buf
, buf_size
, "tmp%d", idx
- s
->nb_globals
);
739 char *tcg_get_arg_str_i32(TCGContext
*s
, char *buf
, int buf_size
, TCGv_i32 arg
)
741 return tcg_get_arg_str_idx(s
, buf
, buf_size
, GET_TCGV_I32(arg
));
744 char *tcg_get_arg_str_i64(TCGContext
*s
, char *buf
, int buf_size
, TCGv_i64 arg
)
746 return tcg_get_arg_str_idx(s
, buf
, buf_size
, GET_TCGV_I32(arg
));
749 static int helper_cmp(const void *p1
, const void *p2
)
751 const TCGHelperInfo
*th1
= p1
;
752 const TCGHelperInfo
*th2
= p2
;
753 if (th1
->func
< th2
->func
)
755 else if (th1
->func
== th2
->func
)
761 /* find helper definition (Note: A hash table would be better) */
762 static TCGHelperInfo
*tcg_find_helper(TCGContext
*s
, tcg_target_ulong val
)
768 if (unlikely(!s
->helpers_sorted
)) {
769 qsort(s
->helpers
, s
->nb_helpers
, sizeof(TCGHelperInfo
),
771 s
->helpers_sorted
= 1;
776 m_max
= s
->nb_helpers
- 1;
777 while (m_min
<= m_max
) {
778 m
= (m_min
+ m_max
) >> 1;
792 static const char * const cond_name
[] =
794 [TCG_COND_EQ
] = "eq",
795 [TCG_COND_NE
] = "ne",
796 [TCG_COND_LT
] = "lt",
797 [TCG_COND_GE
] = "ge",
798 [TCG_COND_LE
] = "le",
799 [TCG_COND_GT
] = "gt",
800 [TCG_COND_LTU
] = "ltu",
801 [TCG_COND_GEU
] = "geu",
802 [TCG_COND_LEU
] = "leu",
803 [TCG_COND_GTU
] = "gtu"
806 void tcg_dump_ops(TCGContext
*s
, FILE *outfile
)
808 const uint16_t *opc_ptr
;
811 int c
, i
, k
, nb_oargs
, nb_iargs
, nb_cargs
, first_insn
;
816 opc_ptr
= gen_opc_buf
;
817 args
= gen_opparam_buf
;
818 while (opc_ptr
< gen_opc_ptr
) {
820 def
= &tcg_op_defs
[c
];
821 if (c
== INDEX_op_debug_insn_start
) {
823 #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
824 pc
= ((uint64_t)args
[1] << 32) | args
[0];
829 fprintf(outfile
, "\n");
830 fprintf(outfile
, " ---- 0x%" PRIx64
, pc
);
832 nb_oargs
= def
->nb_oargs
;
833 nb_iargs
= def
->nb_iargs
;
834 nb_cargs
= def
->nb_cargs
;
835 } else if (c
== INDEX_op_call
) {
838 /* variable number of arguments */
840 nb_oargs
= arg
>> 16;
841 nb_iargs
= arg
& 0xffff;
842 nb_cargs
= def
->nb_cargs
;
844 fprintf(outfile
, " %s ", def
->name
);
847 fprintf(outfile
, "%s",
848 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[nb_oargs
+ nb_iargs
- 1]));
850 fprintf(outfile
, ",$0x%" TCG_PRIlx
,
851 args
[nb_oargs
+ nb_iargs
]);
853 fprintf(outfile
, ",$%d", nb_oargs
);
854 for(i
= 0; i
< nb_oargs
; i
++) {
855 fprintf(outfile
, ",");
856 fprintf(outfile
, "%s",
857 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[i
]));
859 for(i
= 0; i
< (nb_iargs
- 1); i
++) {
860 fprintf(outfile
, ",");
861 if (args
[nb_oargs
+ i
] == TCG_CALL_DUMMY_ARG
) {
862 fprintf(outfile
, "<dummy>");
864 fprintf(outfile
, "%s",
865 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[nb_oargs
+ i
]));
868 } else if (c
== INDEX_op_movi_i32
869 #if TCG_TARGET_REG_BITS == 64
870 || c
== INDEX_op_movi_i64
873 tcg_target_ulong val
;
876 nb_oargs
= def
->nb_oargs
;
877 nb_iargs
= def
->nb_iargs
;
878 nb_cargs
= def
->nb_cargs
;
879 fprintf(outfile
, " %s %s,$", def
->name
,
880 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[0]));
882 th
= tcg_find_helper(s
, val
);
884 fprintf(outfile
, th
->name
);
886 if (c
== INDEX_op_movi_i32
)
887 fprintf(outfile
, "0x%x", (uint32_t)val
);
889 fprintf(outfile
, "0x%" PRIx64
, (uint64_t)val
);
892 fprintf(outfile
, " %s ", def
->name
);
893 if (c
== INDEX_op_nopn
) {
894 /* variable number of arguments */
899 nb_oargs
= def
->nb_oargs
;
900 nb_iargs
= def
->nb_iargs
;
901 nb_cargs
= def
->nb_cargs
;
905 for(i
= 0; i
< nb_oargs
; i
++) {
907 fprintf(outfile
, ",");
908 fprintf(outfile
, "%s",
909 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[k
++]));
911 for(i
= 0; i
< nb_iargs
; i
++) {
913 fprintf(outfile
, ",");
914 fprintf(outfile
, "%s",
915 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[k
++]));
917 if (c
== INDEX_op_brcond_i32
918 #if TCG_TARGET_REG_BITS == 32
919 || c
== INDEX_op_brcond2_i32
920 #elif TCG_TARGET_REG_BITS == 64
921 || c
== INDEX_op_brcond_i64
924 if (args
[k
] < ARRAY_SIZE(cond_name
) && cond_name
[args
[k
]])
925 fprintf(outfile
, ",%s", cond_name
[args
[k
++]]);
927 fprintf(outfile
, ",$0x%" TCG_PRIlx
, args
[k
++]);
932 for(; i
< nb_cargs
; i
++) {
934 fprintf(outfile
, ",");
936 fprintf(outfile
, "$0x%" TCG_PRIlx
, arg
);
939 fprintf(outfile
, "\n");
940 args
+= nb_iargs
+ nb_oargs
+ nb_cargs
;
944 /* we give more priority to constraints with less registers */
945 static int get_constraint_priority(const TCGOpDef
*def
, int k
)
947 const TCGArgConstraint
*arg_ct
;
950 arg_ct
= &def
->args_ct
[k
];
951 if (arg_ct
->ct
& TCG_CT_ALIAS
) {
952 /* an alias is equivalent to a single register */
955 if (!(arg_ct
->ct
& TCG_CT_REG
))
958 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
959 if (tcg_regset_test_reg(arg_ct
->u
.regs
, i
))
963 return TCG_TARGET_NB_REGS
- n
+ 1;
966 /* sort from highest priority to lowest */
967 static void sort_constraints(TCGOpDef
*def
, int start
, int n
)
969 int i
, j
, p1
, p2
, tmp
;
971 for(i
= 0; i
< n
; i
++)
972 def
->sorted_args
[start
+ i
] = start
+ i
;
975 for(i
= 0; i
< n
- 1; i
++) {
976 for(j
= i
+ 1; j
< n
; j
++) {
977 p1
= get_constraint_priority(def
, def
->sorted_args
[start
+ i
]);
978 p2
= get_constraint_priority(def
, def
->sorted_args
[start
+ j
]);
980 tmp
= def
->sorted_args
[start
+ i
];
981 def
->sorted_args
[start
+ i
] = def
->sorted_args
[start
+ j
];
982 def
->sorted_args
[start
+ j
] = tmp
;
988 void tcg_add_target_add_op_defs(const TCGTargetOpDef
*tdefs
)
999 assert(op
>= 0 && op
< NB_OPS
);
1000 def
= &tcg_op_defs
[op
];
1001 nb_args
= def
->nb_iargs
+ def
->nb_oargs
;
1002 for(i
= 0; i
< nb_args
; i
++) {
1003 ct_str
= tdefs
->args_ct_str
[i
];
1004 tcg_regset_clear(def
->args_ct
[i
].u
.regs
);
1005 def
->args_ct
[i
].ct
= 0;
1006 if (ct_str
[0] >= '0' && ct_str
[0] <= '9') {
1008 oarg
= ct_str
[0] - '0';
1009 assert(oarg
< def
->nb_oargs
);
1010 assert(def
->args_ct
[oarg
].ct
& TCG_CT_REG
);
1011 /* TCG_CT_ALIAS is for the output arguments. The input
1012 argument is tagged with TCG_CT_IALIAS. */
1013 def
->args_ct
[i
] = def
->args_ct
[oarg
];
1014 def
->args_ct
[oarg
].ct
= TCG_CT_ALIAS
;
1015 def
->args_ct
[oarg
].alias_index
= i
;
1016 def
->args_ct
[i
].ct
|= TCG_CT_IALIAS
;
1017 def
->args_ct
[i
].alias_index
= oarg
;
1020 if (*ct_str
== '\0')
1024 def
->args_ct
[i
].ct
|= TCG_CT_CONST
;
1028 if (target_parse_constraint(&def
->args_ct
[i
], &ct_str
) < 0) {
1029 fprintf(stderr
, "Invalid constraint '%s' for arg %d of operation '%s'\n",
1030 ct_str
, i
, def
->name
);
1038 /* sort the constraints (XXX: this is just an heuristic) */
1039 sort_constraints(def
, 0, def
->nb_oargs
);
1040 sort_constraints(def
, def
->nb_oargs
, def
->nb_iargs
);
1046 printf("%s: sorted=", def
->name
);
1047 for(i
= 0; i
< def
->nb_oargs
+ def
->nb_iargs
; i
++)
1048 printf(" %d", def
->sorted_args
[i
]);
1057 #ifdef USE_LIVENESS_ANALYSIS
1059 /* set a nop for an operation using 'nb_args' */
1060 static inline void tcg_set_nop(TCGContext
*s
, uint16_t *opc_ptr
,
1061 TCGArg
*args
, int nb_args
)
1064 *opc_ptr
= INDEX_op_nop
;
1066 *opc_ptr
= INDEX_op_nopn
;
1068 args
[nb_args
- 1] = nb_args
;
1072 /* liveness analysis: end of function: globals are live, temps are
1074 /* XXX: at this stage, not used as there would be little gains because
1075 most TBs end with a conditional jump. */
1076 static inline void tcg_la_func_end(TCGContext
*s
, uint8_t *dead_temps
)
1078 memset(dead_temps
, 0, s
->nb_globals
);
1079 memset(dead_temps
+ s
->nb_globals
, 1, s
->nb_temps
- s
->nb_globals
);
1082 /* liveness analysis: end of basic block: globals are live, temps are
1083 dead, local temps are live. */
1084 static inline void tcg_la_bb_end(TCGContext
*s
, uint8_t *dead_temps
)
1089 memset(dead_temps
, 0, s
->nb_globals
);
1090 ts
= &s
->temps
[s
->nb_globals
];
1091 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
1100 /* Liveness analysis : update the opc_dead_iargs array to tell if a
1101 given input arguments is dead. Instructions updating dead
1102 temporaries are removed. */
1103 static void tcg_liveness_analysis(TCGContext
*s
)
1105 int i
, op_index
, op
, nb_args
, nb_iargs
, nb_oargs
, arg
, nb_ops
;
1107 const TCGOpDef
*def
;
1108 uint8_t *dead_temps
;
1109 unsigned int dead_iargs
;
1111 gen_opc_ptr
++; /* skip end */
1113 nb_ops
= gen_opc_ptr
- gen_opc_buf
;
1115 /* XXX: make it really dynamic */
1116 s
->op_dead_iargs
= tcg_malloc(OPC_BUF_SIZE
* sizeof(uint16_t));
1118 dead_temps
= tcg_malloc(s
->nb_temps
);
1119 memset(dead_temps
, 1, s
->nb_temps
);
1121 args
= gen_opparam_ptr
;
1122 op_index
= nb_ops
- 1;
1123 while (op_index
>= 0) {
1124 op
= gen_opc_buf
[op_index
];
1125 def
= &tcg_op_defs
[op
];
1133 nb_iargs
= args
[0] & 0xffff;
1134 nb_oargs
= args
[0] >> 16;
1136 call_flags
= args
[nb_oargs
+ nb_iargs
];
1138 /* pure functions can be removed if their result is not
1140 if (call_flags
& TCG_CALL_PURE
) {
1141 for(i
= 0; i
< nb_oargs
; i
++) {
1143 if (!dead_temps
[arg
])
1144 goto do_not_remove_call
;
1146 tcg_set_nop(s
, gen_opc_buf
+ op_index
,
1151 /* output args are dead */
1152 for(i
= 0; i
< nb_oargs
; i
++) {
1154 dead_temps
[arg
] = 1;
1157 /* globals are live (they may be used by the call) */
1158 memset(dead_temps
, 0, s
->nb_globals
);
1160 /* input args are live */
1162 for(i
= 0; i
< nb_iargs
; i
++) {
1163 arg
= args
[i
+ nb_oargs
];
1164 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1165 if (dead_temps
[arg
]) {
1166 dead_iargs
|= (1 << i
);
1168 dead_temps
[arg
] = 0;
1171 s
->op_dead_iargs
[op_index
] = dead_iargs
;
1176 case INDEX_op_set_label
:
1178 /* mark end of basic block */
1179 tcg_la_bb_end(s
, dead_temps
);
1181 case INDEX_op_debug_insn_start
:
1182 args
-= def
->nb_args
;
1188 case INDEX_op_discard
:
1190 /* mark the temporary as dead */
1191 dead_temps
[args
[0]] = 1;
1195 /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1197 if (op
> INDEX_op_end
) {
1198 args
-= def
->nb_args
;
1199 nb_iargs
= def
->nb_iargs
;
1200 nb_oargs
= def
->nb_oargs
;
1202 /* Test if the operation can be removed because all
1203 its outputs are dead. We assume that nb_oargs == 0
1204 implies side effects */
1205 if (!(def
->flags
& TCG_OPF_SIDE_EFFECTS
) && nb_oargs
!= 0) {
1206 for(i
= 0; i
< nb_oargs
; i
++) {
1208 if (!dead_temps
[arg
])
1211 tcg_set_nop(s
, gen_opc_buf
+ op_index
, args
, def
->nb_args
);
1212 #ifdef CONFIG_PROFILER
1218 /* output args are dead */
1219 for(i
= 0; i
< nb_oargs
; i
++) {
1221 dead_temps
[arg
] = 1;
1224 /* if end of basic block, update */
1225 if (def
->flags
& TCG_OPF_BB_END
) {
1226 tcg_la_bb_end(s
, dead_temps
);
1227 } else if (def
->flags
& TCG_OPF_CALL_CLOBBER
) {
1228 /* globals are live */
1229 memset(dead_temps
, 0, s
->nb_globals
);
1232 /* input args are live */
1234 for(i
= 0; i
< nb_iargs
; i
++) {
1235 arg
= args
[i
+ nb_oargs
];
1236 if (dead_temps
[arg
]) {
1237 dead_iargs
|= (1 << i
);
1239 dead_temps
[arg
] = 0;
1241 s
->op_dead_iargs
[op_index
] = dead_iargs
;
1244 /* legacy dyngen operations */
1245 args
-= def
->nb_args
;
1246 /* mark end of basic block */
1247 tcg_la_bb_end(s
, dead_temps
);
1254 if (args
!= gen_opparam_buf
)
1258 /* dummy liveness analysis */
1259 void tcg_liveness_analysis(TCGContext
*s
)
1262 nb_ops
= gen_opc_ptr
- gen_opc_buf
;
1264 s
->op_dead_iargs
= tcg_malloc(nb_ops
* sizeof(uint16_t));
1265 memset(s
->op_dead_iargs
, 0, nb_ops
* sizeof(uint16_t));
1270 static void dump_regs(TCGContext
*s
)
1276 for(i
= 0; i
< s
->nb_temps
; i
++) {
1278 printf(" %10s: ", tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), i
));
1279 switch(ts
->val_type
) {
1281 printf("%s", tcg_target_reg_names
[ts
->reg
]);
1284 printf("%d(%s)", (int)ts
->mem_offset
, tcg_target_reg_names
[ts
->mem_reg
]);
1286 case TEMP_VAL_CONST
:
1287 printf("$0x%" TCG_PRIlx
, ts
->val
);
1299 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
1300 if (s
->reg_to_temp
[i
] >= 0) {
1302 tcg_target_reg_names
[i
],
1303 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), s
->reg_to_temp
[i
]));
1308 static void check_regs(TCGContext
*s
)
1314 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1315 k
= s
->reg_to_temp
[reg
];
1318 if (ts
->val_type
!= TEMP_VAL_REG
||
1320 printf("Inconsistency for register %s:\n",
1321 tcg_target_reg_names
[reg
]);
1326 for(k
= 0; k
< s
->nb_temps
; k
++) {
1328 if (ts
->val_type
== TEMP_VAL_REG
&&
1330 s
->reg_to_temp
[ts
->reg
] != k
) {
1331 printf("Inconsistency for temp %s:\n",
1332 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), k
));
1334 printf("reg state:\n");
1342 static void temp_allocate_frame(TCGContext
*s
, int temp
)
1345 ts
= &s
->temps
[temp
];
1346 s
->current_frame_offset
= (s
->current_frame_offset
+ sizeof(tcg_target_long
) - 1) & ~(sizeof(tcg_target_long
) - 1);
1347 if (s
->current_frame_offset
+ sizeof(tcg_target_long
) > s
->frame_end
)
1349 ts
->mem_offset
= s
->current_frame_offset
;
1350 ts
->mem_reg
= s
->frame_reg
;
1351 ts
->mem_allocated
= 1;
1352 s
->current_frame_offset
+= sizeof(tcg_target_long
);
1355 /* free register 'reg' by spilling the corresponding temporary if necessary */
1356 static void tcg_reg_free(TCGContext
*s
, int reg
)
1361 temp
= s
->reg_to_temp
[reg
];
1363 ts
= &s
->temps
[temp
];
1364 assert(ts
->val_type
== TEMP_VAL_REG
);
1365 if (!ts
->mem_coherent
) {
1366 if (!ts
->mem_allocated
)
1367 temp_allocate_frame(s
, temp
);
1368 tcg_out_st(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1370 ts
->val_type
= TEMP_VAL_MEM
;
1371 s
->reg_to_temp
[reg
] = -1;
1375 /* Allocate a register belonging to reg1 & ~reg2 */
1376 static int tcg_reg_alloc(TCGContext
*s
, TCGRegSet reg1
, TCGRegSet reg2
)
1381 tcg_regset_andnot(reg_ct
, reg1
, reg2
);
1383 /* first try free registers */
1384 for(i
= 0; i
< ARRAY_SIZE(tcg_target_reg_alloc_order
); i
++) {
1385 reg
= tcg_target_reg_alloc_order
[i
];
1386 if (tcg_regset_test_reg(reg_ct
, reg
) && s
->reg_to_temp
[reg
] == -1)
1390 /* XXX: do better spill choice */
1391 for(i
= 0; i
< ARRAY_SIZE(tcg_target_reg_alloc_order
); i
++) {
1392 reg
= tcg_target_reg_alloc_order
[i
];
1393 if (tcg_regset_test_reg(reg_ct
, reg
)) {
1394 tcg_reg_free(s
, reg
);
1402 /* save a temporary to memory. 'allocated_regs' is used in case a
1403 temporary registers needs to be allocated to store a constant. */
1404 static void temp_save(TCGContext
*s
, int temp
, TCGRegSet allocated_regs
)
1409 ts
= &s
->temps
[temp
];
1410 if (!ts
->fixed_reg
) {
1411 switch(ts
->val_type
) {
1413 tcg_reg_free(s
, ts
->reg
);
1416 ts
->val_type
= TEMP_VAL_MEM
;
1418 case TEMP_VAL_CONST
:
1419 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1421 if (!ts
->mem_allocated
)
1422 temp_allocate_frame(s
, temp
);
1423 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1424 tcg_out_st(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1425 ts
->val_type
= TEMP_VAL_MEM
;
1435 /* save globals to their cannonical location and assume they can be
1436 modified be the following code. 'allocated_regs' is used in case a
1437 temporary registers needs to be allocated to store a constant. */
1438 static void save_globals(TCGContext
*s
, TCGRegSet allocated_regs
)
1442 for(i
= 0; i
< s
->nb_globals
; i
++) {
1443 temp_save(s
, i
, allocated_regs
);
1447 /* at the end of a basic block, we assume all temporaries are dead and
1448 all globals are stored at their canonical location. */
1449 static void tcg_reg_alloc_bb_end(TCGContext
*s
, TCGRegSet allocated_regs
)
1454 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
1456 if (ts
->temp_local
) {
1457 temp_save(s
, i
, allocated_regs
);
1459 if (ts
->val_type
== TEMP_VAL_REG
) {
1460 s
->reg_to_temp
[ts
->reg
] = -1;
1462 ts
->val_type
= TEMP_VAL_DEAD
;
1466 save_globals(s
, allocated_regs
);
1469 #define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
1471 static void tcg_reg_alloc_movi(TCGContext
*s
, const TCGArg
*args
)
1474 tcg_target_ulong val
;
1476 ots
= &s
->temps
[args
[0]];
1479 if (ots
->fixed_reg
) {
1480 /* for fixed registers, we do not do any constant
1482 tcg_out_movi(s
, ots
->type
, ots
->reg
, val
);
1484 /* The movi is not explicitly generated here */
1485 if (ots
->val_type
== TEMP_VAL_REG
)
1486 s
->reg_to_temp
[ots
->reg
] = -1;
1487 ots
->val_type
= TEMP_VAL_CONST
;
1492 static void tcg_reg_alloc_mov(TCGContext
*s
, const TCGOpDef
*def
,
1494 unsigned int dead_iargs
)
1498 const TCGArgConstraint
*arg_ct
;
1500 ots
= &s
->temps
[args
[0]];
1501 ts
= &s
->temps
[args
[1]];
1502 arg_ct
= &def
->args_ct
[0];
1504 /* XXX: always mark arg dead if IS_DEAD_IARG(0) */
1505 if (ts
->val_type
== TEMP_VAL_REG
) {
1506 if (IS_DEAD_IARG(0) && !ts
->fixed_reg
&& !ots
->fixed_reg
) {
1507 /* the mov can be suppressed */
1508 if (ots
->val_type
== TEMP_VAL_REG
)
1509 s
->reg_to_temp
[ots
->reg
] = -1;
1511 s
->reg_to_temp
[reg
] = -1;
1512 ts
->val_type
= TEMP_VAL_DEAD
;
1514 if (ots
->val_type
== TEMP_VAL_REG
) {
1517 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, s
->reserved_regs
);
1519 if (ts
->reg
!= reg
) {
1520 tcg_out_mov(s
, reg
, ts
->reg
);
1523 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1524 if (ots
->val_type
== TEMP_VAL_REG
) {
1527 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, s
->reserved_regs
);
1529 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1530 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1531 if (ots
->fixed_reg
) {
1533 tcg_out_movi(s
, ots
->type
, reg
, ts
->val
);
1535 /* propagate constant */
1536 if (ots
->val_type
== TEMP_VAL_REG
)
1537 s
->reg_to_temp
[ots
->reg
] = -1;
1538 ots
->val_type
= TEMP_VAL_CONST
;
1545 s
->reg_to_temp
[reg
] = args
[0];
1547 ots
->val_type
= TEMP_VAL_REG
;
1548 ots
->mem_coherent
= 0;
1551 static void tcg_reg_alloc_op(TCGContext
*s
,
1552 const TCGOpDef
*def
, int opc
,
1554 unsigned int dead_iargs
)
1556 TCGRegSet allocated_regs
;
1557 int i
, k
, nb_iargs
, nb_oargs
, reg
;
1559 const TCGArgConstraint
*arg_ct
;
1561 TCGArg new_args
[TCG_MAX_OP_ARGS
];
1562 int const_args
[TCG_MAX_OP_ARGS
];
1564 nb_oargs
= def
->nb_oargs
;
1565 nb_iargs
= def
->nb_iargs
;
1567 /* copy constants */
1568 memcpy(new_args
+ nb_oargs
+ nb_iargs
,
1569 args
+ nb_oargs
+ nb_iargs
,
1570 sizeof(TCGArg
) * def
->nb_cargs
);
1572 /* satisfy input constraints */
1573 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1574 for(k
= 0; k
< nb_iargs
; k
++) {
1575 i
= def
->sorted_args
[nb_oargs
+ k
];
1577 arg_ct
= &def
->args_ct
[i
];
1578 ts
= &s
->temps
[arg
];
1579 if (ts
->val_type
== TEMP_VAL_MEM
) {
1580 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1581 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1582 ts
->val_type
= TEMP_VAL_REG
;
1584 ts
->mem_coherent
= 1;
1585 s
->reg_to_temp
[reg
] = arg
;
1586 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1587 if (tcg_target_const_match(ts
->val
, arg_ct
)) {
1588 /* constant is OK for instruction */
1590 new_args
[i
] = ts
->val
;
1593 /* need to move to a register */
1594 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1595 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1596 ts
->val_type
= TEMP_VAL_REG
;
1598 ts
->mem_coherent
= 0;
1599 s
->reg_to_temp
[reg
] = arg
;
1602 assert(ts
->val_type
== TEMP_VAL_REG
);
1603 if (arg_ct
->ct
& TCG_CT_IALIAS
) {
1604 if (ts
->fixed_reg
) {
1605 /* if fixed register, we must allocate a new register
1606 if the alias is not the same register */
1607 if (arg
!= args
[arg_ct
->alias_index
])
1608 goto allocate_in_reg
;
1610 /* if the input is aliased to an output and if it is
1611 not dead after the instruction, we must allocate
1612 a new register and move it */
1613 if (!IS_DEAD_IARG(i
- nb_oargs
))
1614 goto allocate_in_reg
;
1618 if (tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1619 /* nothing to do : the constraint is satisfied */
1622 /* allocate a new register matching the constraint
1623 and move the temporary register into it */
1624 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1625 tcg_out_mov(s
, reg
, ts
->reg
);
1629 tcg_regset_set_reg(allocated_regs
, reg
);
1633 if (def
->flags
& TCG_OPF_BB_END
) {
1634 tcg_reg_alloc_bb_end(s
, allocated_regs
);
1636 /* mark dead temporaries and free the associated registers */
1637 for(i
= 0; i
< nb_iargs
; i
++) {
1638 arg
= args
[nb_oargs
+ i
];
1639 if (IS_DEAD_IARG(i
)) {
1640 ts
= &s
->temps
[arg
];
1641 if (!ts
->fixed_reg
) {
1642 if (ts
->val_type
== TEMP_VAL_REG
)
1643 s
->reg_to_temp
[ts
->reg
] = -1;
1644 ts
->val_type
= TEMP_VAL_DEAD
;
1649 if (def
->flags
& TCG_OPF_CALL_CLOBBER
) {
1650 /* XXX: permit generic clobber register list ? */
1651 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1652 if (tcg_regset_test_reg(tcg_target_call_clobber_regs
, reg
)) {
1653 tcg_reg_free(s
, reg
);
1656 /* XXX: for load/store we could do that only for the slow path
1657 (i.e. when a memory callback is called) */
1659 /* store globals and free associated registers (we assume the insn
1660 can modify any global. */
1661 save_globals(s
, allocated_regs
);
1664 /* satisfy the output constraints */
1665 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1666 for(k
= 0; k
< nb_oargs
; k
++) {
1667 i
= def
->sorted_args
[k
];
1669 arg_ct
= &def
->args_ct
[i
];
1670 ts
= &s
->temps
[arg
];
1671 if (arg_ct
->ct
& TCG_CT_ALIAS
) {
1672 reg
= new_args
[arg_ct
->alias_index
];
1674 /* if fixed register, we try to use it */
1676 if (ts
->fixed_reg
&&
1677 tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1680 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1682 tcg_regset_set_reg(allocated_regs
, reg
);
1683 /* if a fixed register is used, then a move will be done afterwards */
1684 if (!ts
->fixed_reg
) {
1685 if (ts
->val_type
== TEMP_VAL_REG
)
1686 s
->reg_to_temp
[ts
->reg
] = -1;
1687 ts
->val_type
= TEMP_VAL_REG
;
1689 /* temp value is modified, so the value kept in memory is
1690 potentially not the same */
1691 ts
->mem_coherent
= 0;
1692 s
->reg_to_temp
[reg
] = arg
;
1699 /* emit instruction */
1700 tcg_out_op(s
, opc
, new_args
, const_args
);
1702 /* move the outputs in the correct register if needed */
1703 for(i
= 0; i
< nb_oargs
; i
++) {
1704 ts
= &s
->temps
[args
[i
]];
1706 if (ts
->fixed_reg
&& ts
->reg
!= reg
) {
1707 tcg_out_mov(s
, ts
->reg
, reg
);
1712 #ifdef TCG_TARGET_STACK_GROWSUP
1713 #define STACK_DIR(x) (-(x))
1715 #define STACK_DIR(x) (x)
1718 static int tcg_reg_alloc_call(TCGContext
*s
, const TCGOpDef
*def
,
1719 int opc
, const TCGArg
*args
,
1720 unsigned int dead_iargs
)
1722 int nb_iargs
, nb_oargs
, flags
, nb_regs
, i
, reg
, nb_params
;
1723 TCGArg arg
, func_arg
;
1725 tcg_target_long stack_offset
, call_stack_size
, func_addr
;
1726 int const_func_arg
, allocate_args
;
1727 TCGRegSet allocated_regs
;
1728 const TCGArgConstraint
*arg_ct
;
1732 nb_oargs
= arg
>> 16;
1733 nb_iargs
= arg
& 0xffff;
1734 nb_params
= nb_iargs
- 1;
1736 flags
= args
[nb_oargs
+ nb_iargs
];
1738 nb_regs
= tcg_target_get_call_iarg_regs_count(flags
);
1739 if (nb_regs
> nb_params
)
1740 nb_regs
= nb_params
;
1742 /* assign stack slots first */
1743 /* XXX: preallocate call stack */
1744 call_stack_size
= (nb_params
- nb_regs
) * sizeof(tcg_target_long
);
1745 call_stack_size
= (call_stack_size
+ TCG_TARGET_STACK_ALIGN
- 1) &
1746 ~(TCG_TARGET_STACK_ALIGN
- 1);
1747 allocate_args
= (call_stack_size
> TCG_STATIC_CALL_ARGS_SIZE
);
1748 if (allocate_args
) {
1749 tcg_out_addi(s
, TCG_REG_CALL_STACK
, -STACK_DIR(call_stack_size
));
1752 stack_offset
= TCG_TARGET_CALL_STACK_OFFSET
;
1753 for(i
= nb_regs
; i
< nb_params
; i
++) {
1754 arg
= args
[nb_oargs
+ i
];
1755 #ifdef TCG_TARGET_STACK_GROWSUP
1756 stack_offset
-= sizeof(tcg_target_long
);
1758 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1759 ts
= &s
->temps
[arg
];
1760 if (ts
->val_type
== TEMP_VAL_REG
) {
1761 tcg_out_st(s
, ts
->type
, ts
->reg
, TCG_REG_CALL_STACK
, stack_offset
);
1762 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1763 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1765 /* XXX: not correct if reading values from the stack */
1766 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1767 tcg_out_st(s
, ts
->type
, reg
, TCG_REG_CALL_STACK
, stack_offset
);
1768 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1769 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1771 /* XXX: sign extend may be needed on some targets */
1772 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1773 tcg_out_st(s
, ts
->type
, reg
, TCG_REG_CALL_STACK
, stack_offset
);
1778 #ifndef TCG_TARGET_STACK_GROWSUP
1779 stack_offset
+= sizeof(tcg_target_long
);
1783 /* assign input registers */
1784 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1785 for(i
= 0; i
< nb_regs
; i
++) {
1786 arg
= args
[nb_oargs
+ i
];
1787 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1788 ts
= &s
->temps
[arg
];
1789 reg
= tcg_target_call_iarg_regs
[i
];
1790 tcg_reg_free(s
, reg
);
1791 if (ts
->val_type
== TEMP_VAL_REG
) {
1792 if (ts
->reg
!= reg
) {
1793 tcg_out_mov(s
, reg
, ts
->reg
);
1795 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1796 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1797 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1798 /* XXX: sign extend ? */
1799 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1803 tcg_regset_set_reg(allocated_regs
, reg
);
1807 /* assign function address */
1808 func_arg
= args
[nb_oargs
+ nb_iargs
- 1];
1809 arg_ct
= &def
->args_ct
[0];
1810 ts
= &s
->temps
[func_arg
];
1811 func_addr
= ts
->val
;
1813 if (ts
->val_type
== TEMP_VAL_MEM
) {
1814 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1815 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1817 tcg_regset_set_reg(allocated_regs
, reg
);
1818 } else if (ts
->val_type
== TEMP_VAL_REG
) {
1820 if (!tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1821 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1822 tcg_out_mov(s
, reg
, ts
->reg
);
1825 tcg_regset_set_reg(allocated_regs
, reg
);
1826 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1827 if (tcg_target_const_match(func_addr
, arg_ct
)) {
1829 func_arg
= func_addr
;
1831 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1832 tcg_out_movi(s
, ts
->type
, reg
, func_addr
);
1834 tcg_regset_set_reg(allocated_regs
, reg
);
1841 /* mark dead temporaries and free the associated registers */
1842 for(i
= 0; i
< nb_iargs
; i
++) {
1843 arg
= args
[nb_oargs
+ i
];
1844 if (IS_DEAD_IARG(i
)) {
1845 ts
= &s
->temps
[arg
];
1846 if (!ts
->fixed_reg
) {
1847 if (ts
->val_type
== TEMP_VAL_REG
)
1848 s
->reg_to_temp
[ts
->reg
] = -1;
1849 ts
->val_type
= TEMP_VAL_DEAD
;
1854 /* clobber call registers */
1855 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1856 if (tcg_regset_test_reg(tcg_target_call_clobber_regs
, reg
)) {
1857 tcg_reg_free(s
, reg
);
1861 /* store globals and free associated registers (we assume the call
1862 can modify any global. */
1863 save_globals(s
, allocated_regs
);
1865 tcg_out_op(s
, opc
, &func_arg
, &const_func_arg
);
1867 if (allocate_args
) {
1868 tcg_out_addi(s
, TCG_REG_CALL_STACK
, STACK_DIR(call_stack_size
));
1871 /* assign output registers and emit moves if needed */
1872 for(i
= 0; i
< nb_oargs
; i
++) {
1874 ts
= &s
->temps
[arg
];
1875 reg
= tcg_target_call_oarg_regs
[i
];
1876 assert(s
->reg_to_temp
[reg
] == -1);
1877 if (ts
->fixed_reg
) {
1878 if (ts
->reg
!= reg
) {
1879 tcg_out_mov(s
, ts
->reg
, reg
);
1882 if (ts
->val_type
== TEMP_VAL_REG
)
1883 s
->reg_to_temp
[ts
->reg
] = -1;
1884 ts
->val_type
= TEMP_VAL_REG
;
1886 ts
->mem_coherent
= 0;
1887 s
->reg_to_temp
[reg
] = arg
;
1891 return nb_iargs
+ nb_oargs
+ def
->nb_cargs
+ 1;
1894 #ifdef CONFIG_PROFILER
1896 static int64_t dyngen_table_op_count
[NB_OPS
];
1898 void dump_op_count(void)
1902 f
= fopen("/tmp/op1.log", "w");
1903 for(i
= 0; i
< INDEX_op_end
; i
++) {
1904 fprintf(f
, "%s %" PRId64
"\n", tcg_op_defs
[i
].name
, dyngen_table_op_count
[i
]);
1907 f
= fopen("/tmp/op2.log", "w");
1908 for(i
= INDEX_op_end
; i
< NB_OPS
; i
++) {
1909 fprintf(f
, "%s %" PRId64
"\n", tcg_op_defs
[i
].name
, dyngen_table_op_count
[i
]);
1916 static inline int tcg_gen_code_common(TCGContext
*s
, uint8_t *gen_code_buf
,
1920 const TCGOpDef
*def
;
1921 unsigned int dead_iargs
;
1925 if (unlikely(loglevel
& CPU_LOG_TB_OP
)) {
1926 fprintf(logfile
, "OP:\n");
1927 tcg_dump_ops(s
, logfile
);
1928 fprintf(logfile
, "\n");
1932 #ifdef CONFIG_PROFILER
1933 s
->la_time
-= profile_getclock();
1935 tcg_liveness_analysis(s
);
1936 #ifdef CONFIG_PROFILER
1937 s
->la_time
+= profile_getclock();
1941 if (unlikely(loglevel
& CPU_LOG_TB_OP_OPT
)) {
1942 fprintf(logfile
, "OP after la:\n");
1943 tcg_dump_ops(s
, logfile
);
1944 fprintf(logfile
, "\n");
1948 tcg_reg_alloc_start(s
);
1950 s
->code_buf
= gen_code_buf
;
1951 s
->code_ptr
= gen_code_buf
;
1953 args
= gen_opparam_buf
;
1957 opc
= gen_opc_buf
[op_index
];
1958 #ifdef CONFIG_PROFILER
1959 dyngen_table_op_count
[opc
]++;
1961 def
= &tcg_op_defs
[opc
];
1963 printf("%s: %d %d %d\n", def
->name
,
1964 def
->nb_oargs
, def
->nb_iargs
, def
->nb_cargs
);
1968 case INDEX_op_mov_i32
:
1969 #if TCG_TARGET_REG_BITS == 64
1970 case INDEX_op_mov_i64
:
1972 dead_iargs
= s
->op_dead_iargs
[op_index
];
1973 tcg_reg_alloc_mov(s
, def
, args
, dead_iargs
);
1975 case INDEX_op_movi_i32
:
1976 #if TCG_TARGET_REG_BITS == 64
1977 case INDEX_op_movi_i64
:
1979 tcg_reg_alloc_movi(s
, args
);
1981 case INDEX_op_debug_insn_start
:
1982 /* debug instruction */
1992 case INDEX_op_discard
:
1995 ts
= &s
->temps
[args
[0]];
1996 /* mark the temporary as dead */
1997 if (!ts
->fixed_reg
) {
1998 if (ts
->val_type
== TEMP_VAL_REG
)
1999 s
->reg_to_temp
[ts
->reg
] = -1;
2000 ts
->val_type
= TEMP_VAL_DEAD
;
2004 case INDEX_op_set_label
:
2005 tcg_reg_alloc_bb_end(s
, s
->reserved_regs
);
2006 tcg_out_label(s
, args
[0], (long)s
->code_ptr
);
2009 dead_iargs
= s
->op_dead_iargs
[op_index
];
2010 args
+= tcg_reg_alloc_call(s
, def
, opc
, args
, dead_iargs
);
2015 #ifdef CONFIG_DYNGEN_OP
2016 case 0 ... INDEX_op_end
- 1:
2017 /* legacy dyngen ops */
2018 #ifdef CONFIG_PROFILER
2021 tcg_reg_alloc_bb_end(s
, s
->reserved_regs
);
2022 if (search_pc
>= 0) {
2023 s
->code_ptr
+= def
->copy_size
;
2024 args
+= def
->nb_args
;
2026 args
= dyngen_op(s
, opc
, args
);
2031 /* Note: in order to speed up the code, it would be much
2032 faster to have specialized register allocator functions for
2033 some common argument patterns */
2034 dead_iargs
= s
->op_dead_iargs
[op_index
];
2035 tcg_reg_alloc_op(s
, def
, opc
, args
, dead_iargs
);
2038 args
+= def
->nb_args
;
2040 if (search_pc
>= 0 && search_pc
< s
->code_ptr
- gen_code_buf
) {
2052 int dyngen_code(TCGContext
*s
, uint8_t *gen_code_buf
)
2054 #ifdef CONFIG_PROFILER
2057 n
= (gen_opc_ptr
- gen_opc_buf
);
2059 if (n
> s
->op_count_max
)
2060 s
->op_count_max
= n
;
2062 s
->temp_count
+= s
->nb_temps
;
2063 if (s
->nb_temps
> s
->temp_count_max
)
2064 s
->temp_count_max
= s
->nb_temps
;
2068 tcg_gen_code_common(s
, gen_code_buf
, -1);
2070 /* flush instruction cache */
2071 flush_icache_range((unsigned long)gen_code_buf
,
2072 (unsigned long)s
->code_ptr
);
2073 return s
->code_ptr
- gen_code_buf
;
2076 /* Return the index of the micro operation such as the pc after is <
2077 offset bytes from the start of the TB. The contents of gen_code_buf must
2078 not be changed, though writing the same values is ok.
2079 Return -1 if not found. */
2080 int dyngen_code_search_pc(TCGContext
*s
, uint8_t *gen_code_buf
, long offset
)
2082 return tcg_gen_code_common(s
, gen_code_buf
, offset
);
2085 #ifdef CONFIG_PROFILER
2086 void tcg_dump_info(FILE *f
,
2087 int (*cpu_fprintf
)(FILE *f
, const char *fmt
, ...))
2089 TCGContext
*s
= &tcg_ctx
;
2092 tot
= s
->interm_time
+ s
->code_time
;
2093 cpu_fprintf(f
, "JIT cycles %" PRId64
" (%0.3f s at 2.4 GHz)\n",
2095 cpu_fprintf(f
, "translated TBs %" PRId64
" (aborted=%" PRId64
" %0.1f%%)\n",
2097 s
->tb_count1
- s
->tb_count
,
2098 s
->tb_count1
? (double)(s
->tb_count1
- s
->tb_count
) / s
->tb_count1
* 100.0 : 0);
2099 cpu_fprintf(f
, "avg ops/TB %0.1f max=%d\n",
2100 s
->tb_count
? (double)s
->op_count
/ s
->tb_count
: 0, s
->op_count_max
);
2101 cpu_fprintf(f
, "old ops/total ops %0.1f%%\n",
2102 s
->op_count
? (double)s
->old_op_count
/ s
->op_count
* 100.0 : 0);
2103 cpu_fprintf(f
, "deleted ops/TB %0.2f\n",
2105 (double)s
->del_op_count
/ s
->tb_count
: 0);
2106 cpu_fprintf(f
, "avg temps/TB %0.2f max=%d\n",
2108 (double)s
->temp_count
/ s
->tb_count
: 0,
2111 cpu_fprintf(f
, "cycles/op %0.1f\n",
2112 s
->op_count
? (double)tot
/ s
->op_count
: 0);
2113 cpu_fprintf(f
, "cycles/in byte %0.1f\n",
2114 s
->code_in_len
? (double)tot
/ s
->code_in_len
: 0);
2115 cpu_fprintf(f
, "cycles/out byte %0.1f\n",
2116 s
->code_out_len
? (double)tot
/ s
->code_out_len
: 0);
2119 cpu_fprintf(f
, " gen_interm time %0.1f%%\n",
2120 (double)s
->interm_time
/ tot
* 100.0);
2121 cpu_fprintf(f
, " gen_code time %0.1f%%\n",
2122 (double)s
->code_time
/ tot
* 100.0);
2123 cpu_fprintf(f
, "liveness/code time %0.1f%%\n",
2124 (double)s
->la_time
/ (s
->code_time
? s
->code_time
: 1) * 100.0);
2125 cpu_fprintf(f
, "cpu_restore count %" PRId64
"\n",
2127 cpu_fprintf(f
, " avg cycles %0.1f\n",
2128 s
->restore_count
? (double)s
->restore_time
/ s
->restore_count
: 0);
2130 extern void dump_op_count(void);
2135 void tcg_dump_info(FILE *f
,
2136 int (*cpu_fprintf
)(FILE *f
, const char *fmt
, ...))
2138 cpu_fprintf(f
, "[TCG profiler not compiled]\n");