tcg: Add reachable_code_pass
Delete trivially dead code that follows unconditional branches and noreturn helpers. These can occur either via optimization or via the structure of a target's translator following an exception. Reviewed-by: Emilio G. Cota <cota@braap.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
d88a117eaa
commit
b4fc67c7af
76
tcg/tcg.c
76
tcg/tcg.c
@ -2239,6 +2239,81 @@ TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
|
|||||||
return new_op;
|
return new_op;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Reachable analysis : remove unreachable code. */
|
||||||
|
static void reachable_code_pass(TCGContext *s)
|
||||||
|
{
|
||||||
|
TCGOp *op, *op_next;
|
||||||
|
bool dead = false;
|
||||||
|
|
||||||
|
QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
|
||||||
|
bool remove = dead;
|
||||||
|
TCGLabel *label;
|
||||||
|
int call_flags;
|
||||||
|
|
||||||
|
switch (op->opc) {
|
||||||
|
case INDEX_op_set_label:
|
||||||
|
label = arg_label(op->args[0]);
|
||||||
|
if (label->refs == 0) {
|
||||||
|
/*
|
||||||
|
* While there is an occasional backward branch, virtually
|
||||||
|
* all branches generated by the translators are forward.
|
||||||
|
* Which means that generally we will have already removed
|
||||||
|
* all references to the label that will be, and there is
|
||||||
|
* little to be gained by iterating.
|
||||||
|
*/
|
||||||
|
remove = true;
|
||||||
|
} else {
|
||||||
|
/* Once we see a label, insns become live again. */
|
||||||
|
dead = false;
|
||||||
|
remove = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Optimization can fold conditional branches to unconditional.
|
||||||
|
* If we find a label with one reference which is preceded by
|
||||||
|
* an unconditional branch to it, remove both. This needed to
|
||||||
|
* wait until the dead code in between them was removed.
|
||||||
|
*/
|
||||||
|
if (label->refs == 1) {
|
||||||
|
TCGOp *op_prev = QTAILQ_PREV(op, TCGOpHead, link);
|
||||||
|
if (op_prev->opc == INDEX_op_br &&
|
||||||
|
label == arg_label(op_prev->args[0])) {
|
||||||
|
tcg_op_remove(s, op_prev);
|
||||||
|
remove = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INDEX_op_br:
|
||||||
|
case INDEX_op_exit_tb:
|
||||||
|
case INDEX_op_goto_ptr:
|
||||||
|
/* Unconditional branches; everything following is dead. */
|
||||||
|
dead = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INDEX_op_call:
|
||||||
|
/* Notice noreturn helper calls, raising exceptions. */
|
||||||
|
call_flags = op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1];
|
||||||
|
if (call_flags & TCG_CALL_NO_RETURN) {
|
||||||
|
dead = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INDEX_op_insn_start:
|
||||||
|
/* Never remove -- we need to keep these for unwind. */
|
||||||
|
remove = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remove) {
|
||||||
|
tcg_op_remove(s, op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define TS_DEAD 1
|
#define TS_DEAD 1
|
||||||
#define TS_MEM 2
|
#define TS_MEM 2
|
||||||
|
|
||||||
@ -3515,6 +3590,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
|
|||||||
atomic_set(&prof->la_time, prof->la_time - profile_getclock());
|
atomic_set(&prof->la_time, prof->la_time - profile_getclock());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
reachable_code_pass(s);
|
||||||
liveness_pass_1(s);
|
liveness_pass_1(s);
|
||||||
|
|
||||||
if (s->nb_indirects > 0) {
|
if (s->nb_indirects > 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user