[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