[llvm-commits] [llvm] r141360 - in /llvm/trunk: lib/Transforms/Scalar/GVN.cpp test/Transforms/GVN/condprop.ll

Duncan Sands baldrick at free.fr
Fri Oct 7 01:29:06 PDT 2011


Author: baldrick
Date: Fri Oct  7 03:29:06 2011
New Revision: 141360

URL: http://llvm.org/viewvc/llvm-project?rev=141360&view=rev
Log:
Teach GVN to also propagate switch cases.  For example, in this code
  switch (n) {
    case 27:
      do_something(x);
    ...
  }
the call do_something(x) will be replaced with do_something(27).  In
gcc-as-one-big-file this results in the removal of about 500 lines of
bitcode (about 0.02%), so has about 1/10 of the effect of propagating
branch conditions.

Modified:
    llvm/trunk/lib/Transforms/Scalar/GVN.cpp
    llvm/trunk/test/Transforms/GVN/condprop.ll

Modified: llvm/trunk/lib/Transforms/Scalar/GVN.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/GVN.cpp?rev=141360&r1=141359&r2=141360&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/GVN.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/GVN.cpp Fri Oct  7 03:29:06 2011
@@ -1980,6 +1980,42 @@
   return Changed;
 }
 
+/// isOnlyReachableViaThisEdge - There is an edge from 'Src' to 'Dst'.  Return
+/// true if every path from the entry block to 'Dst' passes via this edge.  In
+/// particular 'Dst' must not be reachable via another edge from 'Src'.
+static bool isOnlyReachableViaThisEdge(BasicBlock *Src, BasicBlock *Dst,
+                                       DominatorTree *DT) {
+  // First off, there must not be more than one edge from Src to Dst, there
+  // should be exactly one.  So keep track of the number of times Src occurs
+  // as a predecessor of Dst and fail if it's more than once.  Secondly, any
+  // other predecessors of Dst should be dominated by Dst (see logic below).
+  bool SawEdgeFromSrc = false;
+  for (pred_iterator PI = pred_begin(Dst), PE = pred_end(Dst); PI != PE; ++PI) {
+    BasicBlock *Pred = *PI;
+    if (Pred == Src) {
+      // An edge from Src to Dst.
+      if (SawEdgeFromSrc)
+        // There are multiple edges from Src to Dst - fail.
+        return false;
+      SawEdgeFromSrc = true;
+      continue;
+    }
+    // If the predecessor is not dominated by Dst, then it must be possible to
+    // reach it either without passing through Src (and thus not via the edge)
+    // or by passing through Src but taking a different edge out of Src.  Either
+    // way it is possible to reach Dst without passing via the edge, so fail.
+    if (!DT->dominates(Dst, *PI))
+      return false;
+  }
+  assert(SawEdgeFromSrc && "No edge between these basic blocks!");
+
+  // Every path from the entry block to Dst must at some point pass to Dst from
+  // a predecessor that is not dominated by Dst.  This predecessor can only be
+  // Src, since all others are dominated by Dst.  As there is only one edge from
+  // Src to Dst, the path passes by this edge.
+  return true;
+}
+
 /// processInstruction - When calculating availability, handle an instruction
 /// by inserting it into the appropriate sets
 bool GVN::processInstruction(Instruction *I) {
@@ -2011,7 +2047,6 @@
 
   // For conditional branches, we can perform simple conditional propagation on
   // the condition value itself.
-  // TODO: Add conditional propagation of switch cases.
   if (BranchInst *BI = dyn_cast<BranchInst>(I)) {
     if (!BI->isConditional() || isa<Constant>(BI->getCondition()))
       return false;
@@ -2021,41 +2056,34 @@
     BasicBlock *TrueSucc = BI->getSuccessor(0);
     BasicBlock *FalseSucc = BI->getSuccessor(1);
     BasicBlock *Parent = BI->getParent();
+    bool Changed = false;
 
-    // If the true and false branches are to the same basic block then the
-    // branch gives no information about the condition.  Eliminating this
-    // here simplifies the rest of the logic.
-    if (TrueSucc == FalseSucc)
-      return false;
-
-    // If the true block can be reached without executing the true edge then we
-    // can't say anything about the value of the condition there.
-    for (pred_iterator PI = pred_begin(TrueSucc), PE = pred_end(TrueSucc);
-         PI != PE; ++PI)
-      if (*PI != Parent && !DT->dominates(TrueSucc, *PI)) {
-        TrueSucc = 0;
-        break;
-      }
-
-    // If the false block can be reached without executing the false edge then
-    // we can't say anything about the value of the condition there.
-    for (pred_iterator PI = pred_begin(FalseSucc), PE = pred_end(FalseSucc);
-         PI != PE; ++PI)
-      if (*PI != Parent && !DT->dominates(FalseSucc, *PI)) {
-        FalseSucc = 0;
-        break;
-      }
-
-    // Replace the condition with true/false in basic blocks that can only be
-    // reached via the true/false arm of the branch.
-    return (TrueSucc && propagateEquality(BranchCond,
+    if (isOnlyReachableViaThisEdge(Parent, TrueSucc, DT))
+      Changed |= propagateEquality(BranchCond,
                                    ConstantInt::getTrue(TrueSucc->getContext()),
-                                   TrueSucc))
-      || (FalseSucc && propagateEquality(BranchCond,
-                                 ConstantInt::getFalse(FalseSucc->getContext()),
-                                 FalseSucc));
+                                   TrueSucc);
+
+    if (isOnlyReachableViaThisEdge(Parent, FalseSucc, DT))
+      Changed |= propagateEquality(BranchCond,
+                                   ConstantInt::getFalse(FalseSucc->getContext()),
+                                   FalseSucc);
+
+    return Changed;
+  }
+
+  // For switches, propagate the case values into the case destinations.
+  if (SwitchInst *SI = dyn_cast<SwitchInst>(I)) {
+    Value *SwitchCond = SI->getCondition();
+    BasicBlock *Parent = SI->getParent();
+    bool Changed = false;
+    for (unsigned i = 1, e = SI->getNumCases(); i != e; ++i) {
+      BasicBlock *Dst = SI->getSuccessor(i);
+      if (isOnlyReachableViaThisEdge(Parent, Dst, DT))
+        Changed |= propagateEquality(SwitchCond, SI->getCaseValue(i), Dst);
+    }
+    return Changed;
   }
-  
+
   // Instructions with void type don't return a value, so there's
   // no point in trying to find redudancies in them.
   if (I->getType()->isVoidTy()) return false;

Modified: llvm/trunk/test/Transforms/GVN/condprop.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GVN/condprop.ll?rev=141360&r1=141359&r2=141360&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/GVN/condprop.ll (original)
+++ llvm/trunk/test/Transforms/GVN/condprop.ll Fri Oct  7 03:29:06 2011
@@ -97,3 +97,36 @@
 ; CHECK: call void @foo(i1 false)
   ret void
 }
+
+; CHECK: @test4
+define void @test4(i1 %b, i32 %x) {
+  br i1 %b, label %sw, label %case3
+sw:
+  switch i32 %x, label %default [
+    i32 0, label %case0
+    i32 1, label %case1
+    i32 2, label %case0
+    i32 3, label %case3
+    i32 4, label %default
+  ]
+default:
+; CHECK: default:
+  call void @bar(i32 %x)
+; CHECK: call void @bar(i32 %x)
+  ret void
+case0:
+; CHECK: case0:
+  call void @bar(i32 %x)
+; CHECK: call void @bar(i32 %x)
+  ret void
+case1:
+; CHECK: case1:
+  call void @bar(i32 %x)
+; CHECK: call void @bar(i32 1)
+  ret void
+case3:
+; CHECK: case3:
+  call void @bar(i32 %x)
+; CHECK: call void @bar(i32 %x)
+  ret void
+}





More information about the llvm-commits mailing list