[llvm-commits] [llvm] r62487 - in /llvm/trunk: lib/Transforms/Utils/SimplifyCFG.cpp test/Transforms/SimplifyCFG/2009-01-18-PHIPropCrash.ll

Chris Lattner sabre at nondot.org
Sun Jan 18 18:46:28 PST 2009


Author: lattner
Date: Sun Jan 18 20:46:28 2009
New Revision: 62487

URL: http://llvm.org/viewvc/llvm-project?rev=62487&view=rev
Log:
Fix PR3016, a bug which can occur do to an invalid assumption:
we assumed a CFG structure that would be valid when all code in 
the function is reachable, but not all code is necessarily 
reachable.  Do a simple, but horrible, CFG walk to check for this
case.

Added:
    llvm/trunk/test/Transforms/SimplifyCFG/2009-01-18-PHIPropCrash.ll
Modified:
    llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp

Modified: llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp?rev=62487&r1=62486&r2=62487&view=diff

==============================================================================
--- llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp Sun Jan 18 20:46:28 2009
@@ -21,6 +21,7 @@
 #include "llvm/Support/Debug.h"
 #include "llvm/Analysis/ConstantFolding.h"
 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/Statistic.h"
@@ -172,6 +173,74 @@
   return true;
 }
 
+/// BlockIsReachableFrom - Return true if there is a path from StartBB to
+/// DestBB.  We do this by recursively walking the CFG from DestBB up to StartBB
+/// unwind we either reach StartBB or find an unreachable chunk of the CFG.
+/// 
+/// Each entry in VisitedBlocks is either 0 -> not visited, 1 -> known reachable
+/// 2 -> known unreachable, 3 -> visitation in progress.
+static bool BlockIsReachableFrom(BasicBlock *StartBB, BasicBlock *DestBB,
+                               DenseMap<BasicBlock*, unsigned> &VisitedBlocks) {
+  if (StartBB == DestBB) return true;
+  
+  unsigned &BlockEntry = VisitedBlocks[DestBB];
+  if (BlockEntry == 1) return true;       // Known reachable!
+  if (BlockEntry == 2 ||                  // Known unreachable.
+      BlockEntry == 3)                    // Found a loop.
+    return false;
+  
+  // If BlockEntry is 0, this is the first time we've seen this block.  Mark it
+  // as being visited and recurse up predecessors.
+  BlockEntry = 3;
+  
+  for (pred_iterator PI = pred_begin(DestBB), E = pred_end(DestBB); PI != E;
+       ++PI) {
+    if (BlockIsReachableFrom(StartBB, *PI, VisitedBlocks)) {
+      VisitedBlocks[DestBB] = 1;
+      return true;
+    }
+  }
+  
+  // If we scanned all of our predecessors and we couldn't find a path to 
+  // StartBB, then this block must be unreachable for sure.  Record this to
+  // prevent visitation of this block in the future.
+  VisitedBlocks[DestBB] = 2;
+  return false;
+}
+
+/// RemoveUnreachableUsersOf - For each user of Inst, scan up the CFG until we
+/// find Inst.  If Inst is found, then the user is live, otherwise it is dead.
+/// Remove dead users.  This is basically a poor-man's dominance query, and is
+/// worst-case linear time in the number of blocks in the function.
+static void RemoveUnreachableUsersOf(Instruction *Inst) {
+  DenseMap<BasicBlock*, unsigned> VisitedBlocks;
+  
+  BasicBlock *InstBB = Inst->getParent();
+  for (Instruction::use_iterator UI = Inst->use_begin(), E = Inst->use_end();
+       UI != E;) {
+    Instruction *User = cast<Instruction>(*UI);
+    Use &TheUse = UI.getUse();
+    
+    if (PHINode *PN = dyn_cast<PHINode>(User)) {
+      unsigned UseOp = UI.getOperandNo();
+      ++UI;
+      
+      if (BlockIsReachableFrom(InstBB, PN->getIncomingBlock(UseOp/2),
+                               VisitedBlocks))
+        continue;
+    } else {
+      ++UI;
+      if (BlockIsReachableFrom(InstBB, User->getParent(),
+                               VisitedBlocks))
+        continue;
+    }
+    // If there is no path from Inst to this User, then this user is in dead
+    // code.  Just replace uses of Inst with undef.
+    TheUse = UndefValue::get(Inst->getType());
+  }
+}
+
+
 /// TryToSimplifyUncondBranchFromEmptyBlock - BB contains an unconditional
 /// branch to Succ, and contains no instructions other than PHI nodes and the
 /// branch.  If possible, eliminate BB.
@@ -216,12 +285,18 @@
   }
   
   if (isa<PHINode>(&BB->front())) {
-    SmallVector<BasicBlock*, 16>
-    OldSuccPreds(pred_begin(Succ), pred_end(Succ));
+    SmallVector<BasicBlock*, 16> OldSuccPreds(pred_begin(Succ),
+                                              pred_end(Succ));
     
     // Move all PHI nodes in BB to Succ if they are alive, otherwise
     // delete them.
     while (PHINode *PN = dyn_cast<PHINode>(&BB->front())) {
+      // The algorithm below will not work if there are users of PN that are in
+      // unreachable blocks.  These users will not be properly dominated by the
+      // instruction, but the IR is valid because dead code does not need to
+      // obey dominance properties.
+      RemoveUnreachableUsersOf(PN);
+      
       if (PN->use_empty()) {
         // Just remove the dead phi.  This happens if Succ's PHIs were the only
         // users of the PHI nodes.

Added: llvm/trunk/test/Transforms/SimplifyCFG/2009-01-18-PHIPropCrash.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SimplifyCFG/2009-01-18-PHIPropCrash.ll?rev=62487&view=auto

==============================================================================
--- llvm/trunk/test/Transforms/SimplifyCFG/2009-01-18-PHIPropCrash.ll (added)
+++ llvm/trunk/test/Transforms/SimplifyCFG/2009-01-18-PHIPropCrash.ll Sun Jan 18 20:46:28 2009
@@ -0,0 +1,30 @@
+; RUN: llvm-as < %s | opt -simplifycfg | llvm-dis
+; PR3016
+; Dead use caused invariant violation.
+
+define i32 @func_105(i1 %tmp5, i1 %tmp7) nounwind {
+BB:
+	br i1 true, label %BB2, label %BB1
+
+BB1:		; preds = %BB
+	br label %BB2
+
+BB2:		; preds = %BB1, %BB
+	%tmp3 = phi i1 [ true, %BB ], [ false, %BB1 ]		; <i1> [#uses=1]
+	br label %BB9
+
+BB9:		; preds = %BB11, %BB2
+	%tmp10 = phi i32 [ 0, %BB2 ], [ %tmp12, %BB11 ]		; <i32> [#uses=1]
+	br i1 %tmp5, label %BB11, label %BB13
+
+BB11:		; preds = %BB13, %BB9
+	%tmp12 = phi i32 [ 0, %BB13 ], [ %tmp10, %BB9 ]		; <i32> [#uses=2]
+	br i1 %tmp3, label %BB9, label %BB20
+
+BB13:		; preds = %BB13, %BB9
+	%tmp14 = phi i32 [ 0, %BB9 ], [ %tmp14, %BB13 ]		; <i32> [#uses=1]
+	br i1 %tmp7, label %BB13, label %BB11
+
+BB20:		; preds = %BB11
+	ret i32 %tmp12
+}





More information about the llvm-commits mailing list