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

David Blaikie dblaikie at gmail.com
Wed Oct 5 09:33:39 PDT 2011


Interesting. Might this help the proposed workaround/fix for
http://llvm.org/bugs/show_bug.cgi?id=3100 work?
From: Duncan Sands
Sent: 10/5/2011 7:34 AM
To: llvm-commits at cs.uiuc.edu
Subject: [llvm-commits] [llvm] r141177 - in /llvm/trunk:
lib/Transforms/Scalar/GVN.cpp test/Transforms/GVN/condprop.ll
test/Transforms/GVN/phi-translate.ll
Author: baldrick
Date: Wed Oct  5 09:28:49 2011
New Revision: 141177

URL: http://llvm.org/viewvc/llvm-project?rev=141177&view=rev
Log:
GVN does simple propagation of conditions: when it sees a conditional
branch "br i1 %x, label %if_true, label %if_false" then it replaces
"%x" with "true" in places only reachable via the %if_true arm, and
with "false" in places only reachable via the %if_false arm.  Except
that actually it doesn't: if value numbering shows that %y is equal
to %x then, yes, %y will be turned into true/false in this way, but
any occurrences of %x itself are not transformed.  Fix this.  What's
more, it's often the case that %x is an equality comparison such as
"%x = icmp eq %A, 0", in which case every occurrence of %A that is
only reachable via the %if_true arm can be replaced with 0.  Implement
this and a few other variations on this theme.  This reduces the number
of lines of LLVM IR in "GCC as one big file" by 0.2%.  It has a bigger
impact on Ada code, typically reducing the number of lines of bitcode
by around 0.4% by removing repeated compiler generated checks.  Passes
the LLVM nightly testsuite and the Ada ACATS testsuite.

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

Modified: llvm/trunk/lib/Transforms/Scalar/GVN.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/GVN.cpp?rev=141177&r1=141176&r2=141177&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/GVN.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/GVN.cpp Wed Oct  5 09:28:49 2011
@@ -41,12 +41,16 @@
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/IRBuilder.h"
+#include "llvm/Support/PatternMatch.h"
 using namespace llvm;
+using namespace PatternMatch;

 STATISTIC(NumGVNInstr,  "Number of instructions deleted");
 STATISTIC(NumGVNLoad,   "Number of loads deleted");
 STATISTIC(NumGVNPRE,    "Number of instructions PRE'd");
 STATISTIC(NumGVNBlocks, "Number of blocks merged");
+STATISTIC(NumGVNSimpl,  "Number of instructions simplified");
+STATISTIC(NumGVNEqProp, "Number of equalities propagated");
 STATISTIC(NumPRELoad,   "Number of loads PRE'd");

 static cl::opt<bool> EnablePRE("enable-pre",
@@ -548,6 +552,9 @@
     void cleanupGlobalSets();
     void verifyRemoved(const Instruction *I) const;
     bool splitCriticalEdges();
+    unsigned replaceAllDominatedUsesWith(Value *From, Value *To,
+                                         BasicBlock *Root);
+    bool propagateEquality(Value *LHS, Value *RHS, BasicBlock *Root);
   };

   char GVN::ID = 0;
@@ -1881,6 +1888,97 @@
   return Val;
 }

