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
45 #include "qemu-common.h"
46 #include "cache-utils.h"
48 /* Note: the long term plan is to reduce the dependancies on the QEMU
49 CPU definitions. Currently they are used for qemu_ld/st
51 #define NO_CPU_IO_DEFS
59 static void patch_reloc(uint8_t *code_ptr
, int type
,
60 tcg_target_long value
, tcg_target_long addend
);
62 TCGOpDef tcg_op_defs
[] = {
63 #define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size },
64 #define DEF2(s, iargs, oargs, cargs, flags) { #s, iargs, oargs, cargs, iargs + oargs + cargs, flags, 0 },
70 static TCGRegSet tcg_target_available_regs
[2];
71 static TCGRegSet tcg_target_call_clobber_regs
;
73 /* XXX: move that inside the context */
74 uint16_t *gen_opc_ptr
;
75 TCGArg
*gen_opparam_ptr
;
77 static inline void tcg_out8(TCGContext
*s
, uint8_t v
)
82 static inline void tcg_out16(TCGContext
*s
, uint16_t v
)
84 *(uint16_t *)s
->code_ptr
= v
;
88 static inline void tcg_out32(TCGContext
*s
, uint32_t v
)
90 *(uint32_t *)s
->code_ptr
= v
;
94 /* label relocation processing */
96 void tcg_out_reloc(TCGContext
*s
, uint8_t *code_ptr
, int type
,
97 int label_index
, long addend
)
102 l
= &s
->labels
[label_index
];
104 /* FIXME: This may break relocations on RISC targets that
105 modify instruction fields in place. The caller may not have
106 written the initial value. */
107 patch_reloc(code_ptr
, type
, l
->u
.value
, addend
);
109 /* add a new relocation entry */
110 r
= tcg_malloc(sizeof(TCGRelocation
));
114 r
->next
= l
->u
.first_reloc
;
115 l
->u
.first_reloc
= r
;
119 static void tcg_out_label(TCGContext
*s
, int label_index
,
120 tcg_target_long value
)
125 l
= &s
->labels
[label_index
];
128 r
= l
->u
.first_reloc
;
130 patch_reloc(r
->ptr
, r
->type
, value
, r
->addend
);
137 int gen_new_label(void)
139 TCGContext
*s
= &tcg_ctx
;
143 if (s
->nb_labels
>= TCG_MAX_LABELS
)
145 idx
= s
->nb_labels
++;
148 l
->u
.first_reloc
= NULL
;
152 #include "tcg-target.c"
154 /* pool based memory allocation */
155 void *tcg_malloc_internal(TCGContext
*s
, int size
)
160 if (size
> TCG_POOL_CHUNK_SIZE
) {
161 /* big malloc: insert a new pool (XXX: could optimize) */
162 p
= qemu_malloc(sizeof(TCGPool
) + size
);
165 s
->pool_current
->next
= p
;
168 p
->next
= s
->pool_current
;
178 pool_size
= TCG_POOL_CHUNK_SIZE
;
179 p
= qemu_malloc(sizeof(TCGPool
) + pool_size
);
183 s
->pool_current
->next
= p
;
192 s
->pool_cur
= p
->data
+ size
;
193 s
->pool_end
= p
->data
+ p
->size
;
197 void tcg_pool_reset(TCGContext
*s
)
199 s
->pool_cur
= s
->pool_end
= NULL
;
200 s
->pool_current
= NULL
;
203 void tcg_context_init(TCGContext
*s
)
205 int op
, total_args
, n
;
207 TCGArgConstraint
*args_ct
;
210 memset(s
, 0, sizeof(*s
));
211 s
->temps
= s
->static_temps
;
214 /* Count total number of arguments and allocate the corresponding
217 for(op
= 0; op
< NB_OPS
; op
++) {
218 def
= &tcg_op_defs
[op
];
219 n
= def
->nb_iargs
+ def
->nb_oargs
;
223 args_ct
= qemu_malloc(sizeof(TCGArgConstraint
) * total_args
);
224 sorted_args
= qemu_malloc(sizeof(int) * total_args
);
226 for(op
= 0; op
< NB_OPS
; op
++) {
227 def
= &tcg_op_defs
[op
];
228 def
->args_ct
= args_ct
;
229 def
->sorted_args
= sorted_args
;
230 n
= def
->nb_iargs
+ def
->nb_oargs
;
237 /* init global prologue and epilogue */
238 s
->code_buf
= code_gen_prologue
;
239 s
->code_ptr
= s
->code_buf
;
240 tcg_target_qemu_prologue(s
);
241 flush_icache_range((unsigned long)s
->code_buf
,
242 (unsigned long)s
->code_ptr
);
245 void tcg_set_frame(TCGContext
*s
, int reg
,
246 tcg_target_long start
, tcg_target_long size
)
248 s
->frame_start
= start
;
249 s
->frame_end
= start
+ size
;
253 void tcg_func_start(TCGContext
*s
)
257 s
->nb_temps
= s
->nb_globals
;
258 for(i
= 0; i
< (TCG_TYPE_COUNT
* 2); i
++)
259 s
->first_free_temp
[i
] = -1;
260 s
->labels
= tcg_malloc(sizeof(TCGLabel
) * TCG_MAX_LABELS
);
262 s
->current_frame_offset
= s
->frame_start
;
264 gen_opc_ptr
= gen_opc_buf
;
265 gen_opparam_ptr
= gen_opparam_buf
;
268 static inline void tcg_temp_alloc(TCGContext
*s
, int n
)
270 if (n
> TCG_MAX_TEMPS
)
274 static inline int tcg_global_reg_new_internal(TCGType type
, int reg
,
277 TCGContext
*s
= &tcg_ctx
;
281 #if TCG_TARGET_REG_BITS == 32
282 if (type
!= TCG_TYPE_I32
)
285 if (tcg_regset_test_reg(s
->reserved_regs
, reg
))
288 tcg_temp_alloc(s
, s
->nb_globals
+ 1);
289 ts
= &s
->temps
[s
->nb_globals
];
290 ts
->base_type
= type
;
296 tcg_regset_set_reg(s
->reserved_regs
, reg
);
300 TCGv_i32
tcg_global_reg_new_i32(int reg
, const char *name
)
304 idx
= tcg_global_reg_new_internal(TCG_TYPE_I32
, reg
, name
);
305 return MAKE_TCGV_I32(idx
);
308 TCGv_i64
tcg_global_reg_new_i64(int reg
, const char *name
)
312 idx
= tcg_global_reg_new_internal(TCG_TYPE_I64
, reg
, name
);
313 return MAKE_TCGV_I64(idx
);
316 #if TCG_TARGET_REG_BITS == 32
317 /* temporary hack to avoid register shortage for tcg_qemu_st64() */
318 TCGv_i64
tcg_global_reg2_new_hack(TCGType type
, int reg1
, int reg2
,
321 TCGContext
*s
= &tcg_ctx
;
326 if (type
!= TCG_TYPE_I64
)
329 tcg_temp_alloc(s
, s
->nb_globals
+ 2);
330 ts
= &s
->temps
[s
->nb_globals
];
331 ts
->base_type
= type
;
332 ts
->type
= TCG_TYPE_I32
;
335 pstrcpy(buf
, sizeof(buf
), name
);
336 pstrcat(buf
, sizeof(buf
), "_0");
337 ts
->name
= strdup(buf
);
340 ts
->base_type
= type
;
341 ts
->type
= TCG_TYPE_I32
;
344 pstrcpy(buf
, sizeof(buf
), name
);
345 pstrcat(buf
, sizeof(buf
), "_1");
346 ts
->name
= strdup(buf
);
349 return MAKE_TCGV_I64(idx
);
353 static inline int tcg_global_mem_new_internal(TCGType type
, int reg
,
354 tcg_target_long offset
,
357 TCGContext
*s
= &tcg_ctx
;
362 #if TCG_TARGET_REG_BITS == 32
363 if (type
== TCG_TYPE_I64
) {
365 tcg_temp_alloc(s
, s
->nb_globals
+ 2);
366 ts
= &s
->temps
[s
->nb_globals
];
367 ts
->base_type
= type
;
368 ts
->type
= TCG_TYPE_I32
;
370 ts
->mem_allocated
= 1;
372 #ifdef TCG_TARGET_WORDS_BIGENDIAN
373 ts
->mem_offset
= offset
+ 4;
375 ts
->mem_offset
= offset
;
377 pstrcpy(buf
, sizeof(buf
), name
);
378 pstrcat(buf
, sizeof(buf
), "_0");
379 ts
->name
= strdup(buf
);
382 ts
->base_type
= type
;
383 ts
->type
= TCG_TYPE_I32
;
385 ts
->mem_allocated
= 1;
387 #ifdef TCG_TARGET_WORDS_BIGENDIAN
388 ts
->mem_offset
= offset
;
390 ts
->mem_offset
= offset
+ 4;
392 pstrcpy(buf
, sizeof(buf
), name
);
393 pstrcat(buf
, sizeof(buf
), "_1");
394 ts
->name
= strdup(buf
);
400 tcg_temp_alloc(s
, s
->nb_globals
+ 1);
401 ts
= &s
->temps
[s
->nb_globals
];
402 ts
->base_type
= type
;
405 ts
->mem_allocated
= 1;
407 ts
->mem_offset
= offset
;
414 TCGv_i32
tcg_global_mem_new_i32(int reg
, tcg_target_long offset
,
419 idx
= tcg_global_mem_new_internal(TCG_TYPE_I32
, reg
, offset
, name
);
420 return MAKE_TCGV_I32(idx
);
423 TCGv_i64
tcg_global_mem_new_i64(int reg
, tcg_target_long offset
,
428 idx
= tcg_global_mem_new_internal(TCG_TYPE_I64
, reg
, offset
, name
);
429 return MAKE_TCGV_I64(idx
);
432 static inline int tcg_temp_new_internal(TCGType type
, int temp_local
)
434 TCGContext
*s
= &tcg_ctx
;
441 idx
= s
->first_free_temp
[k
];
443 /* There is already an available temp with the
446 s
->first_free_temp
[k
] = ts
->next_free_temp
;
447 ts
->temp_allocated
= 1;
448 assert(ts
->temp_local
== temp_local
);
451 #if TCG_TARGET_REG_BITS == 32
452 if (type
== TCG_TYPE_I64
) {
453 tcg_temp_alloc(s
, s
->nb_temps
+ 2);
454 ts
= &s
->temps
[s
->nb_temps
];
455 ts
->base_type
= type
;
456 ts
->type
= TCG_TYPE_I32
;
457 ts
->temp_allocated
= 1;
458 ts
->temp_local
= temp_local
;
461 ts
->base_type
= TCG_TYPE_I32
;
462 ts
->type
= TCG_TYPE_I32
;
463 ts
->temp_allocated
= 1;
464 ts
->temp_local
= temp_local
;
470 tcg_temp_alloc(s
, s
->nb_temps
+ 1);
471 ts
= &s
->temps
[s
->nb_temps
];
472 ts
->base_type
= type
;
474 ts
->temp_allocated
= 1;
475 ts
->temp_local
= temp_local
;
483 TCGv_i32
tcg_temp_new_internal_i32(int temp_local
)
487 idx
= tcg_temp_new_internal(TCG_TYPE_I32
, temp_local
);
488 return MAKE_TCGV_I32(idx
);
491 TCGv_i64
tcg_temp_new_internal_i64(int temp_local
)
495 idx
= tcg_temp_new_internal(TCG_TYPE_I64
, temp_local
);
496 return MAKE_TCGV_I64(idx
);
499 static inline void tcg_temp_free_internal(int idx
)
501 TCGContext
*s
= &tcg_ctx
;
505 assert(idx
>= s
->nb_globals
&& idx
< s
->nb_temps
);
507 assert(ts
->temp_allocated
!= 0);
508 ts
->temp_allocated
= 0;
512 ts
->next_free_temp
= s
->first_free_temp
[k
];
513 s
->first_free_temp
[k
] = idx
;
516 void tcg_temp_free_i32(TCGv_i32 arg
)
518 tcg_temp_free_internal(GET_TCGV_I32(arg
));
521 void tcg_temp_free_i64(TCGv_i64 arg
)
523 tcg_temp_free_internal(GET_TCGV_I64(arg
));
526 TCGv_i32
tcg_const_i32(int32_t val
)
529 t0
= tcg_temp_new_i32();
530 tcg_gen_movi_i32(t0
, val
);
534 TCGv_i64
tcg_const_i64(int64_t val
)
537 t0
= tcg_temp_new_i64();
538 tcg_gen_movi_i64(t0
, val
);
542 TCGv_i32
tcg_const_local_i32(int32_t val
)
545 t0
= tcg_temp_local_new_i32();
546 tcg_gen_movi_i32(t0
, val
);
550 TCGv_i64
tcg_const_local_i64(int64_t val
)
553 t0
= tcg_temp_local_new_i64();
554 tcg_gen_movi_i64(t0
, val
);
558 void tcg_register_helper(void *func
, const char *name
)
560 TCGContext
*s
= &tcg_ctx
;
562 if ((s
->nb_helpers
+ 1) > s
->allocated_helpers
) {
563 n
= s
->allocated_helpers
;
569 s
->helpers
= realloc(s
->helpers
, n
* sizeof(TCGHelperInfo
));
570 s
->allocated_helpers
= n
;
572 s
->helpers
[s
->nb_helpers
].func
= (tcg_target_ulong
)func
;
573 s
->helpers
[s
->nb_helpers
].name
= name
;
577 /* Note: we convert the 64 bit args to 32 bit and do some alignment
578 and endian swap. Maybe it would be better to do the alignment
579 and endian swap in tcg_reg_alloc_call(). */
580 void tcg_gen_callN(TCGContext
*s
, TCGv_ptr func
, unsigned int flags
,
581 int sizemask
, TCGArg ret
, int nargs
, TCGArg
*args
)
588 *gen_opc_ptr
++ = INDEX_op_call
;
589 nparam
= gen_opparam_ptr
++;
590 call_type
= (flags
& TCG_CALL_TYPE_MASK
);
591 if (ret
!= TCG_CALL_DUMMY_ARG
) {
592 #if TCG_TARGET_REG_BITS < 64
594 #ifdef TCG_TARGET_WORDS_BIGENDIAN
595 *gen_opparam_ptr
++ = ret
+ 1;
596 *gen_opparam_ptr
++ = ret
;
598 *gen_opparam_ptr
++ = ret
;
599 *gen_opparam_ptr
++ = ret
+ 1;
605 *gen_opparam_ptr
++ = ret
;
612 for (i
= 0; i
< nargs
; i
++) {
613 #if TCG_TARGET_REG_BITS < 64
614 if (sizemask
& (2 << i
)) {
615 #ifdef TCG_TARGET_I386
616 /* REGPARM case: if the third parameter is 64 bit, it is
617 allocated on the stack */
618 if (i
== 2 && call_type
== TCG_CALL_TYPE_REGPARM
) {
619 call_type
= TCG_CALL_TYPE_REGPARM_2
;
620 flags
= (flags
& ~TCG_CALL_TYPE_MASK
) | call_type
;
623 #ifdef TCG_TARGET_CALL_ALIGN_ARGS
624 /* some targets want aligned 64 bit args */
626 *gen_opparam_ptr
++ = TCG_CALL_DUMMY_ARG
;
630 #ifdef TCG_TARGET_WORDS_BIGENDIAN
631 *gen_opparam_ptr
++ = args
[i
] + 1;
632 *gen_opparam_ptr
++ = args
[i
];
634 *gen_opparam_ptr
++ = args
[i
];
635 *gen_opparam_ptr
++ = args
[i
] + 1;
641 *gen_opparam_ptr
++ = args
[i
];
645 *gen_opparam_ptr
++ = GET_TCGV_PTR(func
);
647 *gen_opparam_ptr
++ = flags
;
649 *nparam
= (nb_rets
<< 16) | (real_args
+ 1);
651 /* total parameters, needed to go backward in the instruction stream */
652 *gen_opparam_ptr
++ = 1 + nb_rets
+ real_args
+ 3;
655 #if TCG_TARGET_REG_BITS == 32
656 void tcg_gen_shifti_i64(TCGv_i64 ret
, TCGv_i64 arg1
,
657 int c
, int right
, int arith
)
660 tcg_gen_mov_i32(TCGV_LOW(ret
), TCGV_LOW(arg1
));
661 tcg_gen_mov_i32(TCGV_HIGH(ret
), TCGV_HIGH(arg1
));
662 } else if (c
>= 32) {
666 tcg_gen_sari_i32(TCGV_LOW(ret
), TCGV_HIGH(arg1
), c
);
667 tcg_gen_sari_i32(TCGV_HIGH(ret
), TCGV_HIGH(arg1
), 31);
669 tcg_gen_shri_i32(TCGV_LOW(ret
), TCGV_HIGH(arg1
), c
);
670 tcg_gen_movi_i32(TCGV_HIGH(ret
), 0);
673 tcg_gen_shli_i32(TCGV_HIGH(ret
), TCGV_LOW(arg1
), c
);
674 tcg_gen_movi_i32(TCGV_LOW(ret
), 0);
679 t0
= tcg_temp_new_i32();
680 t1
= tcg_temp_new_i32();
682 tcg_gen_shli_i32(t0
, TCGV_HIGH(arg1
), 32 - c
);
684 tcg_gen_sari_i32(t1
, TCGV_HIGH(arg1
), c
);
686 tcg_gen_shri_i32(t1
, TCGV_HIGH(arg1
), c
);
687 tcg_gen_shri_i32(TCGV_LOW(ret
), TCGV_LOW(arg1
), c
);
688 tcg_gen_or_i32(TCGV_LOW(ret
), TCGV_LOW(ret
), t0
);
689 tcg_gen_mov_i32(TCGV_HIGH(ret
), t1
);
691 tcg_gen_shri_i32(t0
, TCGV_LOW(arg1
), 32 - c
);
692 /* Note: ret can be the same as arg1, so we use t1 */
693 tcg_gen_shli_i32(t1
, TCGV_LOW(arg1
), c
);
694 tcg_gen_shli_i32(TCGV_HIGH(ret
), TCGV_HIGH(arg1
), c
);
695 tcg_gen_or_i32(TCGV_HIGH(ret
), TCGV_HIGH(ret
), t0
);
696 tcg_gen_mov_i32(TCGV_LOW(ret
), t1
);
698 tcg_temp_free_i32(t0
);
699 tcg_temp_free_i32(t1
);
704 static void tcg_reg_alloc_start(TCGContext
*s
)
708 for(i
= 0; i
< s
->nb_globals
; i
++) {
711 ts
->val_type
= TEMP_VAL_REG
;
713 ts
->val_type
= TEMP_VAL_MEM
;
716 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
718 ts
->val_type
= TEMP_VAL_DEAD
;
719 ts
->mem_allocated
= 0;
722 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
723 s
->reg_to_temp
[i
] = -1;
727 static char *tcg_get_arg_str_idx(TCGContext
*s
, char *buf
, int buf_size
,
733 if (idx
< s
->nb_globals
) {
734 pstrcpy(buf
, buf_size
, ts
->name
);
737 snprintf(buf
, buf_size
, "loc%d", idx
- s
->nb_globals
);
739 snprintf(buf
, buf_size
, "tmp%d", idx
- s
->nb_globals
);
744 char *tcg_get_arg_str_i32(TCGContext
*s
, char *buf
, int buf_size
, TCGv_i32 arg
)
746 return tcg_get_arg_str_idx(s
, buf
, buf_size
, GET_TCGV_I32(arg
));
749 char *tcg_get_arg_str_i64(TCGContext
*s
, char *buf
, int buf_size
, TCGv_i64 arg
)
751 return tcg_get_arg_str_idx(s
, buf
, buf_size
, GET_TCGV_I64(arg
));
754 static int helper_cmp(const void *p1
, const void *p2
)
756 const TCGHelperInfo
*th1
= p1
;
757 const TCGHelperInfo
*th2
= p2
;
758 if (th1
->func
< th2
->func
)
760 else if (th1
->func
== th2
->func
)
766 /* find helper definition (Note: A hash table would be better) */
767 static TCGHelperInfo
*tcg_find_helper(TCGContext
*s
, tcg_target_ulong val
)
773 if (unlikely(!s
->helpers_sorted
)) {
774 qsort(s
->helpers
, s
->nb_helpers
, sizeof(TCGHelperInfo
),
776 s
->helpers_sorted
= 1;
781 m_max
= s
->nb_helpers
- 1;
782 while (m_min
<= m_max
) {
783 m
= (m_min
+ m_max
) >> 1;
797 static const char * const cond_name
[] =
799 [TCG_COND_EQ
] = "eq",
800 [TCG_COND_NE
] = "ne",
801 [TCG_COND_LT
] = "lt",
802 [TCG_COND_GE
] = "ge",
803 [TCG_COND_LE
] = "le",
804 [TCG_COND_GT
] = "gt",
805 [TCG_COND_LTU
] = "ltu",
806 [TCG_COND_GEU
] = "geu",
807 [TCG_COND_LEU
] = "leu",
808 [TCG_COND_GTU
] = "gtu"
811 void tcg_dump_ops(TCGContext
*s
, FILE *outfile
)
813 const uint16_t *opc_ptr
;
816 int c
, i
, k
, nb_oargs
, nb_iargs
, nb_cargs
, first_insn
;
821 opc_ptr
= gen_opc_buf
;
822 args
= gen_opparam_buf
;
823 while (opc_ptr
< gen_opc_ptr
) {
825 def
= &tcg_op_defs
[c
];
826 if (c
== INDEX_op_debug_insn_start
) {
828 #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
829 pc
= ((uint64_t)args
[1] << 32) | args
[0];
834 fprintf(outfile
, "\n");
835 fprintf(outfile
, " ---- 0x%" PRIx64
, pc
);
837 nb_oargs
= def
->nb_oargs
;
838 nb_iargs
= def
->nb_iargs
;
839 nb_cargs
= def
->nb_cargs
;
840 } else if (c
== INDEX_op_call
) {
843 /* variable number of arguments */
845 nb_oargs
= arg
>> 16;
846 nb_iargs
= arg
& 0xffff;
847 nb_cargs
= def
->nb_cargs
;
849 fprintf(outfile
, " %s ", def
->name
);
852 fprintf(outfile
, "%s",
853 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[nb_oargs
+ nb_iargs
- 1]));
855 fprintf(outfile
, ",$0x%" TCG_PRIlx
,
856 args
[nb_oargs
+ nb_iargs
]);
858 fprintf(outfile
, ",$%d", nb_oargs
);
859 for(i
= 0; i
< nb_oargs
; i
++) {
860 fprintf(outfile
, ",");
861 fprintf(outfile
, "%s",
862 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[i
]));
864 for(i
= 0; i
< (nb_iargs
- 1); i
++) {
865 fprintf(outfile
, ",");
866 if (args
[nb_oargs
+ i
] == TCG_CALL_DUMMY_ARG
) {
867 fprintf(outfile
, "<dummy>");
869 fprintf(outfile
, "%s",
870 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[nb_oargs
+ i
]));
873 } else if (c
== INDEX_op_movi_i32
874 #if TCG_TARGET_REG_BITS == 64
875 || c
== INDEX_op_movi_i64
878 tcg_target_ulong val
;
881 nb_oargs
= def
->nb_oargs
;
882 nb_iargs
= def
->nb_iargs
;
883 nb_cargs
= def
->nb_cargs
;
884 fprintf(outfile
, " %s %s,$", def
->name
,
885 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[0]));
887 th
= tcg_find_helper(s
, val
);
889 fprintf(outfile
, th
->name
);
891 if (c
== INDEX_op_movi_i32
)
892 fprintf(outfile
, "0x%x", (uint32_t)val
);
894 fprintf(outfile
, "0x%" PRIx64
, (uint64_t)val
);
897 fprintf(outfile
, " %s ", def
->name
);
898 if (c
== INDEX_op_nopn
) {
899 /* variable number of arguments */
904 nb_oargs
= def
->nb_oargs
;
905 nb_iargs
= def
->nb_iargs
;
906 nb_cargs
= def
->nb_cargs
;
910 for(i
= 0; i
< nb_oargs
; i
++) {
912 fprintf(outfile
, ",");
913 fprintf(outfile
, "%s",
914 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[k
++]));
916 for(i
= 0; i
< nb_iargs
; i
++) {
918 fprintf(outfile
, ",");
919 fprintf(outfile
, "%s",
920 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[k
++]));
922 if (c
== INDEX_op_brcond_i32
923 #if TCG_TARGET_REG_BITS == 32
924 || c
== INDEX_op_brcond2_i32
925 #elif TCG_TARGET_REG_BITS == 64
926 || c
== INDEX_op_brcond_i64
929 if (args
[k
] < ARRAY_SIZE(cond_name
) && cond_name
[args
[k
]])
930 fprintf(outfile
, ",%s", cond_name
[args
[k
++]]);
932 fprintf(outfile
, ",$0x%" TCG_PRIlx
, args
[k
++]);
937 for(; i
< nb_cargs
; i
++) {
939 fprintf(outfile
, ",");
941 fprintf(outfile
, "$0x%" TCG_PRIlx
, arg
);
944 fprintf(outfile
, "\n");
945 args
+= nb_iargs
+ nb_oargs
+ nb_cargs
;
949 /* we give more priority to constraints with less registers */
950 static int get_constraint_priority(const TCGOpDef
*def
, int k
)
952 const TCGArgConstraint
*arg_ct
;
955 arg_ct
= &def
->args_ct
[k
];
956 if (arg_ct
->ct
& TCG_CT_ALIAS
) {
957 /* an alias is equivalent to a single register */
960 if (!(arg_ct
->ct
& TCG_CT_REG
))
963 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
964 if (tcg_regset_test_reg(arg_ct
->u
.regs
, i
))
968 return TCG_TARGET_NB_REGS
- n
+ 1;
971 /* sort from highest priority to lowest */
972 static void sort_constraints(TCGOpDef
*def
, int start
, int n
)
974 int i
, j
, p1
, p2
, tmp
;
976 for(i
= 0; i
< n
; i
++)
977 def
->sorted_args
[start
+ i
] = start
+ i
;
980 for(i
= 0; i
< n
- 1; i
++) {
981 for(j
= i
+ 1; j
< n
; j
++) {
982 p1
= get_constraint_priority(def
, def
->sorted_args
[start
+ i
]);
983 p2
= get_constraint_priority(def
, def
->sorted_args
[start
+ j
]);
985 tmp
= def
->sorted_args
[start
+ i
];
986 def
->sorted_args
[start
+ i
] = def
->sorted_args
[start
+ j
];
987 def
->sorted_args
[start
+ j
] = tmp
;
993 void tcg_add_target_add_op_defs(const TCGTargetOpDef
*tdefs
)
1004 assert(op
>= 0 && op
< NB_OPS
);
1005 def
= &tcg_op_defs
[op
];
1006 nb_args
= def
->nb_iargs
+ def
->nb_oargs
;
1007 for(i
= 0; i
< nb_args
; i
++) {
1008 ct_str
= tdefs
->args_ct_str
[i
];
1009 tcg_regset_clear(def
->args_ct
[i
].u
.regs
);
1010 def
->args_ct
[i
].ct
= 0;
1011 if (ct_str
[0] >= '0' && ct_str
[0] <= '9') {
1013 oarg
= ct_str
[0] - '0';
1014 assert(oarg
< def
->nb_oargs
);
1015 assert(def
->args_ct
[oarg
].ct
& TCG_CT_REG
);
1016 /* TCG_CT_ALIAS is for the output arguments. The input
1017 argument is tagged with TCG_CT_IALIAS. */
1018 def
->args_ct
[i
] = def
->args_ct
[oarg
];
1019 def
->args_ct
[oarg
].ct
= TCG_CT_ALIAS
;
1020 def
->args_ct
[oarg
].alias_index
= i
;
1021 def
->args_ct
[i
].ct
|= TCG_CT_IALIAS
;
1022 def
->args_ct
[i
].alias_index
= oarg
;
1025 if (*ct_str
== '\0')
1029 def
->args_ct
[i
].ct
|= TCG_CT_CONST
;
1033 if (target_parse_constraint(&def
->args_ct
[i
], &ct_str
) < 0) {
1034 fprintf(stderr
, "Invalid constraint '%s' for arg %d of operation '%s'\n",
1035 ct_str
, i
, def
->name
);
1043 /* sort the constraints (XXX: this is just an heuristic) */
1044 sort_constraints(def
, 0, def
->nb_oargs
);
1045 sort_constraints(def
, def
->nb_oargs
, def
->nb_iargs
);
1051 printf("%s: sorted=", def
->name
);
1052 for(i
= 0; i
< def
->nb_oargs
+ def
->nb_iargs
; i
++)
1053 printf(" %d", def
->sorted_args
[i
]);
1062 #ifdef USE_LIVENESS_ANALYSIS
1064 /* set a nop for an operation using 'nb_args' */
1065 static inline void tcg_set_nop(TCGContext
*s
, uint16_t *opc_ptr
,
1066 TCGArg
*args
, int nb_args
)
1069 *opc_ptr
= INDEX_op_nop
;
1071 *opc_ptr
= INDEX_op_nopn
;
1073 args
[nb_args
- 1] = nb_args
;
1077 /* liveness analysis: end of function: globals are live, temps are
1079 /* XXX: at this stage, not used as there would be little gains because
1080 most TBs end with a conditional jump. */
1081 static inline void tcg_la_func_end(TCGContext
*s
, uint8_t *dead_temps
)
1083 memset(dead_temps
, 0, s
->nb_globals
);
1084 memset(dead_temps
+ s
->nb_globals
, 1, s
->nb_temps
- s
->nb_globals
);
1087 /* liveness analysis: end of basic block: globals are live, temps are
1088 dead, local temps are live. */
1089 static inline void tcg_la_bb_end(TCGContext
*s
, uint8_t *dead_temps
)
1094 memset(dead_temps
, 0, s
->nb_globals
);
1095 ts
= &s
->temps
[s
->nb_globals
];
1096 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
1105 /* Liveness analysis : update the opc_dead_iargs array to tell if a
1106 given input arguments is dead. Instructions updating dead
1107 temporaries are removed. */
1108 static void tcg_liveness_analysis(TCGContext
*s
)
1110 int i
, op_index
, op
, nb_args
, nb_iargs
, nb_oargs
, arg
, nb_ops
;
1112 const TCGOpDef
*def
;
1113 uint8_t *dead_temps
;
1114 unsigned int dead_iargs
;
1116 gen_opc_ptr
++; /* skip end */
1118 nb_ops
= gen_opc_ptr
- gen_opc_buf
;
1120 /* XXX: make it really dynamic */
1121 s
->op_dead_iargs
= tcg_malloc(OPC_BUF_SIZE
* sizeof(uint16_t));
1123 dead_temps
= tcg_malloc(s
->nb_temps
);
1124 memset(dead_temps
, 1, s
->nb_temps
);
1126 args
= gen_opparam_ptr
;
1127 op_index
= nb_ops
- 1;
1128 while (op_index
>= 0) {
1129 op
= gen_opc_buf
[op_index
];
1130 def
= &tcg_op_defs
[op
];
1138 nb_iargs
= args
[0] & 0xffff;
1139 nb_oargs
= args
[0] >> 16;
1141 call_flags
= args
[nb_oargs
+ nb_iargs
];
1143 /* pure functions can be removed if their result is not
1145 if (call_flags
& TCG_CALL_PURE
) {
1146 for(i
= 0; i
< nb_oargs
; i
++) {
1148 if (!dead_temps
[arg
])
1149 goto do_not_remove_call
;
1151 tcg_set_nop(s
, gen_opc_buf
+ op_index
,
1156 /* output args are dead */
1157 for(i
= 0; i
< nb_oargs
; i
++) {
1159 dead_temps
[arg
] = 1;
1162 /* globals are live (they may be used by the call) */
1163 memset(dead_temps
, 0, s
->nb_globals
);
1165 /* input args are live */
1167 for(i
= 0; i
< nb_iargs
; i
++) {
1168 arg
= args
[i
+ nb_oargs
];
1169 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1170 if (dead_temps
[arg
]) {
1171 dead_iargs
|= (1 << i
);
1173 dead_temps
[arg
] = 0;
1176 s
->op_dead_iargs
[op_index
] = dead_iargs
;
1181 case INDEX_op_set_label
:
1183 /* mark end of basic block */
1184 tcg_la_bb_end(s
, dead_temps
);
1186 case INDEX_op_debug_insn_start
:
1187 args
-= def
->nb_args
;
1193 case INDEX_op_discard
:
1195 /* mark the temporary as dead */
1196 dead_temps
[args
[0]] = 1;
1200 /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1202 args
-= def
->nb_args
;
1203 nb_iargs
= def
->nb_iargs
;
1204 nb_oargs
= def
->nb_oargs
;
1206 /* Test if the operation can be removed because all
1207 its outputs are dead. We assume that nb_oargs == 0
1208 implies side effects */
1209 if (!(def
->flags
& TCG_OPF_SIDE_EFFECTS
) && nb_oargs
!= 0) {
1210 for(i
= 0; i
< nb_oargs
; i
++) {
1212 if (!dead_temps
[arg
])
1215 tcg_set_nop(s
, gen_opc_buf
+ op_index
, args
, def
->nb_args
);
1216 #ifdef CONFIG_PROFILER
1222 /* output args are dead */
1223 for(i
= 0; i
< nb_oargs
; i
++) {
1225 dead_temps
[arg
] = 1;
1228 /* if end of basic block, update */
1229 if (def
->flags
& TCG_OPF_BB_END
) {
1230 tcg_la_bb_end(s
, dead_temps
);
1231 } else if (def
->flags
& TCG_OPF_CALL_CLOBBER
) {
1232 /* globals are live */
1233 memset(dead_temps
, 0, s
->nb_globals
);
1236 /* input args are live */
1238 for(i
= 0; i
< nb_iargs
; i
++) {
1239 arg
= args
[i
+ nb_oargs
];
1240 if (dead_temps
[arg
]) {
1241 dead_iargs
|= (1 << i
);
1243 dead_temps
[arg
] = 0;
1245 s
->op_dead_iargs
[op_index
] = dead_iargs
;
1252 if (args
!= gen_opparam_buf
)
1256 /* dummy liveness analysis */
1257 void tcg_liveness_analysis(TCGContext
*s
)
1260 nb_ops
= gen_opc_ptr
- gen_opc_buf
;
1262 s
->op_dead_iargs
= tcg_malloc(nb_ops
* sizeof(uint16_t));
1263 memset(s
->op_dead_iargs
, 0, nb_ops
* sizeof(uint16_t));
1268 static void dump_regs(TCGContext
*s
)
1274 for(i
= 0; i
< s
->nb_temps
; i
++) {
1276 printf(" %10s: ", tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), i
));
1277 switch(ts
->val_type
) {
1279 printf("%s", tcg_target_reg_names
[ts
->reg
]);
1282 printf("%d(%s)", (int)ts
->mem_offset
, tcg_target_reg_names
[ts
->mem_reg
]);
1284 case TEMP_VAL_CONST
:
1285 printf("$0x%" TCG_PRIlx
, ts
->val
);
1297 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
1298 if (s
->reg_to_temp
[i
] >= 0) {
1300 tcg_target_reg_names
[i
],
1301 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), s
->reg_to_temp
[i
]));
1306 static void check_regs(TCGContext
*s
)
1312 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1313 k
= s
->reg_to_temp
[reg
];
1316 if (ts
->val_type
!= TEMP_VAL_REG
||
1318 printf("Inconsistency for register %s:\n",
1319 tcg_target_reg_names
[reg
]);
1324 for(k
= 0; k
< s
->nb_temps
; k
++) {
1326 if (ts
->val_type
== TEMP_VAL_REG
&&
1328 s
->reg_to_temp
[ts
->reg
] != k
) {
1329 printf("Inconsistency for temp %s:\n",
1330 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), k
));
1332 printf("reg state:\n");
1340 static void temp_allocate_frame(TCGContext
*s
, int temp
)
1343 ts
= &s
->temps
[temp
];
1344 s
->current_frame_offset
= (s
->current_frame_offset
+ sizeof(tcg_target_long
) - 1) & ~(sizeof(tcg_target_long
) - 1);
1345 if (s
->current_frame_offset
+ sizeof(tcg_target_long
) > s
->frame_end
)
1347 ts
->mem_offset
= s
->current_frame_offset
;
1348 ts
->mem_reg
= s
->frame_reg
;
1349 ts
->mem_allocated
= 1;
1350 s
->current_frame_offset
+= sizeof(tcg_target_long
);
1353 /* free register 'reg' by spilling the corresponding temporary if necessary */
1354 static void tcg_reg_free(TCGContext
*s
, int reg
)
1359 temp
= s
->reg_to_temp
[reg
];
1361 ts
= &s
->temps
[temp
];
1362 assert(ts
->val_type
== TEMP_VAL_REG
);
1363 if (!ts
->mem_coherent
) {
1364 if (!ts
->mem_allocated
)
1365 temp_allocate_frame(s
, temp
);
1366 tcg_out_st(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1368 ts
->val_type
= TEMP_VAL_MEM
;
1369 s
->reg_to_temp
[reg
] = -1;
1373 /* Allocate a register belonging to reg1 & ~reg2 */
1374 static int tcg_reg_alloc(TCGContext
*s
, TCGRegSet reg1
, TCGRegSet reg2
)
1379 tcg_regset_andnot(reg_ct
, reg1
, reg2
);
1381 /* first try free registers */
1382 for(i
= 0; i
< ARRAY_SIZE(tcg_target_reg_alloc_order
); i
++) {
1383 reg
= tcg_target_reg_alloc_order
[i
];
1384 if (tcg_regset_test_reg(reg_ct
, reg
) && s
->reg_to_temp
[reg
] == -1)
1388 /* XXX: do better spill choice */
1389 for(i
= 0; i
< ARRAY_SIZE(tcg_target_reg_alloc_order
); i
++) {
1390 reg
= tcg_target_reg_alloc_order
[i
];
1391 if (tcg_regset_test_reg(reg_ct
, reg
)) {
1392 tcg_reg_free(s
, reg
);
1400 /* save a temporary to memory. 'allocated_regs' is used in case a
1401 temporary registers needs to be allocated to store a constant. */
1402 static void temp_save(TCGContext
*s
, int temp
, TCGRegSet allocated_regs
)
1407 ts
= &s
->temps
[temp
];
1408 if (!ts
->fixed_reg
) {
1409 switch(ts
->val_type
) {
1411 tcg_reg_free(s
, ts
->reg
);
1414 ts
->val_type
= TEMP_VAL_MEM
;
1416 case TEMP_VAL_CONST
:
1417 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1419 if (!ts
->mem_allocated
)
1420 temp_allocate_frame(s
, temp
);
1421 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1422 tcg_out_st(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1423 ts
->val_type
= TEMP_VAL_MEM
;
1433 /* save globals to their cannonical location and assume they can be
1434 modified be the following code. 'allocated_regs' is used in case a
1435 temporary registers needs to be allocated to store a constant. */
1436 static void save_globals(TCGContext
*s
, TCGRegSet allocated_regs
)
1440 for(i
= 0; i
< s
->nb_globals
; i
++) {
1441 temp_save(s
, i
, allocated_regs
);
1445 /* at the end of a basic block, we assume all temporaries are dead and
1446 all globals are stored at their canonical location. */
1447 static void tcg_reg_alloc_bb_end(TCGContext
*s
, TCGRegSet allocated_regs
)
1452 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
1454 if (ts
->temp_local
) {
1455 temp_save(s
, i
, allocated_regs
);
1457 if (ts
->val_type
== TEMP_VAL_REG
) {
1458 s
->reg_to_temp
[ts
->reg
] = -1;
1460 ts
->val_type
= TEMP_VAL_DEAD
;
1464 save_globals(s
, allocated_regs
);
1467 #define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
1469 static void tcg_reg_alloc_movi(TCGContext
*s
, const TCGArg
*args
)
1472 tcg_target_ulong val
;
1474 ots
= &s
->temps
[args
[0]];
1477 if (ots
->fixed_reg
) {
1478 /* for fixed registers, we do not do any constant
1480 tcg_out_movi(s
, ots
->type
, ots
->reg
, val
);
1482 /* The movi is not explicitly generated here */
1483 if (ots
->val_type
== TEMP_VAL_REG
)
1484 s
->reg_to_temp
[ots
->reg
] = -1;
1485 ots
->val_type
= TEMP_VAL_CONST
;
1490 static void tcg_reg_alloc_mov(TCGContext
*s
, const TCGOpDef
*def
,
1492 unsigned int dead_iargs
)
1496 const TCGArgConstraint
*arg_ct
;
1498 ots
= &s
->temps
[args
[0]];
1499 ts
= &s
->temps
[args
[1]];
1500 arg_ct
= &def
->args_ct
[0];
1502 /* XXX: always mark arg dead if IS_DEAD_IARG(0) */
1503 if (ts
->val_type
== TEMP_VAL_REG
) {
1504 if (IS_DEAD_IARG(0) && !ts
->fixed_reg
&& !ots
->fixed_reg
) {
1505 /* the mov can be suppressed */
1506 if (ots
->val_type
== TEMP_VAL_REG
)
1507 s
->reg_to_temp
[ots
->reg
] = -1;
1509 s
->reg_to_temp
[reg
] = -1;
1510 ts
->val_type
= TEMP_VAL_DEAD
;
1512 if (ots
->val_type
== TEMP_VAL_REG
) {
1515 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, s
->reserved_regs
);
1517 if (ts
->reg
!= reg
) {
1518 tcg_out_mov(s
, reg
, ts
->reg
);
1521 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1522 if (ots
->val_type
== TEMP_VAL_REG
) {
1525 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, s
->reserved_regs
);
1527 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1528 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1529 if (ots
->fixed_reg
) {
1531 tcg_out_movi(s
, ots
->type
, reg
, ts
->val
);
1533 /* propagate constant */
1534 if (ots
->val_type
== TEMP_VAL_REG
)
1535 s
->reg_to_temp
[ots
->reg
] = -1;
1536 ots
->val_type
= TEMP_VAL_CONST
;
1543 s
->reg_to_temp
[reg
] = args
[0];
1545 ots
->val_type
= TEMP_VAL_REG
;
1546 ots
->mem_coherent
= 0;
1549 static void tcg_reg_alloc_op(TCGContext
*s
,
1550 const TCGOpDef
*def
, int opc
,
1552 unsigned int dead_iargs
)
1554 TCGRegSet allocated_regs
;
1555 int i
, k
, nb_iargs
, nb_oargs
, reg
;
1557 const TCGArgConstraint
*arg_ct
;
1559 TCGArg new_args
[TCG_MAX_OP_ARGS
];
1560 int const_args
[TCG_MAX_OP_ARGS
];
1562 nb_oargs
= def
->nb_oargs
;
1563 nb_iargs
= def
->nb_iargs
;
1565 /* copy constants */
1566 memcpy(new_args
+ nb_oargs
+ nb_iargs
,
1567 args
+ nb_oargs
+ nb_iargs
,
1568 sizeof(TCGArg
) * def
->nb_cargs
);
1570 /* satisfy input constraints */
1571 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1572 for(k
= 0; k
< nb_iargs
; k
++) {
1573 i
= def
->sorted_args
[nb_oargs
+ k
];
1575 arg_ct
= &def
->args_ct
[i
];
1576 ts
= &s
->temps
[arg
];
1577 if (ts
->val_type
== TEMP_VAL_MEM
) {
1578 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1579 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1580 ts
->val_type
= TEMP_VAL_REG
;
1582 ts
->mem_coherent
= 1;
1583 s
->reg_to_temp
[reg
] = arg
;
1584 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1585 if (tcg_target_const_match(ts
->val
, arg_ct
)) {
1586 /* constant is OK for instruction */
1588 new_args
[i
] = ts
->val
;
1591 /* need to move to a register */
1592 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1593 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1594 ts
->val_type
= TEMP_VAL_REG
;
1596 ts
->mem_coherent
= 0;
1597 s
->reg_to_temp
[reg
] = arg
;
1600 assert(ts
->val_type
== TEMP_VAL_REG
);
1601 if (arg_ct
->ct
& TCG_CT_IALIAS
) {
1602 if (ts
->fixed_reg
) {
1603 /* if fixed register, we must allocate a new register
1604 if the alias is not the same register */
1605 if (arg
!= args
[arg_ct
->alias_index
])
1606 goto allocate_in_reg
;
1608 /* if the input is aliased to an output and if it is
1609 not dead after the instruction, we must allocate
1610 a new register and move it */
1611 if (!IS_DEAD_IARG(i
- nb_oargs
))
1612 goto allocate_in_reg
;
1616 if (tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1617 /* nothing to do : the constraint is satisfied */
1620 /* allocate a new register matching the constraint
1621 and move the temporary register into it */
1622 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1623 tcg_out_mov(s
, reg
, ts
->reg
);
1627 tcg_regset_set_reg(allocated_regs
, reg
);
1631 if (def
->flags
& TCG_OPF_BB_END
) {
1632 tcg_reg_alloc_bb_end(s
, allocated_regs
);
1634 /* mark dead temporaries and free the associated registers */
1635 for(i
= 0; i
< nb_iargs
; i
++) {
1636 arg
= args
[nb_oargs
+ i
];
1637 if (IS_DEAD_IARG(i
)) {
1638 ts
= &s
->temps
[arg
];
1639 if (!ts
->fixed_reg
) {
1640 if (ts
->val_type
== TEMP_VAL_REG
)
1641 s
->reg_to_temp
[ts
->reg
] = -1;
1642 ts
->val_type
= TEMP_VAL_DEAD
;
1647 if (def
->flags
& TCG_OPF_CALL_CLOBBER
) {
1648 /* XXX: permit generic clobber register list ? */
1649 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1650 if (tcg_regset_test_reg(tcg_target_call_clobber_regs
, reg
)) {
1651 tcg_reg_free(s
, reg
);
1654 /* XXX: for load/store we could do that only for the slow path
1655 (i.e. when a memory callback is called) */
1657 /* store globals and free associated registers (we assume the insn
1658 can modify any global. */
1659 save_globals(s
, allocated_regs
);
1662 /* satisfy the output constraints */
1663 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1664 for(k
= 0; k
< nb_oargs
; k
++) {
1665 i
= def
->sorted_args
[k
];
1667 arg_ct
= &def
->args_ct
[i
];
1668 ts
= &s
->temps
[arg
];
1669 if (arg_ct
->ct
& TCG_CT_ALIAS
) {
1670 reg
= new_args
[arg_ct
->alias_index
];
1672 /* if fixed register, we try to use it */
1674 if (ts
->fixed_reg
&&
1675 tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1678 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1680 tcg_regset_set_reg(allocated_regs
, reg
);
1681 /* if a fixed register is used, then a move will be done afterwards */
1682 if (!ts
->fixed_reg
) {
1683 if (ts
->val_type
== TEMP_VAL_REG
)
1684 s
->reg_to_temp
[ts
->reg
] = -1;
1685 ts
->val_type
= TEMP_VAL_REG
;
1687 /* temp value is modified, so the value kept in memory is
1688 potentially not the same */
1689 ts
->mem_coherent
= 0;
1690 s
->reg_to_temp
[reg
] = arg
;
1697 /* emit instruction */
1698 tcg_out_op(s
, opc
, new_args
, const_args
);
1700 /* move the outputs in the correct register if needed */
1701 for(i
= 0; i
< nb_oargs
; i
++) {
1702 ts
= &s
->temps
[args
[i
]];
1704 if (ts
->fixed_reg
&& ts
->reg
!= reg
) {
1705 tcg_out_mov(s
, ts
->reg
, reg
);
1710 #ifdef TCG_TARGET_STACK_GROWSUP
1711 #define STACK_DIR(x) (-(x))
1713 #define STACK_DIR(x) (x)
1716 static int tcg_reg_alloc_call(TCGContext
*s
, const TCGOpDef
*def
,
1717 int opc
, const TCGArg
*args
,
1718 unsigned int dead_iargs
)
1720 int nb_iargs
, nb_oargs
, flags
, nb_regs
, i
, reg
, nb_params
;
1721 TCGArg arg
, func_arg
;
1723 tcg_target_long stack_offset
, call_stack_size
, func_addr
;
1724 int const_func_arg
, allocate_args
;
1725 TCGRegSet allocated_regs
;
1726 const TCGArgConstraint
*arg_ct
;
1730 nb_oargs
= arg
>> 16;
1731 nb_iargs
= arg
& 0xffff;
1732 nb_params
= nb_iargs
- 1;
1734 flags
= args
[nb_oargs
+ nb_iargs
];
1736 nb_regs
= tcg_target_get_call_iarg_regs_count(flags
);
1737 if (nb_regs
> nb_params
)
1738 nb_regs
= nb_params
;
1740 /* assign stack slots first */
1741 /* XXX: preallocate call stack */
1742 call_stack_size
= (nb_params
- nb_regs
) * sizeof(tcg_target_long
);
1743 call_stack_size
= (call_stack_size
+ TCG_TARGET_STACK_ALIGN
- 1) &
1744 ~(TCG_TARGET_STACK_ALIGN
- 1);
1745 allocate_args
= (call_stack_size
> TCG_STATIC_CALL_ARGS_SIZE
);
1746 if (allocate_args
) {
1747 tcg_out_addi(s
, TCG_REG_CALL_STACK
, -STACK_DIR(call_stack_size
));
1750 stack_offset
= TCG_TARGET_CALL_STACK_OFFSET
;
1751 for(i
= nb_regs
; i
< nb_params
; i
++) {
1752 arg
= args
[nb_oargs
+ i
];
1753 #ifdef TCG_TARGET_STACK_GROWSUP
1754 stack_offset
-= sizeof(tcg_target_long
);
1756 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1757 ts
= &s
->temps
[arg
];
1758 if (ts
->val_type
== TEMP_VAL_REG
) {
1759 tcg_out_st(s
, ts
->type
, ts
->reg
, TCG_REG_CALL_STACK
, stack_offset
);
1760 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1761 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1763 /* XXX: not correct if reading values from the stack */
1764 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1765 tcg_out_st(s
, ts
->type
, reg
, TCG_REG_CALL_STACK
, stack_offset
);
1766 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1767 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1769 /* XXX: sign extend may be needed on some targets */
1770 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1771 tcg_out_st(s
, ts
->type
, reg
, TCG_REG_CALL_STACK
, stack_offset
);
1776 #ifndef TCG_TARGET_STACK_GROWSUP
1777 stack_offset
+= sizeof(tcg_target_long
);
1781 /* assign input registers */
1782 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1783 for(i
= 0; i
< nb_regs
; i
++) {
1784 arg
= args
[nb_oargs
+ i
];
1785 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1786 ts
= &s
->temps
[arg
];
1787 reg
= tcg_target_call_iarg_regs
[i
];
1788 tcg_reg_free(s
, reg
);
1789 if (ts
->val_type
== TEMP_VAL_REG
) {
1790 if (ts
->reg
!= reg
) {
1791 tcg_out_mov(s
, reg
, ts
->reg
);
1793 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1794 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1795 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1796 /* XXX: sign extend ? */
1797 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1801 tcg_regset_set_reg(allocated_regs
, reg
);
1805 /* assign function address */
1806 func_arg
= args
[nb_oargs
+ nb_iargs
- 1];
1807 arg_ct
= &def
->args_ct
[0];
1808 ts
= &s
->temps
[func_arg
];
1809 func_addr
= ts
->val
;
1811 if (ts
->val_type
== TEMP_VAL_MEM
) {
1812 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1813 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1815 tcg_regset_set_reg(allocated_regs
, reg
);
1816 } else if (ts
->val_type
== TEMP_VAL_REG
) {
1818 if (!tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1819 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1820 tcg_out_mov(s
, reg
, ts
->reg
);
1823 tcg_regset_set_reg(allocated_regs
, reg
);
1824 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1825 if (tcg_target_const_match(func_addr
, arg_ct
)) {
1827 func_arg
= func_addr
;
1829 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1830 tcg_out_movi(s
, ts
->type
, reg
, func_addr
);
1832 tcg_regset_set_reg(allocated_regs
, reg
);
1839 /* mark dead temporaries and free the associated registers */
1840 for(i
= 0; i
< nb_iargs
; i
++) {
1841 arg
= args
[nb_oargs
+ i
];
1842 if (IS_DEAD_IARG(i
)) {
1843 ts
= &s
->temps
[arg
];
1844 if (!ts
->fixed_reg
) {
1845 if (ts
->val_type
== TEMP_VAL_REG
)
1846 s
->reg_to_temp
[ts
->reg
] = -1;
1847 ts
->val_type
= TEMP_VAL_DEAD
;
1852 /* clobber call registers */
1853 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1854 if (tcg_regset_test_reg(tcg_target_call_clobber_regs
, reg
)) {
1855 tcg_reg_free(s
, reg
);
1859 /* store globals and free associated registers (we assume the call
1860 can modify any global. */
1861 save_globals(s
, allocated_regs
);
1863 tcg_out_op(s
, opc
, &func_arg
, &const_func_arg
);
1865 if (allocate_args
) {
1866 tcg_out_addi(s
, TCG_REG_CALL_STACK
, STACK_DIR(call_stack_size
));
1869 /* assign output registers and emit moves if needed */
1870 for(i
= 0; i
< nb_oargs
; i
++) {
1872 ts
= &s
->temps
[arg
];
1873 reg
= tcg_target_call_oarg_regs
[i
];
1874 assert(s
->reg_to_temp
[reg
] == -1);
1875 if (ts
->fixed_reg
) {
1876 if (ts
->reg
!= reg
) {
1877 tcg_out_mov(s
, ts
->reg
, reg
);
1880 if (ts
->val_type
== TEMP_VAL_REG
)
1881 s
->reg_to_temp
[ts
->reg
] = -1;
1882 ts
->val_type
= TEMP_VAL_REG
;
1884 ts
->mem_coherent
= 0;
1885 s
->reg_to_temp
[reg
] = arg
;
1889 return nb_iargs
+ nb_oargs
+ def
->nb_cargs
+ 1;
1892 #ifdef CONFIG_PROFILER
1894 static int64_t tcg_table_op_count
[NB_OPS
];
1896 void dump_op_count(void)
1900 f
= fopen("/tmp/op.log", "w");
1901 for(i
= INDEX_op_end
; i
< NB_OPS
; i
++) {
1902 fprintf(f
, "%s %" PRId64
"\n", tcg_op_defs
[i
].name
, tcg_table_op_count
[i
]);
1909 static inline int tcg_gen_code_common(TCGContext
*s
, uint8_t *gen_code_buf
,
1913 const TCGOpDef
*def
;
1914 unsigned int dead_iargs
;
1918 if (unlikely(loglevel
& CPU_LOG_TB_OP
)) {
1919 fprintf(logfile
, "OP:\n");
1920 tcg_dump_ops(s
, logfile
);
1921 fprintf(logfile
, "\n");
1925 #ifdef CONFIG_PROFILER
1926 s
->la_time
-= profile_getclock();
1928 tcg_liveness_analysis(s
);
1929 #ifdef CONFIG_PROFILER
1930 s
->la_time
+= profile_getclock();
1934 if (unlikely(loglevel
& CPU_LOG_TB_OP_OPT
)) {
1935 fprintf(logfile
, "OP after la:\n");
1936 tcg_dump_ops(s
, logfile
);
1937 fprintf(logfile
, "\n");
1941 tcg_reg_alloc_start(s
);
1943 s
->code_buf
= gen_code_buf
;
1944 s
->code_ptr
= gen_code_buf
;
1946 args
= gen_opparam_buf
;
1950 opc
= gen_opc_buf
[op_index
];
1951 #ifdef CONFIG_PROFILER
1952 tcg_table_op_count
[opc
]++;
1954 def
= &tcg_op_defs
[opc
];
1956 printf("%s: %d %d %d\n", def
->name
,
1957 def
->nb_oargs
, def
->nb_iargs
, def
->nb_cargs
);
1961 case INDEX_op_mov_i32
:
1962 #if TCG_TARGET_REG_BITS == 64
1963 case INDEX_op_mov_i64
:
1965 dead_iargs
= s
->op_dead_iargs
[op_index
];
1966 tcg_reg_alloc_mov(s
, def
, args
, dead_iargs
);
1968 case INDEX_op_movi_i32
:
1969 #if TCG_TARGET_REG_BITS == 64
1970 case INDEX_op_movi_i64
:
1972 tcg_reg_alloc_movi(s
, args
);
1974 case INDEX_op_debug_insn_start
:
1975 /* debug instruction */
1985 case INDEX_op_discard
:
1988 ts
= &s
->temps
[args
[0]];
1989 /* mark the temporary as dead */
1990 if (!ts
->fixed_reg
) {
1991 if (ts
->val_type
== TEMP_VAL_REG
)
1992 s
->reg_to_temp
[ts
->reg
] = -1;
1993 ts
->val_type
= TEMP_VAL_DEAD
;
1997 case INDEX_op_set_label
:
1998 tcg_reg_alloc_bb_end(s
, s
->reserved_regs
);
1999 tcg_out_label(s
, args
[0], (long)s
->code_ptr
);
2002 dead_iargs
= s
->op_dead_iargs
[op_index
];
2003 args
+= tcg_reg_alloc_call(s
, def
, opc
, args
, dead_iargs
);
2008 /* Note: in order to speed up the code, it would be much
2009 faster to have specialized register allocator functions for
2010 some common argument patterns */
2011 dead_iargs
= s
->op_dead_iargs
[op_index
];
2012 tcg_reg_alloc_op(s
, def
, opc
, args
, dead_iargs
);
2015 args
+= def
->nb_args
;
2017 if (search_pc
>= 0 && search_pc
< s
->code_ptr
- gen_code_buf
) {
2029 int tcg_gen_code(TCGContext
*s
, uint8_t *gen_code_buf
)
2031 #ifdef CONFIG_PROFILER
2034 n
= (gen_opc_ptr
- gen_opc_buf
);
2036 if (n
> s
->op_count_max
)
2037 s
->op_count_max
= n
;
2039 s
->temp_count
+= s
->nb_temps
;
2040 if (s
->nb_temps
> s
->temp_count_max
)
2041 s
->temp_count_max
= s
->nb_temps
;
2045 tcg_gen_code_common(s
, gen_code_buf
, -1);
2047 /* flush instruction cache */
2048 flush_icache_range((unsigned long)gen_code_buf
,
2049 (unsigned long)s
->code_ptr
);
2050 return s
->code_ptr
- gen_code_buf
;
2053 /* Return the index of the micro operation such as the pc after is <
2054 offset bytes from the start of the TB. The contents of gen_code_buf must
2055 not be changed, though writing the same values is ok.
2056 Return -1 if not found. */
2057 int tcg_gen_code_search_pc(TCGContext
*s
, uint8_t *gen_code_buf
, long offset
)
2059 return tcg_gen_code_common(s
, gen_code_buf
, offset
);
2062 #ifdef CONFIG_PROFILER
2063 void tcg_dump_info(FILE *f
,
2064 int (*cpu_fprintf
)(FILE *f
, const char *fmt
, ...))
2066 TCGContext
*s
= &tcg_ctx
;
2069 tot
= s
->interm_time
+ s
->code_time
;
2070 cpu_fprintf(f
, "JIT cycles %" PRId64
" (%0.3f s at 2.4 GHz)\n",
2072 cpu_fprintf(f
, "translated TBs %" PRId64
" (aborted=%" PRId64
" %0.1f%%)\n",
2074 s
->tb_count1
- s
->tb_count
,
2075 s
->tb_count1
? (double)(s
->tb_count1
- s
->tb_count
) / s
->tb_count1
* 100.0 : 0);
2076 cpu_fprintf(f
, "avg ops/TB %0.1f max=%d\n",
2077 s
->tb_count
? (double)s
->op_count
/ s
->tb_count
: 0, s
->op_count_max
);
2078 cpu_fprintf(f
, "old ops/total ops %0.1f%%\n",
2079 s
->op_count
? (double)s
->old_op_count
/ s
->op_count
* 100.0 : 0);
2080 cpu_fprintf(f
, "deleted ops/TB %0.2f\n",
2082 (double)s
->del_op_count
/ s
->tb_count
: 0);
2083 cpu_fprintf(f
, "avg temps/TB %0.2f max=%d\n",
2085 (double)s
->temp_count
/ s
->tb_count
: 0,
2088 cpu_fprintf(f
, "cycles/op %0.1f\n",
2089 s
->op_count
? (double)tot
/ s
->op_count
: 0);
2090 cpu_fprintf(f
, "cycles/in byte %0.1f\n",
2091 s
->code_in_len
? (double)tot
/ s
->code_in_len
: 0);
2092 cpu_fprintf(f
, "cycles/out byte %0.1f\n",
2093 s
->code_out_len
? (double)tot
/ s
->code_out_len
: 0);
2096 cpu_fprintf(f
, " gen_interm time %0.1f%%\n",
2097 (double)s
->interm_time
/ tot
* 100.0);
2098 cpu_fprintf(f
, " gen_code time %0.1f%%\n",
2099 (double)s
->code_time
/ tot
* 100.0);
2100 cpu_fprintf(f
, "liveness/code time %0.1f%%\n",
2101 (double)s
->la_time
/ (s
->code_time
? s
->code_time
: 1) * 100.0);
2102 cpu_fprintf(f
, "cpu_restore count %" PRId64
"\n",
2104 cpu_fprintf(f
, " avg cycles %0.1f\n",
2105 s
->restore_count
? (double)s
->restore_time
/ s
->restore_count
: 0);
2107 extern void dump_op_count(void);
2112 void tcg_dump_info(FILE *f
,
2113 int (*cpu_fprintf
)(FILE *f
, const char *fmt
, ...))
2115 cpu_fprintf(f
, "[TCG profiler not compiled]\n");