[llvm-branch-commits] [llvm] 453361d - [DSE] Fall back to CFG scan for unreachable terminators.

Tom Stellard via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Feb 28 10:55:02 PST 2022


Author: Florian Hahn
Date: 2022-02-28T10:53:06-08:00
New Revision: 453361d5ac0131ca713904bdd87166d429e17612

URL: https://github.com/llvm/llvm-project/commit/453361d5ac0131ca713904bdd87166d429e17612
DIFF: https://github.com/llvm/llvm-project/commit/453361d5ac0131ca713904bdd87166d429e17612.diff

LOG: [DSE] Fall back to CFG scan for unreachable terminators.

Blocks with UnreachableInst terminators are considered as root nodes in
the PDT. This pessimize DSE, if there are no aliasing reads from the
potentially dead store and the block with the unreachable terminator.

If any of the root nodes of the PDF has UnreachableInst as terminator,
fall back to the CFG scan, even the common dominator of all killing
blocks does not post-dominate the block with potentially dead store.

It looks like the compile-time impact for the extra scans is negligible.
https://llvm-compile-time-tracker.com/compare.php?from=779bbbf27fe631154bdfaac7a443f198d4654688&to=ac59945f1bec1c6a7d7f5590c8c69fd9c5369c53&stat=instructions

Fixes #53800.

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D119760

Added: 
    

Modified: 
    llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
    llvm/test/Transforms/DeadStoreElimination/multiblock-unreachable.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