+/// replaceAllDominatedUsesWith - Replace all uses of 'From' with 'To' if the
+/// use is dominated by the given basic block.  Returns the number of uses that
+/// were replaced.
+unsigned GVN::replaceAllDominatedUsesWith(Value *From, Value *To,
+                                          BasicBlock *Root) {
+  unsigned Count = 0;
+  for (Value::use_iterator UI = From->use_begin(), UE = From->use_end();
+       UI != UE; ) {
+    Instruction *User = cast<Instruction>(*UI);
+    unsigned OpNum = UI.getOperandNo();
+    ++UI;
+
+    if (DT->dominates(Root, User->getParent())) {
+      User->setOperand(OpNum, To);
+      ++Count;
+    }
+  }
+  return Count;
+}
+
+/// propagateEquality - The given values are known to be equal in every block
+/// dominated by 'Root'.  Exploit this, for example by replacing 'LHS' with
+/// 'RHS' everywhere in the scope.  Returns whether a change was made.
+bool GVN::propagateEquality(Value *LHS, Value *RHS, BasicBlock *Root) {
+  if (LHS == RHS) return false;
+  assert(LHS->getType() == RHS->getType() && "Equal but types differ!");
+
+  // Don't try to propagate equalities between constants.
+  if (isa<Constant>(LHS) && isa<Constant>(RHS))
+    return false;
+
+  // Make sure that any constants are on the right-hand side.  In general the
+  // best results are obtained by placing the longest lived value on the RHS.
+  if (isa<Constant>(LHS))
+    std::swap(LHS, RHS);
+
+  // If neither term is constant then bail out.  This is not for correctness,
+  // it's just that the non-constant case is much less useful: it occurs just
+  // as often as the constant case but handling it hardly ever results in an
+  // improvement.
+  if (!isa<Constant>(RHS))
+    return false;
+
+  // If value numbering later deduces that an instruction in the scope is equal
+  // to 'LHS' then ensure it will be turned into 'RHS'.
+  addToLeaderTable(VN.lookup_or_add(LHS), RHS, Root);
+
+  // Replace all occurrences of 'LHS' with 'RHS' everywhere in the scope.
+  unsigned NumReplacements = replaceAllDominatedUsesWith(LHS, RHS, Root);
+  bool Changed = NumReplacements > 0;
+  NumGVNEqProp += NumReplacements;
+
+  // Now try to deduce additional equalities from this one.  For
example, if the
+  // known equality was "(A != B)" == "false" then it follows that A and B are
+  // equal in the scope.  Only boolean equalities with an explicit
true or false
+  // RHS are currently supported.
+  if (!RHS->getType()->isIntegerTy(1))
+    // Not a boolean equality - bail out.
+    return Changed;
+  ConstantInt *CI = dyn_cast<ConstantInt>(RHS);
+  if (!CI)
+    // RHS neither 'true' nor 'false' - bail out.
+    return Changed;
+  // Whether RHS equals 'true'.  Otherwise it equals 'false'.
+  bool isKnownTrue = CI->isAllOnesValue();
+  bool isKnownFalse = !isKnownTrue;
+
+  // If "A && B" is known true then both A and B are known true.  If "A || B"
+  // is known false then both A and B are known false.
+  Value *A, *B;
+  if ((isKnownTrue && match(LHS, m_And(m_Value(A), m_Value(B)))) ||
+      (isKnownFalse && match(LHS, m_Or(m_Value(A), m_Value(B))))) {
+    Changed |= propagateEquality(A, RHS, Root);
+    Changed |= propagateEquality(B, RHS, Root);
+    return Changed;
+  }
+
+  // If we are propagating an equality like "(A == B)" == "true" then also
+  // propagate the equality A == B.
+  if (ICmpInst *Cmp = dyn_cast<ICmpInst>(LHS)) {
+    // Only equality comparisons are supported.
+    if ((isKnownTrue && Cmp->getPredicate() == CmpInst::ICMP_EQ) ||
+        (isKnownFalse && Cmp->getPredicate() == CmpInst::ICMP_NE)) {
+      Value *Op0 = Cmp->getOperand(0), *Op1 = Cmp->getOperand(1);
+      Changed |= propagateEquality(Op0, Op1, Root);
+    }
+    return Changed;
+  }
+
+  return Changed;
+}

 /// processInstruction - When calculating availability, handle an instruction
 /// by inserting it into the appropriate sets
@@ -1898,6 +1996,7 @@
     if (MD && V->getType()->isPointerTy())
       MD->invalidateCachedPointerInfo(V);
     markInstructionForDeletion(I);
+    ++NumGVNSimpl;
     return true;
   }

@@ -1910,15 +2009,15 @@
     return false;
   }

-  // For conditions branches, we can perform simple conditional propagation on
+  // 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;
-
+
     Value *BranchCond = BI->getCondition();
