[llvm] 70aca7b - [InstCombine] Explicitly track dead edges

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 27 07:41:12 PDT 2023


Author: Nikita Popov
Date: 2023-07-27T16:41:03+02:00
New Revision: 70aca7b12220971dcc54ec6431813665eac5856e

URL: https://github.com/llvm/llvm-project/commit/70aca7b12220971dcc54ec6431813665eac5856e
DIFF: https://github.com/llvm/llvm-project/commit/70aca7b12220971dcc54ec6431813665eac5856e.diff

LOG: [InstCombine] Explicitly track dead edges

This allows us to handle dead blocks with multiple incoming edges,
where we can determine that all of those edges are dead (or cycles).

This allows InstCombine to handle certain dead code patterns that
can be produced by LoopVectorize in a single iteration.

This is in preparation for D154579.

Added: 
    

Modified: 
    llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
    llvm/lib/Transforms/InstCombine/InstCombineInternal.h
    llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
    llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
    llvm/test/Transforms/InstCombine/unreachable-code.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
index 5569bc90caa698..6b5a7c3634dcb4 100644
--- a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
+++ b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
@@ -83,6 +83,9 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner {
 
   bool MadeIRChange = false;
 
+  /// Edges that are known to never be taken.
+  SmallDenseSet<std::pair<BasicBlock *, BasicBlock *>, 8> DeadEdges;
+
 public:
   InstCombiner(InstructionWorklist &Worklist, BuilderTy &Builder,
                bool MinimizeSize, AAResults *AA, AssumptionCache &AC,

diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index 701579e1de4830..2ee293ba8ff990 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -667,7 +667,9 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
   bool tryToSinkInstruction(Instruction *I, BasicBlock *DestBlock);
 
   bool removeInstructionsBeforeUnreachable(Instruction &I);
-  bool handleUnreachableFrom(Instruction *I);
+  bool handleUnreachableFrom(Instruction *I,
+                             SmallVectorImpl<BasicBlock *> &Worklist);
+  bool handlePotentiallyDeadBlocks(SmallVectorImpl<BasicBlock *> &Worklist);
   bool handlePotentiallyDeadSuccessors(BasicBlock *BB, BasicBlock *LiveSucc);
   void freelyInvertAllUsersOf(Value *V, Value *IgnoredUser = nullptr);
 };

diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
index 6aa20ee26b9aa2..5694e7ef79b64f 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
@@ -1560,10 +1560,16 @@ Instruction *InstCombinerImpl::visitStoreInst(StoreInst &SI) {
 
   // This is a non-terminator unreachable marker. Don't remove it.
   if (isa<UndefValue>(Ptr)) {
-    // Remove all instructions after the marker and guaranteed-to-transfer
-    // instructions before the marker.
-    if (handleUnreachableFrom(SI.getNextNode()) ||
-        removeInstructionsBeforeUnreachable(SI))
+    // Remove guaranteed-to-transfer instructions before the marker.
+    if (removeInstructionsBeforeUnreachable(SI))
+      return &SI;
+
+    // Remove all instructions after the marker and handle dead blocks this
+    // implies.
+    SmallVector<BasicBlock *> Worklist;
+    bool Changed = handleUnreachableFrom(SI.getNextNode(), Worklist);
+    Changed |= handlePotentiallyDeadBlocks(Worklist);
+    if (Changed)
       return &SI;
     return nullptr;
   }

diff  --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index afd6e034f46d70..4e208703bac652 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -2748,7 +2748,8 @@ Instruction *InstCombinerImpl::visitUnconditionalBranchInst(BranchInst &BI) {
 
 // Under the assumption that I is unreachable, remove it and following
 // instructions.
-bool InstCombinerImpl::handleUnreachableFrom(Instruction *I) {
+bool InstCombinerImpl::handleUnreachableFrom(
+    Instruction *I, SmallVectorImpl<BasicBlock *> &Worklist) {
   bool Changed = false;
   BasicBlock *BB = I->getParent();
   for (Instruction &Inst : make_early_inc_range(
@@ -2774,27 +2775,41 @@ bool InstCombinerImpl::handleUnreachableFrom(Instruction *I) {
           Changed = true;
         }
 
-  // TODO: Successor blocks may also be dead.
+  // Handle potentially dead successors.
+  for (BasicBlock *Succ : successors(BB))
+    if (DeadEdges.insert({BB, Succ}).second)
+      Worklist.push_back(Succ);
+  return Changed;
+}
+
+bool InstCombinerImpl::handlePotentiallyDeadBlocks(
+    SmallVectorImpl<BasicBlock *> &Worklist) {
+  bool Changed = false;
+  while (!Worklist.empty()) {
+    BasicBlock *BB = Worklist.pop_back_val();
+    if (!all_of(predecessors(BB), [&](BasicBlock *Pred) {
+          return DeadEdges.contains({Pred, BB}) || DT.dominates(BB, Pred);
+        }))
+      continue;
+
+    Changed |= handleUnreachableFrom(&BB->front(), Worklist);
+  }
   return Changed;
 }
 
 bool InstCombinerImpl::handlePotentiallyDeadSuccessors(BasicBlock *BB,
                                                        BasicBlock *LiveSucc) {
-  bool Changed = false;
+  SmallVector<BasicBlock *> Worklist;
   for (BasicBlock *Succ : successors(BB)) {
     // The live successor isn't dead.
     if (Succ == LiveSucc)
       continue;
 
-    if (!all_of(predecessors(Succ), [&](BasicBlock *Pred) {
-          return DT.dominates(BasicBlockEdge(BB, Succ),
-                              BasicBlockEdge(Pred, Succ));
-        }))
-      continue;
-
-    Changed |= handleUnreachableFrom(&Succ->front());
+    if (DeadEdges.insert({BB, Succ}).second)
+      Worklist.push_back(Succ);
   }
-  return Changed;
+
+  return handlePotentiallyDeadBlocks(Worklist);
 }
 
 Instruction *InstCombinerImpl::visitBranchInst(BranchInst &BI) {

diff  --git a/llvm/test/Transforms/InstCombine/unreachable-code.ll b/llvm/test/Transforms/InstCombine/unreachable-code.ll
index eea4ff987d17bf..7c37690bc9808a 100644
--- a/llvm/test/Transforms/InstCombine/unreachable-code.ll
+++ b/llvm/test/Transforms/InstCombine/unreachable-code.ll
@@ -69,7 +69,7 @@ define i32 @br_undef(i1 %x) {
 ; CHECK:       else:
 ; CHECK-NEXT:    br label [[JOIN]]
 ; CHECK:       join:
-; CHECK-NEXT:    ret i32 undef
+; CHECK-NEXT:    ret i32 poison
 ;
   %c = xor i1 %x, undef
   br i1 %c, label %if, label %else
@@ -234,10 +234,8 @@ define void @non_term_unreachable_following_blocks() {
 ; CHECK-NEXT:    store i1 true, ptr poison, align 1
 ; CHECK-NEXT:    br label [[SPLIT:%.*]]
 ; CHECK:       split:
-; CHECK-NEXT:    call void @dummy()
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
-; CHECK-NEXT:    call void @dummy()
 ; CHECK-NEXT:    br label [[LOOP]]
 ;
   call void @dummy()
@@ -299,28 +297,16 @@ exit:
 }
 
 define void @two_br_not_into_loop(i1 %x) {
-; DEFAULT_ITER-LABEL: define void @two_br_not_into_loop
-; DEFAULT_ITER-SAME: (i1 [[X:%.*]]) {
-; DEFAULT_ITER-NEXT:    br i1 true, label [[BB2:%.*]], label [[LOOP:%.*]]
-; DEFAULT_ITER:       bb2:
-; DEFAULT_ITER-NEXT:    br i1 true, label [[EXIT:%.*]], label [[LOOP]]
-; DEFAULT_ITER:       loop:
-; DEFAULT_ITER-NEXT:    br label [[LOOP]]
-; DEFAULT_ITER:       exit:
-; DEFAULT_ITER-NEXT:    call void @dummy()
-; DEFAULT_ITER-NEXT:    ret void
-;
-; MAX1-LABEL: define void @two_br_not_into_loop
-; MAX1-SAME: (i1 [[X:%.*]]) {
-; MAX1-NEXT:    br i1 true, label [[BB2:%.*]], label [[LOOP:%.*]]
-; MAX1:       bb2:
-; MAX1-NEXT:    br i1 true, label [[EXIT:%.*]], label [[LOOP]]
-; MAX1:       loop:
-; MAX1-NEXT:    call void @dummy()
-; MAX1-NEXT:    br label [[LOOP]]
-; MAX1:       exit:
-; MAX1-NEXT:    call void @dummy()
-; MAX1-NEXT:    ret void
+; CHECK-LABEL: define void @two_br_not_into_loop
+; CHECK-SAME: (i1 [[X:%.*]]) {
+; CHECK-NEXT:    br i1 true, label [[BB2:%.*]], label [[LOOP:%.*]]
+; CHECK:       bb2:
+; CHECK-NEXT:    br i1 true, label [[EXIT:%.*]], label [[LOOP]]
+; CHECK:       loop:
+; CHECK-NEXT:    br label [[LOOP]]
+; CHECK:       exit:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    ret void
 ;
   %c = or i1 %x, true
   br i1 %c, label %bb2, label %loop
@@ -367,36 +353,20 @@ exit:
 }
 
 define void @two_br_not_into_loop_with_split(i1 %x) {
-; DEFAULT_ITER-LABEL: define void @two_br_not_into_loop_with_split
-; DEFAULT_ITER-SAME: (i1 [[X:%.*]]) {
-; DEFAULT_ITER-NEXT:    br i1 true, label [[BB2:%.*]], label [[SPLIT1:%.*]]
-; DEFAULT_ITER:       bb2:
-; DEFAULT_ITER-NEXT:    br i1 true, label [[EXIT:%.*]], label [[SPLIT2:%.*]]
-; DEFAULT_ITER:       split1:
-; DEFAULT_ITER-NEXT:    br label [[LOOP:%.*]]
-; DEFAULT_ITER:       split2:
-; DEFAULT_ITER-NEXT:    br label [[LOOP]]
-; DEFAULT_ITER:       loop:
-; DEFAULT_ITER-NEXT:    br label [[LOOP]]
-; DEFAULT_ITER:       exit:
-; DEFAULT_ITER-NEXT:    call void @dummy()
-; DEFAULT_ITER-NEXT:    ret void
-;
-; MAX1-LABEL: define void @two_br_not_into_loop_with_split
-; MAX1-SAME: (i1 [[X:%.*]]) {
-; MAX1-NEXT:    br i1 true, label [[BB2:%.*]], label [[SPLIT1:%.*]]
-; MAX1:       bb2:
-; MAX1-NEXT:    br i1 true, label [[EXIT:%.*]], label [[SPLIT2:%.*]]
-; MAX1:       split1:
-; MAX1-NEXT:    br label [[LOOP:%.*]]
-; MAX1:       split2:
-; MAX1-NEXT:    br label [[LOOP]]
-; MAX1:       loop:
-; MAX1-NEXT:    call void @dummy()
-; MAX1-NEXT:    br label [[LOOP]]
-; MAX1:       exit:
-; MAX1-NEXT:    call void @dummy()
-; MAX1-NEXT:    ret void
+; CHECK-LABEL: define void @two_br_not_into_loop_with_split
+; CHECK-SAME: (i1 [[X:%.*]]) {
+; CHECK-NEXT:    br i1 true, label [[BB2:%.*]], label [[SPLIT1:%.*]]
+; CHECK:       bb2:
+; CHECK-NEXT:    br i1 true, label [[EXIT:%.*]], label [[SPLIT2:%.*]]
+; CHECK:       split1:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       split2:
+; CHECK-NEXT:    br label [[LOOP]]
+; CHECK:       loop:
+; CHECK-NEXT:    br label [[LOOP]]
+; CHECK:       exit:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    ret void
 ;
   %c = or i1 %x, true
   br i1 %c, label %bb2, label %split1
@@ -422,3 +392,6 @@ exit:
   ret void
 }
 
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; DEFAULT_ITER: {{.*}}
+; MAX1: {{.*}}


        


More information about the llvm-commits mailing list