aboutsummaryrefslogtreecommitdiff
path: root/tcg/tcg.c
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2018-11-26 14:28:28 -0800
committerRichard Henderson <richard.henderson@linaro.org>2018-12-26 06:40:30 +1100
commitb4fc67c7afd2c338d6e7c73a7f428dfe05ae0603 (patch)
treec44d69aa3bcf491500a09736929ac5ca65d6fa9c /tcg/tcg.c
parentd88a117eaa39b1d0eb1a79fe84c81840a39eb233 (diff)
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>
Diffstat (limited to 'tcg/tcg.c')
-rw-r--r--tcg/tcg.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 99afc65126..d2be550ab4 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -2239,6 +2239,81 @@ TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
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_MEM 2
@@ -3515,6 +3590,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
atomic_set(&prof->la_time, prof->la_time - profile_getclock());
#endif
+ reachable_code_pass(s);
liveness_pass_1(s);
if (s->nb_indirects > 0) {