summaryrefslogtreecommitdiff
path: root/gcc/dce.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/dce.c')
-rw-r--r--gcc/dce.c25
1 files changed, 25 insertions, 0 deletions
diff --git a/gcc/dce.c b/gcc/dce.c
index 7b2ffe92581..91cc9aa5c28 100644
--- a/gcc/dce.c
+++ b/gcc/dce.c
@@ -99,6 +99,20 @@ deletable_insn_p (rtx insn, bool fast)
rtx body, x;
int i;
+ if (CALL_P (insn)
+ /* We cannot delete calls inside of the recursive dce because
+ this may cause basic blocks to be deleted and this messes up
+ the rest of the stack of optimization passes. */
+ && (!df_in_progress)
+ /* We cannot delete pure or const sibling calls because it is
+ hard to see the result. */
+ && (!SIBLING_CALL_P (insn))
+ /* We can delete dead const or pure calls as long as they do not
+ infinite loop. */
+ && (RTL_CONST_OR_PURE_CALL_P (insn)
+ && !RTL_LOOPING_CONST_OR_PURE_CALL_P (insn)))
+ return true;
+
if (!NONJUMP_INSN_P (insn))
return false;
@@ -296,6 +310,7 @@ delete_unmarked_insns (void)
{
basic_block bb;
rtx insn, next;
+ bool must_clean = false;
FOR_EACH_BB (bb)
FOR_BB_INSNS_SAFE (bb, insn, next)
@@ -373,9 +388,19 @@ delete_unmarked_insns (void)
remove_note (XEXP (note, 0), libcall_note);
}
+ /* If a pure or const call is deleted, this may make the cfg
+ have unreachable blocks. We rememeber this and call
+ delete_unreachable_blocks at the end. */
+ if (CALL_P (insn))
+ must_clean = true;
+
/* Now delete the insn. */
delete_insn_and_edges (insn);
}
+
+ /* Deleted a pure or const call. */
+ if (must_clean)
+ delete_unreachable_blocks ();
}