[InstCombine] Remove instructions in dead blocks during combining
authorNikita Popov <npopov@redhat.com>
Wed, 24 May 2023 14:47:15 +0000 (16:47 +0200)
committerNikita Popov <npopov@redhat.com>
Fri, 26 May 2023 14:43:34 +0000 (16:43 +0200)
We already do this during initial worklist population. Doing this
as part of primary combining allows us to remove instructions in
blocks that were rendered dead by condition folding within the
same instcombine iteration.

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
llvm/test/Transforms/InstCombine/unreachable-code.ll

index 0df85be..2af6ba5 100644 (file)
@@ -2550,6 +2550,41 @@ Instruction *InstCombinerImpl::visitUnconditionalBranchInst(BranchInst &BI) {
   return nullptr;
 }
 
+/// If a block is dead due to a known branch condition, remove instructions
+/// in it.
+static bool handlePotentiallyDeadBlock(BasicBlock *BB, InstCombiner &IC) {
+  // We only know one edge to this block is dead, but there may be others.
+  // TODO: We could track dead edges globally.
+  if (!BB->getSinglePredecessor())
+    return false;
+
+  bool Changed = false;
+  for (Instruction &Inst : make_early_inc_range(make_range(
+           std::next(BB->getTerminator()->getReverseIterator()), BB->rend()))) {
+    if (!Inst.use_empty() && !Inst.getType()->isTokenTy()) {
+      IC.replaceInstUsesWith(Inst, PoisonValue::get(Inst.getType()));
+      Changed = true;
+    }
+    if (Inst.isEHPad() || Inst.getType()->isTokenTy())
+      continue;
+    IC.eraseInstFromFunction(Inst);
+    Changed = true;
+  }
+
+  // TODO: Successor blocks may also be dead.
+  return Changed;
+}
+
+static bool handlePotentiallyDeadSuccessors(BasicBlock *BB,
+                                            BasicBlock *LiveSucc,
+                                            InstCombiner &IC) {
+  bool Changed = false;
+  for (BasicBlock *Succ : successors(BB))
+    if (Succ != LiveSucc)
+      Changed |= handlePotentiallyDeadBlock(Succ, IC);
+  return Changed;
+}
+
 Instruction *InstCombinerImpl::visitBranchInst(BranchInst &BI) {
   if (BI.isUnconditional())
     return visitUnconditionalBranchInst(BI);
@@ -2593,6 +2628,14 @@ Instruction *InstCombinerImpl::visitBranchInst(BranchInst &BI) {
     return &BI;
   }
 
+  if (isa<UndefValue>(Cond) && handlePotentiallyDeadSuccessors(
+                                   BI.getParent(), /*LiveSucc*/ nullptr, *this))
+    return &BI;
+  if (auto *CI = dyn_cast<ConstantInt>(Cond))
+    if (handlePotentiallyDeadSuccessors(
+            BI.getParent(), BI.getSuccessor(!CI->getZExtValue()), *this))
+      return &BI;
+
   return nullptr;
 }
 
@@ -2611,6 +2654,14 @@ Instruction *InstCombinerImpl::visitSwitchInst(SwitchInst &SI) {
     return replaceOperand(SI, 0, Op0);
   }
 
+  if (isa<UndefValue>(Cond) && handlePotentiallyDeadSuccessors(
+                                   SI.getParent(), /*LiveSucc*/ nullptr, *this))
+    return &SI;
+  if (auto *CI = dyn_cast<ConstantInt>(Cond))
+    if (handlePotentiallyDeadSuccessors(
+            SI.getParent(), SI.findCaseValue(CI)->getCaseSuccessor(), *this))
+      return &SI;
+
   KnownBits Known = computeKnownBits(Cond, 0, &SI);
   unsigned LeadingKnownZeros = Known.countMinLeadingZeros();
   unsigned LeadingKnownOnes = Known.countMinLeadingOnes();
index 4a85d08..7f17dfa 100644 (file)
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
-; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+; RUN: opt -S -passes=instcombine -instcombine-infinite-loop-threshold=2 < %s | FileCheck %s
 
 declare void @dummy()