-    uint32_t CondVN = VN.lookup_or_add(BranchCond);
-
+
     BasicBlock *TrueSucc = BI->getSuccessor(0);
     BasicBlock *FalseSucc = BI->getSuccessor(1);
     BasicBlock *Parent = BI->getParent();
@@ -1947,16 +2046,14 @@
         break;
       }

-    if (TrueSucc)
-      addToLeaderTable(CondVN,
-                   ConstantInt::getTrue(TrueSucc->getContext()),
-                   TrueSucc);
-    if (FalseSucc)
-      addToLeaderTable(CondVN,
-                   ConstantInt::getFalse(FalseSucc->getContext()),
-                   FalseSucc);
-
-    return false;
+    // 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,
+
ConstantInt::getTrue(TrueSucc->getContext()),
+                                   TrueSucc))
+      || (FalseSucc && propagateEquality(BranchCond,
+
ConstantInt::getFalse(FalseSucc->getContext()),
+                                 FalseSucc));
   }

   // Instructions with void type don't return a value, so there's

Modified: llvm/trunk/test/Transforms/GVN/condprop.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GVN/condprop.ll?rev=141177&r1=141176&r2=141177&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/GVN/condprop.ll (original)
+++ llvm/trunk/test/Transforms/GVN/condprop.ll Wed Oct  5 09:28:49 2011
@@ -2,8 +2,8 @@

 @a = external global i32		; <i32*> [#uses=7]

-; CHECK: @foo
-define i32 @foo() nounwind {
+; CHECK: @test1
+define i32 @test1() nounwind {
 entry:
 	%0 = load i32* @a, align 4
 	%1 = icmp eq i32 %0, 4
@@ -54,22 +54,46 @@
 	ret i32 %.0
 }

-declare void @ext(i1)
+declare void @foo(i1)

-; CHECK: @bar
-define void @bar(i1 %x, i1 %y) {
+; CHECK: @test2
+define void @test2(i1 %x, i1 %y) {
   %z = or i1 %x, %y
   br i1 %z, label %true, label %false
 true:
 ; CHECK: true:
   %z2 = or i1 %x, %y
-  call void @ext(i1 %z2)
-; CHECK: call void @ext(i1 true)
+  call void @foo(i1 %z2)
+; CHECK: call void @foo(i1 true)
   br label %true
 false:
 ; CHECK: false:
   %z3 = or i1 %x, %y
-  call void @ext(i1 %z3)
-; CHECK: call void @ext(i1 false)
+  call void @foo(i1 %z3)
+; CHECK: call void @foo(i1 false)
   br label %false
 }
+
+declare void @bar(i32)
+
+; CHECK: @test3
+define void @test3(i32 %x, i32 %y) {
+  %xz = icmp eq i32 %x, 0
+  %yz = icmp eq i32 %y, 0
+  %z = and i1 %xz, %yz
+  br i1 %z, label %both_zero, label %nope
+both_zero:
+  call void @foo(i1 %xz)
+; CHECK: call void @foo(i1 true)
+  call void @foo(i1 %yz)
+; CHECK: call void @foo(i1 true)
+  call void @bar(i32 %x)
+; CHECK: call void @bar(i32 0)
+  call void @bar(i32 %y)
+; CHECK: call void @bar(i32 0)
+  ret void
+nope:
+  call void @foo(i1 %z)
+; CHECK: call void @foo(i1 false)
+  ret void
+}

Modified: llvm/trunk/test/Transforms/GVN/phi-translate.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GVN/phi-translate.ll?rev=141177&r1=141176&r2=141177&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/GVN/phi-translate.ll (original)
+++ llvm/trunk/test/Transforms/GVN/phi-translate.ll Wed Oct  5 09:28:49 2011
@@ -14,7 +14,7 @@
 @G = external global [100 x i32]
 define i32 @foo(i32 %x, i32 %z) {
 entry:
-  %tobool = icmp eq i32 %x, 0
+  %tobool = icmp eq i32 %z, 0
   br i1 %tobool, label %end, label %then

 then:


_______________________________________________
llvm-commits mailing list
llvm-commits at cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits



More information about the llvm-commits mailing list