diff options
-rw-r--r-- | tcg/README | 5 | ||||
-rw-r--r-- | tcg/tcg-op.h | 29 | ||||
-rw-r--r-- | tcg/tcg-opc.h | 98 | ||||
-rw-r--r-- | tcg/tcg.c | 59 | ||||
-rw-r--r-- | tcg/tcg.h | 4 |
5 files changed, 124 insertions, 71 deletions
diff --git a/tcg/README b/tcg/README index 466e330368..fd72cad357 100644 --- a/tcg/README +++ b/tcg/README @@ -280,6 +280,11 @@ to zero. 64 bit byte swap +* discard_i32/i64 t0 + +Indicate that the value of t0 won't be used later. It is useful to +force dead code elimination. + ********* Type conversions * ext_i32_i64 t0, t1 diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index 6fb3138366..82aebb3219 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -865,7 +865,7 @@ static inline void tcg_gen_ext8s_i32(TCGv ret, TCGv arg) tcg_gen_op2(INDEX_op_ext8s_i32, ret, arg); #else tcg_gen_shli_i32(ret, arg, 24); - tcg_gen_sari_i32(ret, arg, 24); + tcg_gen_sari_i32(ret, ret, 24); #endif } @@ -875,7 +875,7 @@ static inline void tcg_gen_ext16s_i32(TCGv ret, TCGv arg) tcg_gen_op2(INDEX_op_ext16s_i32, ret, arg); #else tcg_gen_shli_i32(ret, arg, 16); - tcg_gen_sari_i32(ret, arg, 16); + tcg_gen_sari_i32(ret, ret, 16); #endif } @@ -975,7 +975,7 @@ static inline void tcg_gen_ext8s_i64(TCGv ret, TCGv arg) tcg_gen_op2(INDEX_op_ext8s_i64, ret, arg); #else tcg_gen_shli_i64(ret, arg, 56); - tcg_gen_sari_i64(ret, arg, 56); + tcg_gen_sari_i64(ret, ret, 56); #endif } @@ -985,7 +985,7 @@ static inline void tcg_gen_ext16s_i64(TCGv ret, TCGv arg) tcg_gen_op2(INDEX_op_ext16s_i64, ret, arg); #else tcg_gen_shli_i64(ret, arg, 48); - tcg_gen_sari_i64(ret, arg, 48); + tcg_gen_sari_i64(ret, ret, 48); #endif } @@ -995,7 +995,7 @@ static inline void tcg_gen_ext32s_i64(TCGv ret, TCGv arg) tcg_gen_op2(INDEX_op_ext32s_i64, ret, arg); #else tcg_gen_shli_i64(ret, arg, 32); - tcg_gen_sari_i64(ret, arg, 32); + tcg_gen_sari_i64(ret, ret, 32); #endif } @@ -1062,6 +1062,25 @@ static inline void tcg_gen_bswap_i64(TCGv ret, TCGv arg) #endif + +static inline void tcg_gen_discard_i32(TCGv arg) +{ + tcg_gen_op1(INDEX_op_discard, arg); +} + +#if TCG_TARGET_REG_BITS == 32 +static inline void tcg_gen_discard_i64(TCGv arg) +{ + tcg_gen_discard_i32(arg); + tcg_gen_discard_i32(TCGV_HIGH(arg)); +} +#else +static inline void tcg_gen_discard_i64(TCGv arg) +{ + tcg_gen_op1(INDEX_op_discard, arg); +} +#endif + /***************************************/ static inline void tcg_gen_macro_2(TCGv ret0, TCGv ret1, int macro_id) { diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h index ebf4f82fb8..4d91d117db 100644 --- a/tcg/tcg-opc.h +++ b/tcg/tcg-opc.h @@ -40,10 +40,12 @@ DEF2(macro_start, 0, 0, 2, 0) DEF2(macro_end, 0, 0, 2, 0) DEF2(macro_goto, 0, 0, 3, 0) +DEF2(discard, 1, 0, 0, 0) + DEF2(set_label, 0, 0, 1, 0) -DEF2(call, 0, 1, 2, 0) /* variable number of parameters */ -DEF2(jmp, 0, 1, 0, TCG_OPF_BB_END) -DEF2(br, 0, 0, 1, TCG_OPF_BB_END) +DEF2(call, 0, 1, 2, TCG_OPF_SIDE_EFFECTS) /* variable number of parameters */ +DEF2(jmp, 0, 1, 0, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +DEF2(br, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) DEF2(mov_i32, 1, 1, 0, 0) DEF2(movi_i32, 1, 0, 1, 0) @@ -53,9 +55,9 @@ DEF2(ld8s_i32, 1, 1, 1, 0) DEF2(ld16u_i32, 1, 1, 1, 0) DEF2(ld16s_i32, 1, 1, 1, 0) DEF2(ld_i32, 1, 1, 1, 0) -DEF2(st8_i32, 0, 2, 1, 0) -DEF2(st16_i32, 0, 2, 1, 0) -DEF2(st_i32, 0, 2, 1, 0) +DEF2(st8_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF2(st16_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF2(st_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) /* arith */ DEF2(add_i32, 1, 2, 0, 0) DEF2(sub_i32, 1, 2, 0, 0) @@ -77,11 +79,11 @@ DEF2(shl_i32, 1, 2, 0, 0) DEF2(shr_i32, 1, 2, 0, 0) DEF2(sar_i32, 1, 2, 0, 0) -DEF2(brcond_i32, 0, 2, 2, TCG_OPF_BB_END) +DEF2(brcond_i32, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) #if TCG_TARGET_REG_BITS == 32 DEF2(add2_i32, 2, 4, 0, 0) DEF2(sub2_i32, 2, 4, 0, 0) -DEF2(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END) +DEF2(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) DEF2(mulu2_i32, 2, 2, 0, 0) #endif #ifdef TCG_TARGET_HAS_ext8s_i32 @@ -105,10 +107,10 @@ DEF2(ld16s_i64, 1, 1, 1, 0) DEF2(ld32u_i64, 1, 1, 1, 0) DEF2(ld32s_i64, 1, 1, 1, 0) DEF2(ld_i64, 1, 1, 1, 0) -DEF2(st8_i64, 0, 2, 1, 0) -DEF2(st16_i64, 0, 2, 1, 0) -DEF2(st32_i64, 0, 2, 1, 0) -DEF2(st_i64, 0, 2, 1, 0) +DEF2(st8_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF2(st16_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF2(st32_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF2(st_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) /* arith */ DEF2(add_i64, 1, 2, 0, 0) DEF2(sub_i64, 1, 2, 0, 0) @@ -130,7 +132,7 @@ DEF2(shl_i64, 1, 2, 0, 0) DEF2(shr_i64, 1, 2, 0, 0) DEF2(sar_i64, 1, 2, 0, 0) -DEF2(brcond_i64, 0, 2, 2, TCG_OPF_BB_END) +DEF2(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) #ifdef TCG_TARGET_HAS_ext8s_i64 DEF2(ext8s_i64, 1, 1, 0, 0) #endif @@ -146,82 +148,82 @@ DEF2(bswap_i64, 1, 1, 0, 0) #endif /* QEMU specific */ -DEF2(exit_tb, 0, 0, 1, TCG_OPF_BB_END) -DEF2(goto_tb, 0, 0, 1, TCG_OPF_BB_END) +DEF2(exit_tb, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +DEF2(goto_tb, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) /* Note: even if TARGET_LONG_BITS is not defined, the INDEX_op constants must be defined */ #if TCG_TARGET_REG_BITS == 32 #if TARGET_LONG_BITS == 32 -DEF2(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #else -DEF2(qemu_ld8u, 1, 2, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_ld8u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #endif #if TARGET_LONG_BITS == 32 -DEF2(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #else -DEF2(qemu_ld8s, 1, 2, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_ld8s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #endif #if TARGET_LONG_BITS == 32 -DEF2(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #else -DEF2(qemu_ld16u, 1, 2, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_ld16u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #endif #if TARGET_LONG_BITS == 32 -DEF2(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #else -DEF2(qemu_ld16s, 1, 2, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_ld16s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #endif #if TARGET_LONG_BITS == 32 -DEF2(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #else -DEF2(qemu_ld32u, 1, 2, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_ld32u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #endif #if TARGET_LONG_BITS == 32 -DEF2(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #else -DEF2(qemu_ld32s, 1, 2, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_ld32s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #endif #if TARGET_LONG_BITS == 32 -DEF2(qemu_ld64, 2, 1, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_ld64, 2, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #else -DEF2(qemu_ld64, 2, 2, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_ld64, 2, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #endif #if TARGET_LONG_BITS == 32 -DEF2(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #else -DEF2(qemu_st8, 0, 3, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_st8, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #endif #if TARGET_LONG_BITS == 32 -DEF2(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #else -DEF2(qemu_st16, 0, 3, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_st16, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #endif #if TARGET_LONG_BITS == 32 -DEF2(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #else -DEF2(qemu_st32, 0, 3, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_st32, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #endif #if TARGET_LONG_BITS == 32 -DEF2(qemu_st64, 0, 3, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_st64, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #else -DEF2(qemu_st64, 0, 4, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_st64, 0, 4, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #endif #else /* TCG_TARGET_REG_BITS == 32 */ -DEF2(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER) -DEF2(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER) -DEF2(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER) -DEF2(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER) -DEF2(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER) -DEF2(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER) -DEF2(qemu_ld64, 1, 1, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_ld64, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) -DEF2(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER) -DEF2(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER) -DEF2(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER) -DEF2(qemu_st64, 0, 2, 1, TCG_OPF_CALL_CLOBBER) +DEF2(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF2(qemu_st64, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) #endif /* TCG_TARGET_REG_BITS != 32 */ @@ -401,6 +401,7 @@ TCGv tcg_temp_new(TCGType type) ts = &s->temps[s->nb_temps]; ts->base_type = type; ts->type = TCG_TYPE_I32; + ts->fixed_reg = 0; ts->val_type = TEMP_VAL_DEAD; ts->mem_allocated = 0; ts->name = NULL; @@ -408,6 +409,7 @@ TCGv tcg_temp_new(TCGType type) ts->base_type = TCG_TYPE_I32; ts->type = TCG_TYPE_I32; ts->val_type = TEMP_VAL_DEAD; + ts->fixed_reg = 0; ts->mem_allocated = 0; ts->name = NULL; s->nb_temps += 2; @@ -418,6 +420,7 @@ TCGv tcg_temp_new(TCGType type) ts = &s->temps[s->nb_temps]; ts->base_type = type; ts->type = type; + ts->fixed_reg = 0; ts->val_type = TEMP_VAL_DEAD; ts->mem_allocated = 0; ts->name = NULL; @@ -805,11 +808,12 @@ void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs) assert(oarg < def->nb_oargs); assert(def->args_ct[oarg].ct & TCG_CT_REG); /* TCG_CT_ALIAS is for the output arguments. The input - argument is tagged with TCG_CT_IALIAS for - informative purposes. */ + argument is tagged with TCG_CT_IALIAS. */ def->args_ct[i] = def->args_ct[oarg]; - def->args_ct[oarg].ct = i | TCG_CT_ALIAS; + def->args_ct[oarg].ct = TCG_CT_ALIAS; + def->args_ct[oarg].alias_index = i; def->args_ct[i].ct |= TCG_CT_IALIAS; + def->args_ct[i].alias_index = oarg; } else { for(;;) { if (*ct_str == '\0') @@ -935,6 +939,11 @@ void tcg_liveness_analysis(TCGContext *s) nb_args = args[-1]; args -= nb_args; break; + case INDEX_op_discard: + args--; + /* mark the temporary as dead */ + dead_temps[args[0]] = 1; + break; case INDEX_op_macro_2: { int dead_args[2], macro_id; @@ -1015,12 +1024,9 @@ void tcg_liveness_analysis(TCGContext *s) nb_oargs = def->nb_oargs; /* Test if the operation can be removed because all - its outputs are dead. We may add a flag to - explicitely tell if the op has side - effects. Currently we assume that if nb_oargs == 0 - or OPF_BB_END is set, the operation has side - effects and cannot be removed */ - if (nb_oargs != 0 && !(def->flags & TCG_OPF_BB_END)) { + its outputs are dead. We assume that nb_oargs == 0 + implies side effects */ + if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { for(i = 0; i < nb_oargs; i++) { arg = args[i]; if (!dead_temps[arg]) @@ -1164,7 +1170,7 @@ static void temp_allocate_frame(TCGContext *s, int temp) ts = &s->temps[temp]; s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1); if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end) - abort(); + tcg_abort(); ts->mem_offset = s->current_frame_offset; ts->mem_reg = s->frame_reg; ts->mem_allocated = 1; @@ -1350,12 +1356,19 @@ static void tcg_reg_alloc_op(TCGContext *s, } } assert(ts->val_type == TEMP_VAL_REG); - if ((arg_ct->ct & TCG_CT_IALIAS) && - !IS_DEAD_IARG(i - nb_oargs)) { - /* if the input is aliased to an output and if it is - not dead after the instruction, we must allocate - a new register and move it */ - goto allocate_in_reg; + if (arg_ct->ct & TCG_CT_IALIAS) { + if (ts->fixed_reg) { + /* if fixed register, we must allocate a new register + if the alias is not the same register */ + if (arg != args[arg_ct->alias_index]) + goto allocate_in_reg; + } else { + /* if the input is aliased to an output and if it is + not dead after the instruction, we must allocate + a new register and move it */ + if (!IS_DEAD_IARG(i - nb_oargs)) + goto allocate_in_reg; + } } reg = ts->reg; if (tcg_regset_test_reg(arg_ct->u.regs, reg)) { @@ -1404,7 +1417,7 @@ static void tcg_reg_alloc_op(TCGContext *s, arg_ct = &def->args_ct[i]; ts = &s->temps[arg]; if (arg_ct->ct & TCG_CT_ALIAS) { - reg = new_args[arg_ct->ct & ~TCG_CT_ALIAS]; + reg = new_args[arg_ct->alias_index]; } else { /* if fixed register, we try to use it */ reg = ts->reg; @@ -1694,6 +1707,18 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, case INDEX_op_nopn: args += args[0]; goto next; + case INDEX_op_discard: + { + TCGTemp *ts; + ts = &s->temps[args[0]]; + /* mark the temporary as dead */ + if (ts->val_type != TEMP_VAL_CONST && !ts->fixed_reg) { + if (ts->val_type == TEMP_VAL_REG) + s->reg_to_temp[ts->reg] = -1; + ts->val_type = TEMP_VAL_DEAD; + } + } + break; case INDEX_op_macro_goto: macro_op_index = op_index; /* only used for exceptions */ op_index = args[0] - 1; @@ -275,7 +275,8 @@ char *tcg_get_arg_str(TCGContext *s, char *buf, int buf_size, TCGv arg); #define TCG_CT_CONST 0x02 /* any constant of register size */ typedef struct TCGArgConstraint { - uint32_t ct; + uint16_t ct; + uint8_t alias_index; union { TCGRegSet regs; } u; @@ -286,6 +287,7 @@ typedef struct TCGArgConstraint { #define TCG_OPF_BB_END 0x01 /* instruction defines the end of a basic block */ #define TCG_OPF_CALL_CLOBBER 0x02 /* instruction clobbers call registers */ +#define TCG_OPF_SIDE_EFFECTS 0x04 /* instruction has side effects */ typedef struct TCGOpDef { const char *name; |