Improve DSE to handle stores before __builtin_unreachable ()
Checks
Commit Message
DSE isn't good at identifying program points that end lifetime
of variables that are not associated with virtual operands. But
at least for those that end basic-blocks we can handle the simple
case where this ending is in the same basic-block as the definition
we want to elide. That should catch quite some common cases already.
Bootstrapped and tested on x86_64-unknown-linux-gnu.
As you can see from the testcase I had to adjust this possibly can
lead to more severe issues when one forgets a return (the C++ frontend
places builtin_unreachable () there). I'm still planning to push
this improvement unless I hear objections.
Thanks,
Richard.
* tree-ssa-dse.cc (dse_classify_store): When we found
no defs and the basic-block with the original definition
ends in __builtin_unreachable[_trap] the store is dead.
* gcc.dg/tree-ssa/ssa-dse-47.c: New testcase.
* c-c++-common/asan/pr106558.c: Avoid undefined behavior
due to missing return.
---
gcc/testsuite/c-c++-common/asan/pr106558.c | 2 +-
gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-47.c | 17 +++++++++++++++++
gcc/tree-ssa-dse.cc | 21 ++++++++++++++++++++-
3 files changed, 38 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-47.c
@@ -8,7 +8,7 @@ int **c = &b;
int d[1];
int *e = &d[1];
-static int f(int *g) {
+static void f(int *g) {
*b = e;
*c = e;
*b = 2;
new file mode 100644
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-dse1-details" } */
+
+int a;
+int b[3];
+void test()
+{
+ if (a > 0)
+ {
+ b[0] = 0;
+ b[1] = 1;
+ b[2] = 2;
+ __builtin_unreachable ();
+ }
+}
+
+/* { dg-final { scan-tree-dump-times "Deleted dead store" 3 "dse1" } } */
@@ -1118,7 +1118,26 @@ dse_classify_store (ao_ref *ref, gimple *stmt,
if (defs.is_empty ())
{
if (ref_may_alias_global_p (ref, false))
- return DSE_STORE_LIVE;
+ {
+ basic_block def_bb = gimple_bb (SSA_NAME_DEF_STMT (defvar));
+ /* Assume that BUILT_IN_UNREACHABLE and BUILT_IN_UNREACHABLE_TRAP
+ do not need to keep (global) memory side-effects live.
+ We do not have virtual operands on BUILT_IN_UNREACHABLE
+ but we can do poor mans reachability when the last
+ definition we want to elide is in the block that ends
+ in such a call. */
+ if (EDGE_COUNT (def_bb->succs) == 0)
+ if (gcall *last = dyn_cast <gcall *> (*gsi_last_bb (def_bb)))
+ if (gimple_call_builtin_p (last, BUILT_IN_UNREACHABLE)
+ || gimple_call_builtin_p (last,
+ BUILT_IN_UNREACHABLE_TRAP))
+ {
+ if (by_clobber_p)
+ *by_clobber_p = false;
+ return DSE_STORE_DEAD;
+ }
+ return DSE_STORE_LIVE;
+ }
if (by_clobber_p)
*by_clobber_p = false;