index 8739ddce91606..c5c8e880eb3d5 100644
--- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
@@ -770,6 +770,10 @@ struct DSEState {
   /// Keep track of instructions (partly) overlapping with killing MemoryDefs per
   /// basic block.
   MapVector<BasicBlock *, InstOverlapIntervalsTy> IOLs;
+  // Check if there are root nodes that are terminated by UnreachableInst.
+  // Those roots pessimize post-dominance queries. If there are such roots,
+  // fall back to CFG scan starting from all non-unreachable roots.
+  bool AnyUnreachableExit;
 
   // Class contains self-reference, make sure it's not copied/moved.
   DSEState(const DSEState &) = delete;
@@ -805,6 +809,10 @@ struct DSEState {
 
     // Collect whether there is any irreducible control flow in the function.
     ContainsIrreducibleLoops = mayContainIrreducibleControl(F, &LI);
+
+    AnyUnreachableExit = any_of(PDT.roots(), [](const BasicBlock *E) {
+      return isa<UnreachableInst>(E->getTerminator());
+    });
   }
 
   /// Return 'OW_Complete' if a store to the 'KillingLoc' location (by \p
@@ -1511,22 +1519,29 @@ struct DSEState {
       // If the common post-dominator does not post-dominate MaybeDeadAccess,
       // there is a path from MaybeDeadAccess to an exit not going through a
       // killing block.
-      if (!PDT.dominates(CommonPred, MaybeDeadAccess->getBlock()))
-        return None;
+      if (!PDT.dominates(CommonPred, MaybeDeadAccess->getBlock())) {
+        if (!AnyUnreachableExit)
+          return None;
+
+        // Fall back to CFG scan starting at all non-unreachable roots if not
+        // all paths to the exit go through CommonPred.
+        CommonPred = nullptr;
+      }
 
       // If CommonPred itself is in the set of killing blocks, we're done.
       if (KillingBlocks.count(CommonPred))
         return {MaybeDeadAccess};
 
       SetVector<BasicBlock *> WorkList;
-
       // If CommonPred is null, there are multiple exits from the function.
       // They all have to be added to the worklist.
       if (CommonPred)
         WorkList.insert(CommonPred);
       else
-        for (BasicBlock *R : PDT.roots())
-          WorkList.insert(R);
+        for (BasicBlock *R : PDT.roots()) {
+          if (!isa<UnreachableInst>(R->getTerminator()))
+            WorkList.insert(R);
+        }
 
       NumCFGTries++;
       // Check if all paths starting from an exit node go through one of the

diff  --git a/llvm/test/Transforms/DeadStoreElimination/multiblock-unreachable.ll b/llvm/test/Transforms/DeadStoreElimination/multiblock-unreachable.ll
index 6548ec34ae0ac..a1af7271dcce0 100644
--- a/llvm/test/Transforms/DeadStoreElimination/multiblock-unreachable.ll
+++ b/llvm/test/Transforms/DeadStoreElimination/multiblock-unreachable.ll
@@ -57,3 +57,139 @@ bb50:                                             ; preds = %bb43
 bb53:                                             ; preds = %bb53, %bb50, %bb22, %bb
   br label %bb53
 }
+
+declare void @exit()
+
+define void @unreachable_exit_with_no_call(i64* noalias %ptr, i1 %c.1) {
+; CHECK-LABEL: @unreachable_exit_with_no_call(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[C_1:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    unreachable
+; CHECK:       if.end:
+; CHECK-NEXT:    store i64 0, i64* [[PTR:%.*]], align 8
+; CHECK-NEXT:    ret void
+;
+entry:
+  store i64 1, i64* %ptr, align 8
+  br i1 %c.1, label %if.then, label %if.end
+
+if.then:
+  unreachable
+
+if.end:
+  store i64 0, i64* %ptr, align 8
+  ret void
+}
+
+; Test for PR53800.
+define void @unreachable_exit_with_nounwind_call_pr53800(i64* noalias %ptr, i1 %c.1) {
+; CHECK-LABEL: @unreachable_exit_with_nounwind_call_pr53800(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[C_1:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    tail call void @exit() #[[ATTR0:[0-9]+]]
+; CHECK-NEXT:    unreachable
+; CHECK:       if.end:
+; CHECK-NEXT:    store i64 0, i64* [[PTR:%.*]], align 8
+; CHECK-NEXT:    ret void
+;
+entry:
+  store i64 1, i64* %ptr, align 8
+  br i1 %c.1, label %if.then, label %if.end
+
+if.then:
+  tail call void @exit() nounwind
+  unreachable
+
+if.end:
+  store i64 0, i64* %ptr, align 8
+  ret void
+}
+
+; The call @exit may read %ptr as it is not marked as noalias
+define void @unreachable_exit_and_call_may_read(i64* %ptr, i1 %c.1) {
+; CHECK-LABEL: @unreachable_exit_and_call_may_read(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    store i64 1, i64* [[PTR:%.*]], align 8
+; CHECK-NEXT:    br i1 [[C_1:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    tail call void @exit() #[[ATTR0]]
+; CHECK-NEXT:    unreachable
+; CHECK:       if.end:
+; CHECK-NEXT:    store i64 0, i64* [[PTR]], align 8
+; CHECK-NEXT:    ret void
+;
+entry:
+  store i64 1, i64* %ptr, align 8
+  br i1 %c.1, label %if.then, label %if.end
+
+if.then:
+  tail call void @exit() nounwind
+  unreachable
+
+if.end:
+  store i64 0, i64* %ptr, align 8
+  ret void
+}
+
+define void @unreachable_exit_with_may_unwind_call(i64* noalias %ptr, i1 %c.1) {
+; CHECK-LABEL: @unreachable_exit_with_may_unwind_call(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    store i64 1, i64* [[PTR:%.*]], align 8
+; CHECK-NEXT:    br i1 [[C_1:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    tail call void @exit()
+; CHECK-NEXT:    unreachable
+; CHECK:       if.end:
+; CHECK-NEXT:    store i64 0, i64* [[PTR]], align 8
+; CHECK-NEXT:    ret void
+;
+entry:
+  store i64 1, i64* %ptr, align 8
+  br i1 %c.1, label %if.then, label %if.end
+
+if.then:
+  tail call void @exit()
+  unreachable
+
+if.end:
+  store i64 0, i64* %ptr, align 8
+  ret void
+}
+
+; Cannot remove the store in entry, because it is not dead on the path to e.1
+define void @unreachable_exit_but_another_exit(i64* noalias %ptr, i1 %c.1, i32 %s, i1 %c.2) {
+; CHECK-LABEL: @unreachable_exit_but_another_exit(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    store i64 1, i64* [[PTR:%.*]], align 8
+; CHECK-NEXT:    br i1 [[C_1:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    br i1 [[C_2:%.*]], label [[E_0:%.*]], label [[E_1:%.*]]
+; CHECK:       e.0:
+; CHECK-NEXT:    tail call void @exit() #[[ATTR0]]
+; CHECK-NEXT:    unreachable
+; CHECK:       e.1:
+; CHECK-NEXT:    ret void
+; CHECK:       if.end:
+; CHECK-NEXT:    store i64 0, i64* [[PTR]], align 8
+; CHECK-NEXT:    ret void
+;
+entry:
+  store i64 1, i64* %ptr, align 8
+  br i1 %c.1, label %if.then, label %if.end
+
+if.then:
+  br i1 %c.2, label %e.0, label %e.1
+
+e.0:
+  tail call void @exit() nounwind
+  unreachable
+
+e.1:
+  ret void
+
+if.end:
+  store i64 0, i64* %ptr, align 8
+  ret void
+}


        


More information about the llvm-branch-commits mailing list