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 TCGRegSet tcg_target_available_regs
[2];
67 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 /* free all the pool */
200 void tcg_pool_free(TCGContext
*s
)
204 for(p
= s
->pool_first
; p
!= NULL
; p
= p1
) {
208 s
->pool_first
= NULL
;
209 s
->pool_cur
= s
->pool_end
= NULL
;
212 void tcg_context_init(TCGContext
*s
)
214 int op
, total_args
, n
;
216 TCGArgConstraint
*args_ct
;
219 memset(s
, 0, sizeof(*s
));
220 s
->temps
= s
->static_temps
;
223 /* Count total number of arguments and allocate the corresponding
226 for(op
= 0; op
< NB_OPS
; op
++) {
227 def
= &tcg_op_defs
[op
];
228 n
= def
->nb_iargs
+ def
->nb_oargs
;
232 args_ct
= qemu_malloc(sizeof(TCGArgConstraint
) * total_args
);
233 sorted_args
= qemu_malloc(sizeof(int) * total_args
);
235 for(op
= 0; op
< NB_OPS
; op
++) {
236 def
= &tcg_op_defs
[op
];
237 def
->args_ct
= args_ct
;
238 def
->sorted_args
= sorted_args
;
239 n
= def
->nb_iargs
+ def
->nb_oargs
;
246 /* init global prologue and epilogue */
247 s
->code_buf
= code_gen_prologue
;
248 s
->code_ptr
= s
->code_buf
;
249 tcg_target_qemu_prologue(s
);
250 flush_icache_range((unsigned long)s
->code_buf
,
251 (unsigned long)s
->code_ptr
);
254 void tcg_set_frame(TCGContext
*s
, int reg
,
255 tcg_target_long start
, tcg_target_long size
)
257 s
->frame_start
= start
;
258 s
->frame_end
= start
+ size
;
262 void tcg_set_macro_func(TCGContext
*s
, TCGMacroFunc
*func
)
264 s
->macro_func
= func
;
267 void tcg_func_start(TCGContext
*s
)
270 s
->nb_temps
= s
->nb_globals
;
271 s
->labels
= tcg_malloc(sizeof(TCGLabel
) * TCG_MAX_LABELS
);
273 s
->current_frame_offset
= s
->frame_start
;
275 gen_opc_ptr
= gen_opc_buf
;
276 gen_opparam_ptr
= gen_opparam_buf
;
279 static inline void tcg_temp_alloc(TCGContext
*s
, int n
)
281 if (n
> TCG_MAX_TEMPS
)
285 TCGv
tcg_global_reg_new(TCGType type
, int reg
, const char *name
)
287 TCGContext
*s
= &tcg_ctx
;
291 #if TCG_TARGET_REG_BITS == 32
292 if (type
!= TCG_TYPE_I32
)
295 if (tcg_regset_test_reg(s
->reserved_regs
, reg
))
298 tcg_temp_alloc(s
, s
->nb_globals
+ 1);
299 ts
= &s
->temps
[s
->nb_globals
];
300 ts
->base_type
= type
;
304 ts
->val_type
= TEMP_VAL_REG
;
307 tcg_regset_set_reg(s
->reserved_regs
, reg
);
308 return MAKE_TCGV(idx
);
311 #if TCG_TARGET_REG_BITS == 32
312 /* temporary hack to avoid register shortage for tcg_qemu_st64() */
313 TCGv
tcg_global_reg2_new_hack(TCGType type
, int reg1
, int reg2
,
316 TCGContext
*s
= &tcg_ctx
;
321 if (type
!= TCG_TYPE_I64
)
324 tcg_temp_alloc(s
, s
->nb_globals
+ 2);
325 ts
= &s
->temps
[s
->nb_globals
];
326 ts
->base_type
= type
;
327 ts
->type
= TCG_TYPE_I32
;
330 ts
->val_type
= TEMP_VAL_REG
;
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 ts
->val_type
= TEMP_VAL_REG
;
341 pstrcpy(buf
, sizeof(buf
), name
);
342 pstrcat(buf
, sizeof(buf
), "_1");
343 ts
->name
= strdup(buf
);
346 return MAKE_TCGV(idx
);
350 TCGv
tcg_global_mem_new(TCGType type
, int reg
, 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
+ 1);
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 ts
->val_type
= TEMP_VAL_MEM
;
374 pstrcpy(buf
, sizeof(buf
), name
);
375 pstrcat(buf
, sizeof(buf
), "_0");
376 ts
->name
= strdup(buf
);
379 ts
->base_type
= type
;
380 ts
->type
= TCG_TYPE_I32
;
382 ts
->mem_allocated
= 1;
384 #ifdef TCG_TARGET_WORDS_BIGENDIAN
385 ts
->mem_offset
= offset
;
387 ts
->mem_offset
= offset
+ 4;
389 ts
->val_type
= TEMP_VAL_MEM
;
390 pstrcpy(buf
, sizeof(buf
), name
);
391 pstrcat(buf
, sizeof(buf
), "_1");
392 ts
->name
= strdup(buf
);
398 tcg_temp_alloc(s
, s
->nb_globals
+ 1);
399 ts
= &s
->temps
[s
->nb_globals
];
400 ts
->base_type
= type
;
403 ts
->mem_allocated
= 1;
405 ts
->mem_offset
= offset
;
406 ts
->val_type
= TEMP_VAL_MEM
;
410 return MAKE_TCGV(idx
);
413 TCGv
tcg_temp_new(TCGType type
)
415 TCGContext
*s
= &tcg_ctx
;
420 #if TCG_TARGET_REG_BITS == 32
421 if (type
== TCG_TYPE_I64
) {
422 tcg_temp_alloc(s
, s
->nb_temps
+ 1);
423 ts
= &s
->temps
[s
->nb_temps
];
424 ts
->base_type
= type
;
425 ts
->type
= TCG_TYPE_I32
;
427 ts
->val_type
= TEMP_VAL_DEAD
;
428 ts
->mem_allocated
= 0;
431 ts
->base_type
= TCG_TYPE_I32
;
432 ts
->type
= TCG_TYPE_I32
;
433 ts
->val_type
= TEMP_VAL_DEAD
;
435 ts
->mem_allocated
= 0;
441 tcg_temp_alloc(s
, s
->nb_temps
+ 1);
442 ts
= &s
->temps
[s
->nb_temps
];
443 ts
->base_type
= type
;
446 ts
->val_type
= TEMP_VAL_DEAD
;
447 ts
->mem_allocated
= 0;
451 return MAKE_TCGV(idx
);
454 TCGv
tcg_const_i32(int32_t val
)
456 TCGContext
*s
= &tcg_ctx
;
461 tcg_temp_alloc(s
, idx
+ 1);
463 ts
->base_type
= ts
->type
= TCG_TYPE_I32
;
464 ts
->val_type
= TEMP_VAL_CONST
;
468 return MAKE_TCGV(idx
);
471 TCGv
tcg_const_i64(int64_t val
)
473 TCGContext
*s
= &tcg_ctx
;
478 #if TCG_TARGET_REG_BITS == 32
479 tcg_temp_alloc(s
, idx
+ 2);
481 ts
->base_type
= TCG_TYPE_I64
;
482 ts
->type
= TCG_TYPE_I32
;
483 ts
->val_type
= TEMP_VAL_CONST
;
487 ts
->base_type
= TCG_TYPE_I32
;
488 ts
->type
= TCG_TYPE_I32
;
489 ts
->val_type
= TEMP_VAL_CONST
;
494 tcg_temp_alloc(s
, idx
+ 1);
496 ts
->base_type
= ts
->type
= TCG_TYPE_I64
;
497 ts
->val_type
= TEMP_VAL_CONST
;
502 return MAKE_TCGV(idx
);
505 void tcg_register_helper(void *func
, const char *name
)
507 TCGContext
*s
= &tcg_ctx
;
509 if ((s
->nb_helpers
+ 1) > s
->allocated_helpers
) {
510 n
= s
->allocated_helpers
;
516 s
->helpers
= realloc(s
->helpers
, n
* sizeof(TCGHelperInfo
));
517 s
->allocated_helpers
= n
;
519 s
->helpers
[s
->nb_helpers
].func
= func
;
520 s
->helpers
[s
->nb_helpers
].name
= name
;
524 const char *tcg_helper_get_name(TCGContext
*s
, void *func
)
528 for(i
= 0; i
< s
->nb_helpers
; i
++) {
529 if (s
->helpers
[i
].func
== func
)
530 return s
->helpers
[i
].name
;
535 static inline TCGType
tcg_get_base_type(TCGContext
*s
, TCGv arg
)
537 return s
->temps
[GET_TCGV(arg
)].base_type
;
540 static void tcg_gen_call_internal(TCGContext
*s
, TCGv func
,
542 unsigned int nb_rets
, const TCGv
*rets
,
543 unsigned int nb_params
, const TCGv
*params
)
546 *gen_opc_ptr
++ = INDEX_op_call
;
547 *gen_opparam_ptr
++ = (nb_rets
<< 16) | (nb_params
+ 1);
548 for(i
= 0; i
< nb_rets
; i
++) {
549 *gen_opparam_ptr
++ = GET_TCGV(rets
[i
]);
551 for(i
= 0; i
< nb_params
; i
++) {
552 *gen_opparam_ptr
++ = GET_TCGV(params
[i
]);
554 *gen_opparam_ptr
++ = GET_TCGV(func
);
556 *gen_opparam_ptr
++ = flags
;
557 /* total parameters, needed to go backward in the instruction stream */
558 *gen_opparam_ptr
++ = 1 + nb_rets
+ nb_params
+ 3;
562 #if TCG_TARGET_REG_BITS < 64
563 /* Note: we convert the 64 bit args to 32 bit and do some alignment
564 and endian swap. Maybe it would be better to do the alignment
565 and endian swap in tcg_reg_alloc_call(). */
566 void tcg_gen_call(TCGContext
*s
, TCGv func
, unsigned int flags
,
567 unsigned int nb_rets
, const TCGv
*rets
,
568 unsigned int nb_params
, const TCGv
*args1
)
570 TCGv ret
, *args2
, rets_2
[2], arg
;
575 if (tcg_get_base_type(s
, ret
) == TCG_TYPE_I64
) {
577 #ifdef TCG_TARGET_WORDS_BIGENDIAN
578 rets_2
[0] = TCGV_HIGH(ret
);
582 rets_2
[1] = TCGV_HIGH(ret
);
587 args2
= alloca((nb_params
* 3) * sizeof(TCGv
));
589 call_type
= (flags
& TCG_CALL_TYPE_MASK
);
590 for(i
= 0; i
< nb_params
; i
++) {
592 if (tcg_get_base_type(s
, arg
) == TCG_TYPE_I64
) {
593 #ifdef TCG_TARGET_I386
594 /* REGPARM case: if the third parameter is 64 bit, it is
595 allocated on the stack */
596 if (j
== 2 && call_type
== TCG_CALL_TYPE_REGPARM
) {
597 call_type
= TCG_CALL_TYPE_REGPARM_2
;
598 flags
= (flags
& ~TCG_CALL_TYPE_MASK
) | call_type
;
601 args2
[j
++] = TCGV_HIGH(arg
);
603 #ifdef TCG_TARGET_CALL_ALIGN_ARGS
604 /* some targets want aligned 64 bit args */
606 args2
[j
++] = TCG_CALL_DUMMY_ARG
;
609 #ifdef TCG_TARGET_WORDS_BIGENDIAN
610 args2
[j
++] = TCGV_HIGH(arg
);
614 args2
[j
++] = TCGV_HIGH(arg
);
621 tcg_gen_call_internal(s
, func
, flags
,
622 nb_rets
, rets
, j
, args2
);
625 void tcg_gen_call(TCGContext
*s
, TCGv func
, unsigned int flags
,
626 unsigned int nb_rets
, const TCGv
*rets
,
627 unsigned int nb_params
, const TCGv
*args1
)
629 tcg_gen_call_internal(s
, func
, flags
,
630 nb_rets
, rets
, nb_params
, args1
);
634 #if TCG_TARGET_REG_BITS == 32
635 void tcg_gen_shifti_i64(TCGv ret
, TCGv arg1
,
636 int c
, int right
, int arith
)
639 tcg_gen_mov_i32(ret
, arg1
);
640 tcg_gen_mov_i32(TCGV_HIGH(ret
), TCGV_HIGH(arg1
));
641 } else if (c
>= 32) {
645 tcg_gen_sari_i32(ret
, TCGV_HIGH(arg1
), c
);
646 tcg_gen_sari_i32(TCGV_HIGH(ret
), TCGV_HIGH(arg1
), 31);
648 tcg_gen_shri_i32(ret
, TCGV_HIGH(arg1
), c
);
649 tcg_gen_movi_i32(TCGV_HIGH(ret
), 0);
652 tcg_gen_shli_i32(TCGV_HIGH(ret
), arg1
, c
);
653 tcg_gen_movi_i32(ret
, 0);
658 t0
= tcg_temp_new(TCG_TYPE_I32
);
659 t1
= tcg_temp_new(TCG_TYPE_I32
);
661 tcg_gen_shli_i32(t0
, TCGV_HIGH(arg1
), 32 - c
);
663 tcg_gen_sari_i32(t1
, TCGV_HIGH(arg1
), c
);
665 tcg_gen_shri_i32(t1
, TCGV_HIGH(arg1
), c
);
666 tcg_gen_shri_i32(ret
, arg1
, c
);
667 tcg_gen_or_i32(ret
, ret
, t0
);
668 tcg_gen_mov_i32(TCGV_HIGH(ret
), t1
);
670 tcg_gen_shri_i32(t0
, arg1
, 32 - c
);
671 /* Note: ret can be the same as arg1, so we use t1 */
672 tcg_gen_shli_i32(t1
, arg1
, c
);
673 tcg_gen_shli_i32(TCGV_HIGH(ret
), TCGV_HIGH(arg1
), c
);
674 tcg_gen_or_i32(TCGV_HIGH(ret
), TCGV_HIGH(ret
), t0
);
675 tcg_gen_mov_i32(ret
, t1
);
681 void tcg_reg_alloc_start(TCGContext
*s
)
685 for(i
= 0; i
< s
->nb_globals
; i
++) {
688 ts
->val_type
= TEMP_VAL_REG
;
690 ts
->val_type
= TEMP_VAL_MEM
;
693 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
694 s
->reg_to_temp
[i
] = -1;
698 static char *tcg_get_arg_str_idx(TCGContext
*s
, char *buf
, int buf_size
,
704 if (idx
< s
->nb_globals
) {
705 pstrcpy(buf
, buf_size
, ts
->name
);
707 if (ts
->val_type
== TEMP_VAL_CONST
) {
708 snprintf(buf
, buf_size
, "$0x%" TCG_PRIlx
, ts
->val
);
710 snprintf(buf
, buf_size
, "tmp%d", idx
- s
->nb_globals
);
716 char *tcg_get_arg_str(TCGContext
*s
, char *buf
, int buf_size
, TCGv arg
)
718 return tcg_get_arg_str_idx(s
, buf
, buf_size
, GET_TCGV(arg
));
721 void tcg_dump_ops(TCGContext
*s
, FILE *outfile
)
723 const uint16_t *opc_ptr
;
726 int c
, i
, k
, nb_oargs
, nb_iargs
, nb_cargs
;
730 opc_ptr
= gen_opc_buf
;
731 args
= gen_opparam_buf
;
732 while (opc_ptr
< gen_opc_ptr
) {
734 def
= &tcg_op_defs
[c
];
735 fprintf(outfile
, " %s ", def
->name
);
736 if (c
== INDEX_op_call
) {
738 /* variable number of arguments */
740 nb_oargs
= arg
>> 16;
741 nb_iargs
= arg
& 0xffff;
742 nb_cargs
= def
->nb_cargs
;
745 /* XXX: dump helper name for call */
746 fprintf(outfile
, "%s",
747 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[nb_oargs
+ nb_iargs
- 1]));
749 fprintf(outfile
, ",$0x%" TCG_PRIlx
,
750 args
[nb_oargs
+ nb_iargs
]);
752 fprintf(outfile
, ",$%d", nb_oargs
);
753 for(i
= 0; i
< nb_oargs
; i
++) {
754 fprintf(outfile
, ",");
755 fprintf(outfile
, "%s",
756 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[i
]));
758 for(i
= 0; i
< (nb_iargs
- 1); i
++) {
759 fprintf(outfile
, ",");
760 if (args
[nb_oargs
+ i
] == TCG_CALL_DUMMY_ARG
) {
761 fprintf(outfile
, "<dummy>");
763 fprintf(outfile
, "%s",
764 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[nb_oargs
+ i
]));
768 if (c
== INDEX_op_nopn
) {
769 /* variable number of arguments */
774 nb_oargs
= def
->nb_oargs
;
775 nb_iargs
= def
->nb_iargs
;
776 nb_cargs
= def
->nb_cargs
;
780 for(i
= 0; i
< nb_oargs
; i
++) {
782 fprintf(outfile
, ",");
783 fprintf(outfile
, "%s",
784 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[k
++]));
786 for(i
= 0; i
< nb_iargs
; i
++) {
788 fprintf(outfile
, ",");
789 fprintf(outfile
, "%s",
790 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), args
[k
++]));
792 for(i
= 0; i
< nb_cargs
; i
++) {
794 fprintf(outfile
, ",");
796 fprintf(outfile
, "$0x%" TCG_PRIlx
, arg
);
799 fprintf(outfile
, "\n");
800 args
+= nb_iargs
+ nb_oargs
+ nb_cargs
;
804 /* we give more priority to constraints with less registers */
805 static int get_constraint_priority(const TCGOpDef
*def
, int k
)
807 const TCGArgConstraint
*arg_ct
;
810 arg_ct
= &def
->args_ct
[k
];
811 if (arg_ct
->ct
& TCG_CT_ALIAS
) {
812 /* an alias is equivalent to a single register */
815 if (!(arg_ct
->ct
& TCG_CT_REG
))
818 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
819 if (tcg_regset_test_reg(arg_ct
->u
.regs
, i
))
823 return TCG_TARGET_NB_REGS
- n
+ 1;
826 /* sort from highest priority to lowest */
827 static void sort_constraints(TCGOpDef
*def
, int start
, int n
)
829 int i
, j
, p1
, p2
, tmp
;
831 for(i
= 0; i
< n
; i
++)
832 def
->sorted_args
[start
+ i
] = start
+ i
;
835 for(i
= 0; i
< n
- 1; i
++) {
836 for(j
= i
+ 1; j
< n
; j
++) {
837 p1
= get_constraint_priority(def
, def
->sorted_args
[start
+ i
]);
838 p2
= get_constraint_priority(def
, def
->sorted_args
[start
+ j
]);
840 tmp
= def
->sorted_args
[start
+ i
];
841 def
->sorted_args
[start
+ i
] = def
->sorted_args
[start
+ j
];
842 def
->sorted_args
[start
+ j
] = tmp
;
848 void tcg_add_target_add_op_defs(const TCGTargetOpDef
*tdefs
)
859 assert(op
>= 0 && op
< NB_OPS
);
860 def
= &tcg_op_defs
[op
];
861 nb_args
= def
->nb_iargs
+ def
->nb_oargs
;
862 for(i
= 0; i
< nb_args
; i
++) {
863 ct_str
= tdefs
->args_ct_str
[i
];
864 tcg_regset_clear(def
->args_ct
[i
].u
.regs
);
865 def
->args_ct
[i
].ct
= 0;
866 if (ct_str
[0] >= '0' && ct_str
[0] <= '9') {
868 oarg
= ct_str
[0] - '0';
869 assert(oarg
< def
->nb_oargs
);
870 assert(def
->args_ct
[oarg
].ct
& TCG_CT_REG
);
871 /* TCG_CT_ALIAS is for the output arguments. The input
872 argument is tagged with TCG_CT_IALIAS. */
873 def
->args_ct
[i
] = def
->args_ct
[oarg
];
874 def
->args_ct
[oarg
].ct
= TCG_CT_ALIAS
;
875 def
->args_ct
[oarg
].alias_index
= i
;
876 def
->args_ct
[i
].ct
|= TCG_CT_IALIAS
;
877 def
->args_ct
[i
].alias_index
= oarg
;
884 def
->args_ct
[i
].ct
|= TCG_CT_CONST
;
888 if (target_parse_constraint(&def
->args_ct
[i
], &ct_str
) < 0) {
889 fprintf(stderr
, "Invalid constraint '%s' for arg %d of operation '%s'\n",
890 ct_str
, i
, def
->name
);
898 /* sort the constraints (XXX: this is just an heuristic) */
899 sort_constraints(def
, 0, def
->nb_oargs
);
900 sort_constraints(def
, def
->nb_oargs
, def
->nb_iargs
);
906 printf("%s: sorted=", def
->name
);
907 for(i
= 0; i
< def
->nb_oargs
+ def
->nb_iargs
; i
++)
908 printf(" %d", def
->sorted_args
[i
]);
917 #ifdef USE_LIVENESS_ANALYSIS
919 /* set a nop for an operation using 'nb_args' */
920 static inline void tcg_set_nop(TCGContext
*s
, uint16_t *opc_ptr
,
921 TCGArg
*args
, int nb_args
)
924 *opc_ptr
= INDEX_op_nop
;
926 *opc_ptr
= INDEX_op_nopn
;
928 args
[nb_args
- 1] = nb_args
;
932 /* liveness analysis: end of basic block: globals are live, temps are dead */
933 static inline void tcg_la_bb_end(TCGContext
*s
, uint8_t *dead_temps
)
935 memset(dead_temps
, 0, s
->nb_globals
);
936 memset(dead_temps
+ s
->nb_globals
, 1, s
->nb_temps
- s
->nb_globals
);
939 /* Liveness analysis : update the opc_dead_iargs array to tell if a
940 given input arguments is dead. Instructions updating dead
941 temporaries are removed. */
942 void tcg_liveness_analysis(TCGContext
*s
)
944 int i
, op_index
, op
, nb_args
, nb_iargs
, nb_oargs
, arg
, nb_ops
;
948 unsigned int dead_iargs
;
950 gen_opc_ptr
++; /* skip end */
952 nb_ops
= gen_opc_ptr
- gen_opc_buf
;
954 /* XXX: make it really dynamic */
955 s
->op_dead_iargs
= tcg_malloc(OPC_BUF_SIZE
* sizeof(uint16_t));
957 dead_temps
= tcg_malloc(s
->nb_temps
);
958 memset(dead_temps
, 1, s
->nb_temps
);
960 args
= gen_opparam_ptr
;
961 op_index
= nb_ops
- 1;
962 while (op_index
>= 0) {
963 op
= gen_opc_buf
[op_index
];
964 def
= &tcg_op_defs
[op
];
972 nb_iargs
= args
[0] & 0xffff;
973 nb_oargs
= args
[0] >> 16;
975 call_flags
= args
[nb_oargs
+ nb_iargs
];
977 /* pure functions can be removed if their result is not
979 if (call_flags
& TCG_CALL_PURE
) {
980 for(i
= 0; i
< nb_oargs
; i
++) {
982 if (!dead_temps
[arg
])
983 goto do_not_remove_call
;
985 tcg_set_nop(s
, gen_opc_buf
+ op_index
,
990 /* output args are dead */
991 for(i
= 0; i
< nb_oargs
; i
++) {
996 /* globals are live (they may be used by the call) */
997 memset(dead_temps
, 0, s
->nb_globals
);
999 /* input args are live */
1001 for(i
= 0; i
< nb_iargs
; i
++) {
1002 arg
= args
[i
+ nb_oargs
];
1003 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1004 if (dead_temps
[arg
]) {
1005 dead_iargs
|= (1 << i
);
1007 dead_temps
[arg
] = 0;
1010 s
->op_dead_iargs
[op_index
] = dead_iargs
;
1015 case INDEX_op_set_label
:
1017 /* mark end of basic block */
1018 tcg_la_bb_end(s
, dead_temps
);
1024 case INDEX_op_discard
:
1026 /* mark the temporary as dead */
1027 dead_temps
[args
[0]] = 1;
1029 case INDEX_op_macro_2
:
1031 int dead_args
[2], macro_id
;
1032 int saved_op_index
, saved_arg_index
;
1033 int macro_op_index
, macro_arg_index
;
1034 int macro_end_op_index
, macro_end_arg_index
;
1039 dead_args
[0] = dead_temps
[args
[0]];
1040 dead_args
[1] = dead_temps
[args
[1]];
1043 /* call the macro function which generate code
1044 depending on the live outputs */
1045 saved_op_index
= op_index
;
1046 saved_arg_index
= args
- gen_opparam_buf
;
1048 /* add a macro start instruction */
1049 *gen_opc_ptr
++ = INDEX_op_macro_start
;
1050 *gen_opparam_ptr
++ = saved_op_index
;
1051 *gen_opparam_ptr
++ = saved_arg_index
;
1053 macro_op_index
= gen_opc_ptr
- gen_opc_buf
;
1054 macro_arg_index
= gen_opparam_ptr
- gen_opparam_buf
;
1056 last_nb_temps
= s
->nb_temps
;
1058 s
->macro_func(s
, macro_id
, dead_args
);
1060 /* realloc temp info (XXX: make it faster) */
1061 if (s
->nb_temps
> last_nb_temps
) {
1062 uint8_t *new_dead_temps
;
1064 new_dead_temps
= tcg_malloc(s
->nb_temps
);
1065 memcpy(new_dead_temps
, dead_temps
, last_nb_temps
);
1066 memset(new_dead_temps
+ last_nb_temps
, 1,
1067 s
->nb_temps
- last_nb_temps
);
1068 dead_temps
= new_dead_temps
;
1071 macro_end_op_index
= gen_opc_ptr
- gen_opc_buf
;
1072 macro_end_arg_index
= gen_opparam_ptr
- gen_opparam_buf
;
1074 /* end of macro: add a goto to the next instruction */
1075 *gen_opc_ptr
++ = INDEX_op_macro_end
;
1076 *gen_opparam_ptr
++ = op_index
+ 1;
1077 *gen_opparam_ptr
++ = saved_arg_index
+ nb_args
;
1079 /* modify the macro operation to be a macro_goto */
1080 gen_opc_buf
[op_index
] = INDEX_op_macro_goto
;
1081 args
[0] = macro_op_index
;
1082 args
[1] = macro_arg_index
;
1083 args
[2] = 0; /* dummy third arg to match the
1086 /* set the next instruction to the end of the macro */
1087 op_index
= macro_end_op_index
;
1088 args
= macro_end_arg_index
+ gen_opparam_buf
;
1091 case INDEX_op_macro_start
:
1094 args
= gen_opparam_buf
+ args
[1];
1096 case INDEX_op_macro_goto
:
1097 case INDEX_op_macro_end
:
1098 tcg_abort(); /* should never happen in liveness analysis */
1101 /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
1103 if (op
> INDEX_op_end
) {
1104 args
-= def
->nb_args
;
1105 nb_iargs
= def
->nb_iargs
;
1106 nb_oargs
= def
->nb_oargs
;
1108 /* Test if the operation can be removed because all
1109 its outputs are dead. We assume that nb_oargs == 0
1110 implies side effects */
1111 if (!(def
->flags
& TCG_OPF_SIDE_EFFECTS
) && nb_oargs
!= 0) {
1112 for(i
= 0; i
< nb_oargs
; i
++) {
1114 if (!dead_temps
[arg
])
1117 tcg_set_nop(s
, gen_opc_buf
+ op_index
, args
, def
->nb_args
);
1118 #ifdef CONFIG_PROFILER
1120 extern int64_t dyngen_tcg_del_op_count
;
1121 dyngen_tcg_del_op_count
++;
1127 /* output args are dead */
1128 for(i
= 0; i
< nb_oargs
; i
++) {
1130 dead_temps
[arg
] = 1;
1133 /* if end of basic block, update */
1134 if (def
->flags
& TCG_OPF_BB_END
) {
1135 tcg_la_bb_end(s
, dead_temps
);
1136 } else if (def
->flags
& TCG_OPF_CALL_CLOBBER
) {
1137 /* globals are live */
1138 memset(dead_temps
, 0, s
->nb_globals
);
1141 /* input args are live */
1143 for(i
= 0; i
< nb_iargs
; i
++) {
1144 arg
= args
[i
+ nb_oargs
];
1145 if (dead_temps
[arg
]) {
1146 dead_iargs
|= (1 << i
);
1148 dead_temps
[arg
] = 0;
1150 s
->op_dead_iargs
[op_index
] = dead_iargs
;
1153 /* legacy dyngen operations */
1154 args
-= def
->nb_args
;
1155 /* mark end of basic block */
1156 tcg_la_bb_end(s
, dead_temps
);
1163 if (args
!= gen_opparam_buf
)
1167 /* dummy liveness analysis */
1168 void tcg_liveness_analysis(TCGContext
*s
)
1171 nb_ops
= gen_opc_ptr
- gen_opc_buf
;
1173 s
->op_dead_iargs
= tcg_malloc(nb_ops
* sizeof(uint16_t));
1174 memset(s
->op_dead_iargs
, 0, nb_ops
* sizeof(uint16_t));
1179 static void dump_regs(TCGContext
*s
)
1185 for(i
= 0; i
< s
->nb_temps
; i
++) {
1187 printf(" %10s: ", tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), i
));
1188 switch(ts
->val_type
) {
1190 printf("%s", tcg_target_reg_names
[ts
->reg
]);
1193 printf("%d(%s)", (int)ts
->mem_offset
, tcg_target_reg_names
[ts
->mem_reg
]);
1195 case TEMP_VAL_CONST
:
1196 printf("$0x%" TCG_PRIlx
, ts
->val
);
1208 for(i
= 0; i
< TCG_TARGET_NB_REGS
; i
++) {
1209 if (s
->reg_to_temp
[i
] >= 0) {
1211 tcg_target_reg_names
[i
],
1212 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), s
->reg_to_temp
[i
]));
1217 static void check_regs(TCGContext
*s
)
1223 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1224 k
= s
->reg_to_temp
[reg
];
1227 if (ts
->val_type
!= TEMP_VAL_REG
||
1229 printf("Inconsistency for register %s:\n",
1230 tcg_target_reg_names
[reg
]);
1235 for(k
= 0; k
< s
->nb_temps
; k
++) {
1237 if (ts
->val_type
== TEMP_VAL_REG
&&
1239 s
->reg_to_temp
[ts
->reg
] != k
) {
1240 printf("Inconsistency for temp %s:\n",
1241 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), k
));
1243 printf("reg state:\n");
1247 if (ts
->val_type
== TEMP_VAL_CONST
&& k
< s
->nb_globals
) {
1248 printf("constant forbidden in global %s\n",
1249 tcg_get_arg_str_idx(s
, buf
, sizeof(buf
), k
));
1256 static void temp_allocate_frame(TCGContext
*s
, int temp
)
1259 ts
= &s
->temps
[temp
];
1260 s
->current_frame_offset
= (s
->current_frame_offset
+ sizeof(tcg_target_long
) - 1) & ~(sizeof(tcg_target_long
) - 1);
1261 if (s
->current_frame_offset
+ sizeof(tcg_target_long
) > s
->frame_end
)
1263 ts
->mem_offset
= s
->current_frame_offset
;
1264 ts
->mem_reg
= s
->frame_reg
;
1265 ts
->mem_allocated
= 1;
1266 s
->current_frame_offset
+= sizeof(tcg_target_long
);
1269 /* free register 'reg' by spilling the corresponding temporary if necessary */
1270 static void tcg_reg_free(TCGContext
*s
, int reg
)
1275 temp
= s
->reg_to_temp
[reg
];
1277 ts
= &s
->temps
[temp
];
1278 assert(ts
->val_type
== TEMP_VAL_REG
);
1279 if (!ts
->mem_coherent
) {
1280 if (!ts
->mem_allocated
)
1281 temp_allocate_frame(s
, temp
);
1282 tcg_out_st(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1284 ts
->val_type
= TEMP_VAL_MEM
;
1285 s
->reg_to_temp
[reg
] = -1;
1289 /* Allocate a register belonging to reg1 & ~reg2 */
1290 static int tcg_reg_alloc(TCGContext
*s
, TCGRegSet reg1
, TCGRegSet reg2
)
1295 tcg_regset_andnot(reg_ct
, reg1
, reg2
);
1297 /* first try free registers */
1298 for(i
= 0; i
< ARRAY_SIZE(tcg_target_reg_alloc_order
); i
++) {
1299 reg
= tcg_target_reg_alloc_order
[i
];
1300 if (tcg_regset_test_reg(reg_ct
, reg
) && s
->reg_to_temp
[reg
] == -1)
1304 /* XXX: do better spill choice */
1305 for(i
= 0; i
< ARRAY_SIZE(tcg_target_reg_alloc_order
); i
++) {
1306 reg
= tcg_target_reg_alloc_order
[i
];
1307 if (tcg_regset_test_reg(reg_ct
, reg
)) {
1308 tcg_reg_free(s
, reg
);
1316 /* save globals to their cannonical location and assume they can be
1317 modified be the following code. */
1318 static void save_globals(TCGContext
*s
)
1323 for(i
= 0; i
< s
->nb_globals
; i
++) {
1325 if (!ts
->fixed_reg
) {
1326 if (ts
->val_type
== TEMP_VAL_REG
) {
1327 tcg_reg_free(s
, ts
->reg
);
1328 } else if (ts
->val_type
== TEMP_VAL_DEAD
) {
1329 ts
->val_type
= TEMP_VAL_MEM
;
1335 /* at the end of a basic block, we assume all temporaries are dead and
1336 all globals are stored at their canonical location */
1337 /* XXX: optimize by handling constants in another array ? */
1338 void tcg_reg_alloc_bb_end(TCGContext
*s
)
1345 for(i
= s
->nb_globals
; i
< s
->nb_temps
; i
++) {
1347 if (ts
->val_type
!= TEMP_VAL_CONST
) {
1348 if (ts
->val_type
== TEMP_VAL_REG
) {
1349 s
->reg_to_temp
[ts
->reg
] = -1;
1351 ts
->val_type
= TEMP_VAL_DEAD
;
1356 #define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
1358 static void tcg_reg_alloc_mov(TCGContext
*s
, const TCGOpDef
*def
,
1360 unsigned int dead_iargs
)
1364 const TCGArgConstraint
*arg_ct
;
1366 ots
= &s
->temps
[args
[0]];
1367 ts
= &s
->temps
[args
[1]];
1368 arg_ct
= &def
->args_ct
[0];
1370 if (ts
->val_type
== TEMP_VAL_REG
) {
1371 if (IS_DEAD_IARG(0) && !ts
->fixed_reg
&& !ots
->fixed_reg
) {
1372 /* the mov can be suppressed */
1373 if (ots
->val_type
== TEMP_VAL_REG
)
1374 s
->reg_to_temp
[ots
->reg
] = -1;
1376 s
->reg_to_temp
[reg
] = -1;
1377 ts
->val_type
= TEMP_VAL_DEAD
;
1379 if (ots
->val_type
== TEMP_VAL_REG
) {
1382 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, s
->reserved_regs
);
1384 if (ts
->reg
!= reg
) {
1385 tcg_out_mov(s
, reg
, ts
->reg
);
1388 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1389 if (ots
->val_type
== TEMP_VAL_REG
) {
1392 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, s
->reserved_regs
);
1394 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1395 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1396 if (ots
->val_type
== TEMP_VAL_REG
) {
1399 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, s
->reserved_regs
);
1401 tcg_out_movi(s
, ots
->type
, reg
, ts
->val
);
1405 s
->reg_to_temp
[reg
] = args
[0];
1407 ots
->val_type
= TEMP_VAL_REG
;
1408 ots
->mem_coherent
= 0;
1411 static void tcg_reg_alloc_op(TCGContext
*s
,
1412 const TCGOpDef
*def
, int opc
,
1414 unsigned int dead_iargs
)
1416 TCGRegSet allocated_regs
;
1417 int i
, k
, nb_iargs
, nb_oargs
, reg
;
1419 const TCGArgConstraint
*arg_ct
;
1421 TCGArg new_args
[TCG_MAX_OP_ARGS
];
1422 int const_args
[TCG_MAX_OP_ARGS
];
1424 nb_oargs
= def
->nb_oargs
;
1425 nb_iargs
= def
->nb_iargs
;
1427 /* copy constants */
1428 memcpy(new_args
+ nb_oargs
+ nb_iargs
,
1429 args
+ nb_oargs
+ nb_iargs
,
1430 sizeof(TCGArg
) * def
->nb_cargs
);
1432 /* satisfy input constraints */
1433 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1434 for(k
= 0; k
< nb_iargs
; k
++) {
1435 i
= def
->sorted_args
[nb_oargs
+ k
];
1437 arg_ct
= &def
->args_ct
[i
];
1438 ts
= &s
->temps
[arg
];
1439 if (ts
->val_type
== TEMP_VAL_MEM
) {
1440 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1441 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1442 ts
->val_type
= TEMP_VAL_REG
;
1444 ts
->mem_coherent
= 1;
1445 s
->reg_to_temp
[reg
] = arg
;
1446 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1447 if (tcg_target_const_match(ts
->val
, arg_ct
)) {
1448 /* constant is OK for instruction */
1450 new_args
[i
] = ts
->val
;
1453 /* need to move to a register*/
1454 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1455 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1459 assert(ts
->val_type
== TEMP_VAL_REG
);
1460 if (arg_ct
->ct
& TCG_CT_IALIAS
) {
1461 if (ts
->fixed_reg
) {
1462 /* if fixed register, we must allocate a new register
1463 if the alias is not the same register */
1464 if (arg
!= args
[arg_ct
->alias_index
])
1465 goto allocate_in_reg
;
1467 /* if the input is aliased to an output and if it is
1468 not dead after the instruction, we must allocate
1469 a new register and move it */
1470 if (!IS_DEAD_IARG(i
- nb_oargs
))
1471 goto allocate_in_reg
;
1475 if (tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1476 /* nothing to do : the constraint is satisfied */
1479 /* allocate a new register matching the constraint
1480 and move the temporary register into it */
1481 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1482 tcg_out_mov(s
, reg
, ts
->reg
);
1487 tcg_regset_set_reg(allocated_regs
, reg
);
1491 /* mark dead temporaries and free the associated registers */
1492 for(i
= 0; i
< nb_iargs
; i
++) {
1493 arg
= args
[nb_oargs
+ i
];
1494 if (IS_DEAD_IARG(i
)) {
1495 ts
= &s
->temps
[arg
];
1496 if (ts
->val_type
!= TEMP_VAL_CONST
&& !ts
->fixed_reg
) {
1497 if (ts
->val_type
== TEMP_VAL_REG
)
1498 s
->reg_to_temp
[ts
->reg
] = -1;
1499 ts
->val_type
= TEMP_VAL_DEAD
;
1504 if (def
->flags
& TCG_OPF_CALL_CLOBBER
) {
1505 /* XXX: permit generic clobber register list ? */
1506 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1507 if (tcg_regset_test_reg(tcg_target_call_clobber_regs
, reg
)) {
1508 tcg_reg_free(s
, reg
);
1511 /* XXX: for load/store we could do that only for the slow path
1512 (i.e. when a memory callback is called) */
1514 /* store globals and free associated registers (we assume the insn
1515 can modify any global. */
1519 /* satisfy the output constraints */
1520 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1521 for(k
= 0; k
< nb_oargs
; k
++) {
1522 i
= def
->sorted_args
[k
];
1524 arg_ct
= &def
->args_ct
[i
];
1525 ts
= &s
->temps
[arg
];
1526 if (arg_ct
->ct
& TCG_CT_ALIAS
) {
1527 reg
= new_args
[arg_ct
->alias_index
];
1529 /* if fixed register, we try to use it */
1531 if (ts
->fixed_reg
&&
1532 tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1535 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1537 tcg_regset_set_reg(allocated_regs
, reg
);
1538 /* if a fixed register is used, then a move will be done afterwards */
1539 if (!ts
->fixed_reg
) {
1540 if (ts
->val_type
== TEMP_VAL_REG
)
1541 s
->reg_to_temp
[ts
->reg
] = -1;
1542 ts
->val_type
= TEMP_VAL_REG
;
1544 /* temp value is modified, so the value kept in memory is
1545 potentially not the same */
1546 ts
->mem_coherent
= 0;
1547 s
->reg_to_temp
[reg
] = arg
;
1553 if (def
->flags
& TCG_OPF_BB_END
)
1554 tcg_reg_alloc_bb_end(s
);
1556 /* emit instruction */
1557 tcg_out_op(s
, opc
, new_args
, const_args
);
1559 /* move the outputs in the correct register if needed */
1560 for(i
= 0; i
< nb_oargs
; i
++) {
1561 ts
= &s
->temps
[args
[i
]];
1563 if (ts
->fixed_reg
&& ts
->reg
!= reg
) {
1564 tcg_out_mov(s
, ts
->reg
, reg
);
1569 #ifdef TCG_TARGET_STACK_GROWSUP
1570 #define STACK_DIR(x) (-(x))
1572 #define STACK_DIR(x) (x)
1575 static int tcg_reg_alloc_call(TCGContext
*s
, const TCGOpDef
*def
,
1576 int opc
, const TCGArg
*args
,
1577 unsigned int dead_iargs
)
1579 int nb_iargs
, nb_oargs
, flags
, nb_regs
, i
, reg
, nb_params
;
1580 TCGArg arg
, func_arg
;
1582 tcg_target_long stack_offset
, call_stack_size
, func_addr
;
1583 int const_func_arg
, allocate_args
;
1584 TCGRegSet allocated_regs
;
1585 const TCGArgConstraint
*arg_ct
;
1589 nb_oargs
= arg
>> 16;
1590 nb_iargs
= arg
& 0xffff;
1591 nb_params
= nb_iargs
- 1;
1593 flags
= args
[nb_oargs
+ nb_iargs
];
1595 nb_regs
= tcg_target_get_call_iarg_regs_count(flags
);
1596 if (nb_regs
> nb_params
)
1597 nb_regs
= nb_params
;
1599 /* assign stack slots first */
1600 /* XXX: preallocate call stack */
1601 call_stack_size
= (nb_params
- nb_regs
) * sizeof(tcg_target_long
);
1602 call_stack_size
= (call_stack_size
+ TCG_TARGET_STACK_ALIGN
- 1) &
1603 ~(TCG_TARGET_STACK_ALIGN
- 1);
1604 allocate_args
= (call_stack_size
> TCG_STATIC_CALL_ARGS_SIZE
);
1605 if (allocate_args
) {
1606 tcg_out_addi(s
, TCG_REG_CALL_STACK
, -STACK_DIR(call_stack_size
));
1609 stack_offset
= TCG_TARGET_CALL_STACK_OFFSET
;
1610 for(i
= nb_regs
; i
< nb_params
; i
++) {
1611 arg
= args
[nb_oargs
+ i
];
1612 #ifdef TCG_TARGET_STACK_GROWSUP
1613 stack_offset
-= sizeof(tcg_target_long
);
1615 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1616 ts
= &s
->temps
[arg
];
1617 if (ts
->val_type
== TEMP_VAL_REG
) {
1618 tcg_out_st(s
, ts
->type
, ts
->reg
, TCG_REG_CALL_STACK
, stack_offset
);
1619 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1620 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1622 /* XXX: not correct if reading values from the stack */
1623 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1624 tcg_out_st(s
, ts
->type
, reg
, TCG_REG_CALL_STACK
, stack_offset
);
1625 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1626 reg
= tcg_reg_alloc(s
, tcg_target_available_regs
[ts
->type
],
1628 /* XXX: sign extend may be needed on some targets */
1629 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1630 tcg_out_st(s
, ts
->type
, reg
, TCG_REG_CALL_STACK
, stack_offset
);
1635 #ifndef TCG_TARGET_STACK_GROWSUP
1636 stack_offset
+= sizeof(tcg_target_long
);
1640 /* assign input registers */
1641 tcg_regset_set(allocated_regs
, s
->reserved_regs
);
1642 for(i
= 0; i
< nb_regs
; i
++) {
1643 arg
= args
[nb_oargs
+ i
];
1644 if (arg
!= TCG_CALL_DUMMY_ARG
) {
1645 ts
= &s
->temps
[arg
];
1646 reg
= tcg_target_call_iarg_regs
[i
];
1647 tcg_reg_free(s
, reg
);
1648 if (ts
->val_type
== TEMP_VAL_REG
) {
1649 if (ts
->reg
!= reg
) {
1650 tcg_out_mov(s
, reg
, ts
->reg
);
1652 } else if (ts
->val_type
== TEMP_VAL_MEM
) {
1653 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1654 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1655 /* XXX: sign extend ? */
1656 tcg_out_movi(s
, ts
->type
, reg
, ts
->val
);
1660 tcg_regset_set_reg(allocated_regs
, reg
);
1664 /* assign function address */
1665 func_arg
= args
[nb_oargs
+ nb_iargs
- 1];
1666 arg_ct
= &def
->args_ct
[0];
1667 ts
= &s
->temps
[func_arg
];
1668 func_addr
= ts
->val
;
1670 if (ts
->val_type
== TEMP_VAL_MEM
) {
1671 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1672 tcg_out_ld(s
, ts
->type
, reg
, ts
->mem_reg
, ts
->mem_offset
);
1674 } else if (ts
->val_type
== TEMP_VAL_REG
) {
1676 if (!tcg_regset_test_reg(arg_ct
->u
.regs
, reg
)) {
1677 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1678 tcg_out_mov(s
, reg
, ts
->reg
);
1681 } else if (ts
->val_type
== TEMP_VAL_CONST
) {
1682 if (tcg_target_const_match(func_addr
, arg_ct
)) {
1684 func_arg
= func_addr
;
1686 reg
= tcg_reg_alloc(s
, arg_ct
->u
.regs
, allocated_regs
);
1687 tcg_out_movi(s
, ts
->type
, reg
, func_addr
);
1694 /* mark dead temporaries and free the associated registers */
1695 for(i
= 0; i
< nb_iargs
; i
++) {
1696 arg
= args
[nb_oargs
+ i
];
1697 if (IS_DEAD_IARG(i
)) {
1698 ts
= &s
->temps
[arg
];
1699 if (ts
->val_type
!= TEMP_VAL_CONST
&& !ts
->fixed_reg
) {
1700 if (ts
->val_type
== TEMP_VAL_REG
)
1701 s
->reg_to_temp
[ts
->reg
] = -1;
1702 ts
->val_type
= TEMP_VAL_DEAD
;
1707 /* clobber call registers */
1708 for(reg
= 0; reg
< TCG_TARGET_NB_REGS
; reg
++) {
1709 if (tcg_regset_test_reg(tcg_target_call_clobber_regs
, reg
)) {
1710 tcg_reg_free(s
, reg
);
1714 /* store globals and free associated registers (we assume the call
1715 can modify any global. */
1718 tcg_out_op(s
, opc
, &func_arg
, &const_func_arg
);
1720 if (allocate_args
) {
1721 tcg_out_addi(s
, TCG_REG_CALL_STACK
, STACK_DIR(call_stack_size
));
1724 /* assign output registers and emit moves if needed */
1725 for(i
= 0; i
< nb_oargs
; i
++) {
1727 ts
= &s
->temps
[arg
];
1728 reg
= tcg_target_call_oarg_regs
[i
];
1729 tcg_reg_free(s
, reg
);
1730 if (ts
->fixed_reg
) {
1731 if (ts
->reg
!= reg
) {
1732 tcg_out_mov(s
, ts
->reg
, reg
);
1735 if (ts
->val_type
== TEMP_VAL_REG
)
1736 s
->reg_to_temp
[ts
->reg
] = -1;
1737 ts
->val_type
= TEMP_VAL_REG
;
1739 ts
->mem_coherent
= 0;
1740 s
->reg_to_temp
[reg
] = arg
;
1744 return nb_iargs
+ nb_oargs
+ def
->nb_cargs
+ 1;
1747 #ifdef CONFIG_PROFILER
1749 static int64_t dyngen_table_op_count
[NB_OPS
];
1751 void dump_op_count(void)
1755 f
= fopen("/tmp/op1.log", "w");
1756 for(i
= 0; i
< INDEX_op_end
; i
++) {
1757 fprintf(f
, "%s %" PRId64
"\n", tcg_op_defs
[i
].name
, dyngen_table_op_count
[i
]);
1760 f
= fopen("/tmp/op2.log", "w");
1761 for(i
= INDEX_op_end
; i
< NB_OPS
; i
++) {
1762 fprintf(f
, "%s %" PRId64
"\n", tcg_op_defs
[i
].name
, dyngen_table_op_count
[i
]);
1769 static inline int tcg_gen_code_common(TCGContext
*s
, uint8_t *gen_code_buf
,
1772 int opc
, op_index
, macro_op_index
;
1773 const TCGOpDef
*def
;
1774 unsigned int dead_iargs
;
1778 if (unlikely(loglevel
& CPU_LOG_TB_OP
)) {
1779 fprintf(logfile
, "OP:\n");
1780 tcg_dump_ops(s
, logfile
);
1781 fprintf(logfile
, "\n");
1785 tcg_liveness_analysis(s
);
1788 if (unlikely(loglevel
& CPU_LOG_TB_OP_OPT
)) {
1789 fprintf(logfile
, "OP after la:\n");
1790 tcg_dump_ops(s
, logfile
);
1791 fprintf(logfile
, "\n");
1795 tcg_reg_alloc_start(s
);
1797 s
->code_buf
= gen_code_buf
;
1798 s
->code_ptr
= gen_code_buf
;
1800 macro_op_index
= -1;
1801 args
= gen_opparam_buf
;
1805 opc
= gen_opc_buf
[op_index
];
1806 #ifdef CONFIG_PROFILER
1807 dyngen_table_op_count
[opc
]++;
1809 def
= &tcg_op_defs
[opc
];
1811 printf("%s: %d %d %d\n", def
->name
,
1812 def
->nb_oargs
, def
->nb_iargs
, def
->nb_cargs
);
1816 case INDEX_op_mov_i32
:
1817 #if TCG_TARGET_REG_BITS == 64
1818 case INDEX_op_mov_i64
:
1820 dead_iargs
= s
->op_dead_iargs
[op_index
];
1821 tcg_reg_alloc_mov(s
, def
, args
, dead_iargs
);
1831 case INDEX_op_discard
:
1834 ts
= &s
->temps
[args
[0]];
1835 /* mark the temporary as dead */
1836 if (ts
->val_type
!= TEMP_VAL_CONST
&& !ts
->fixed_reg
) {
1837 if (ts
->val_type
== TEMP_VAL_REG
)
1838 s
->reg_to_temp
[ts
->reg
] = -1;
1839 ts
->val_type
= TEMP_VAL_DEAD
;
1843 case INDEX_op_macro_goto
:
1844 macro_op_index
= op_index
; /* only used for exceptions */
1845 op_index
= args
[0] - 1;
1846 args
= gen_opparam_buf
+ args
[1];
1848 case INDEX_op_macro_end
:
1849 macro_op_index
= -1; /* only used for exceptions */
1850 op_index
= args
[0] - 1;
1851 args
= gen_opparam_buf
+ args
[1];
1853 case INDEX_op_macro_start
:
1854 /* must never happen here */
1856 case INDEX_op_set_label
:
1857 tcg_reg_alloc_bb_end(s
);
1858 tcg_out_label(s
, args
[0], (long)s
->code_ptr
);
1861 dead_iargs
= s
->op_dead_iargs
[op_index
];
1862 args
+= tcg_reg_alloc_call(s
, def
, opc
, args
, dead_iargs
);
1867 #ifdef CONFIG_DYNGEN_OP
1868 case 0 ... INDEX_op_end
- 1:
1869 /* legacy dyngen ops */
1870 #ifdef CONFIG_PROFILER
1872 extern int64_t dyngen_old_op_count
;
1873 dyngen_old_op_count
++;
1876 tcg_reg_alloc_bb_end(s
);
1877 if (search_pc
>= 0) {
1878 s
->code_ptr
+= def
->copy_size
;
1879 args
+= def
->nb_args
;
1881 args
= dyngen_op(s
, opc
, args
);
1886 /* Note: in order to speed up the code, it would be much
1887 faster to have specialized register allocator functions for
1888 some common argument patterns */
1889 dead_iargs
= s
->op_dead_iargs
[op_index
];
1890 tcg_reg_alloc_op(s
, def
, opc
, args
, dead_iargs
);
1893 args
+= def
->nb_args
;
1895 if (search_pc
>= 0 && search_pc
< s
->code_ptr
- gen_code_buf
) {
1896 if (macro_op_index
>= 0)
1897 return macro_op_index
;
1910 int dyngen_code(TCGContext
*s
, uint8_t *gen_code_buf
)
1912 #ifdef CONFIG_PROFILER
1914 extern int64_t dyngen_op_count
;
1915 extern int dyngen_op_count_max
;
1917 n
= (gen_opc_ptr
- gen_opc_buf
);
1918 dyngen_op_count
+= n
;
1919 if (n
> dyngen_op_count_max
)
1920 dyngen_op_count_max
= n
;
1924 tcg_gen_code_common(s
, gen_code_buf
, -1);
1926 /* flush instruction cache */
1927 flush_icache_range((unsigned long)gen_code_buf
,
1928 (unsigned long)s
->code_ptr
);
1929 return s
->code_ptr
- gen_code_buf
;
1932 /* Return the index of the micro operation such as the pc after is <
1933 offset bytes from the start of the TB. The contents of gen_code_buf must
1934 not be changed, though writing the same values is ok.
1935 Return -1 if not found. */
1936 int dyngen_code_search_pc(TCGContext
*s
, uint8_t *gen_code_buf
, long offset
)
1938 return tcg_gen_code_common(s
, gen_code_buf
, offset
);