[llvm-commits] [llvm] r132103 - in /llvm/trunk: lib/Transforms/Scalar/IndVarSimplify.cpp test/Transforms/IndVarSimplify/elim-extend.ll

Andrew Trick atrick at apple.com
Wed May 25 17:46:11 PDT 2011


Author: atrick
Date: Wed May 25 19:46:11 2011
New Revision: 132103

URL: http://llvm.org/viewvc/llvm-project?rev=132103&view=rev
Log:
indvars: incremental fixes for -disable-iv-rewrite and testcases.

Use a proper worklist for use-def traversal without holding onto an
iterator. Now that we process all IV uses, we need complete logic for
resusing existing derived IV defs. See HoistStep.

Modified:
    llvm/trunk/lib/Transforms/Scalar/IndVarSimplify.cpp
    llvm/trunk/test/Transforms/IndVarSimplify/elim-extend.ll

Modified: llvm/trunk/lib/Transforms/Scalar/IndVarSimplify.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/IndVarSimplify.cpp?rev=132103&r1=132102&r2=132103&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/IndVarSimplify.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/IndVarSimplify.cpp Wed May 25 19:46:11 2011
@@ -537,6 +537,7 @@
   LoopInfo *LI;
   Loop *L;
   ScalarEvolution *SE;
+  DominatorTree *DT;
   SmallVectorImpl<WeakVH> &DeadInsts;
 
   PHINode *WidePhi;
@@ -547,7 +548,8 @@
 
 public:
   WidenIV(PHINode *PN, const WideIVInfo &IVInfo, IVUsers *IUsers,
-          LoopInfo *LInfo, ScalarEvolution *SEv, SmallVectorImpl<WeakVH> &DI) :
+          LoopInfo *LInfo, ScalarEvolution *SEv, DominatorTree *DTree,
+          SmallVectorImpl<WeakVH> &DI) :
     OrigPhi(PN),
     WideType(IVInfo.WidestNativeType),
     IsSigned(IVInfo.IsSigned),
@@ -555,6 +557,7 @@
     LI(LInfo),
     L(LI->getLoopFor(OrigPhi->getParent())),
     SE(SEv),
+    DT(DTree),
     DeadInsts(DI),
     WidePhi(0),
     WideInc(0),
@@ -616,7 +619,7 @@
     }
     for (WideIVMap::const_iterator I = IVMap.begin(), E = IVMap.end();
          I != E; ++I) {
-      WidenIV Widener(I->first, I->second, IU, LI, SE, DeadInsts);
+      WidenIV Widener(I->first, I->second, IU, LI, SE, DT, DeadInsts);
       if (Widener.CreateWideIV(Rewriter))
         Changed = true;
     }
@@ -696,6 +699,40 @@
   return AddRec;
 }
 
+/// HoistStep - Attempt to hoist an IV increment above a potential use.
+///
+/// To successfully hoist, two criteria must be met:
+/// - IncV operands dominate InsertPos and
+/// - InsertPos dominates IncV
+///
+/// Meeting the second condition means that we don't need to check all of IncV's
+/// existing uses (it's moving up in the domtree).
+///
+/// This does not yet recursively hoist the operands, although that would
+/// not be difficult.
+static bool HoistStep(Instruction *IncV, Instruction *InsertPos,
+                      const DominatorTree *DT)
+{
+  if (DT->dominates(IncV, InsertPos))
+    return true;
+
+  if (!DT->dominates(InsertPos->getParent(), IncV->getParent()))
+    return false;
+
+  if (IncV->mayHaveSideEffects())
+    return false;
+
+  // Attempt to hoist IncV
+  for (User::op_iterator OI = IncV->op_begin(), OE = IncV->op_end();
+       OI != OE; ++OI) {
+    Instruction *OInst = dyn_cast<Instruction>(OI);
+    if (OInst && !DT->dominates(OInst, InsertPos))
+      return false;
+  }
+  IncV->moveBefore(InsertPos);
+  return true;
+}
+
 /// WidenIVUse - Determine whether an individual user of the narrow IV can be
 /// widened. If so, return the wide clone of the user.
 Instruction *WidenIV::WidenIVUse(Instruction *NarrowUse,
@@ -755,9 +792,10 @@
     NarrowUse->replaceUsesOfWith(NarrowDef, Trunc);
     return 0;
   }
+  // Reuse the IV increment that SCEVExpander created as long as it dominates
+  // NarrowUse.
   Instruction *WideUse = 0;
-  if (WideAddRec == WideIncExpr) {
-    // Reuse the IV increment that SCEVExpander created.
+  if (WideAddRec == WideIncExpr && HoistStep(WideInc, NarrowUse, DT)) {
     WideUse = WideInc;
   }
   else {
@@ -828,32 +866,45 @@
   // WidenIVUse to reuse it when widening the narrow IV's increment. We don't
   // employ a general reuse mechanism because the call above is the only call to
   // SCEVExpander. Henceforth, we produce 1-to-1 narrow to wide uses.
-  assert(WidePhi->hasOneUse() && "New IV has multiple users");
-  WideInc = WidePhi->use_back();
-  WideIncExpr = SE->getSCEV(WideInc);
+  if (BasicBlock *LatchBlock = L->getLoopLatch()) {
+    WideInc =
+      cast<Instruction>(WidePhi->getIncomingValueForBlock(LatchBlock));
+    WideIncExpr = SE->getSCEV(WideInc);
+  }
 
   DEBUG(dbgs() << "Wide IV: " << *WidePhi << "\n");
   ++NumWidened;
 
   // Traverse the def-use chain using a worklist starting at the original IV.
   assert(Processed.empty() && "expect initial state" );
-  SmallVector<std::pair<Instruction *, Instruction *>, 8> NarrowIVUsers;
 
-  NarrowIVUsers.push_back(std::make_pair(OrigPhi, WidePhi));
+  // Each worklist entry has a Narrow def-use link and Wide def.
+  SmallVector<std::pair<Use *, Instruction *>, 8> NarrowIVUsers;
+  for (Value::use_iterator UI = OrigPhi->use_begin(),
+         UE = OrigPhi->use_end(); UI != UE; ++UI) {
+    NarrowIVUsers.push_back(std::make_pair(&UI.getUse(), WidePhi));
+  }
   while (!NarrowIVUsers.empty()) {
-    Instruction *NarrowInst, *WideInst;
-    tie(NarrowInst, WideInst) = NarrowIVUsers.pop_back_val();
-
-    for (Value::use_iterator UI = NarrowInst->use_begin(),
-           UE = NarrowInst->use_end(); UI != UE; ++UI) {
-      Instruction *NarrowUse = cast<Instruction>(*UI);
-      Instruction *WideUse = WidenIVUse(NarrowUse, NarrowInst, WideInst);
-      if (WideUse)
-        NarrowIVUsers.push_back(std::make_pair(NarrowUse, WideUse));
-
-      if (NarrowInst->use_empty())
-        DeadInsts.push_back(NarrowInst);
+    Use *NarrowDefUse;
+    Instruction *WideDef;
+    tie(NarrowDefUse, WideDef) = NarrowIVUsers.pop_back_val();
+
+    // Process a def-use edge. This may replace the use, so don't hold a
+    // use_iterator across it.
+    Instruction *NarrowDef = cast<Instruction>(NarrowDefUse->get());
+    Instruction *NarrowUse = cast<Instruction>(NarrowDefUse->getUser());
+    Instruction *WideUse = WidenIVUse(NarrowUse, NarrowDef, WideDef);
+
+    // Follow all def-use edges from the previous narrow use.
+    if (WideUse) {
+      for (Value::use_iterator UI = NarrowUse->use_begin(),
+             UE = NarrowUse->use_end(); UI != UE; ++UI) {
+        NarrowIVUsers.push_back(std::make_pair(&UI.getUse(), WideUse));
+      }
     }
+    // WidenIVUse may have removed the def-use edge.
+    if (NarrowDef->use_empty())
+      DeadInsts.push_back(NarrowDef);
   }
   return true;
 }

Modified: llvm/trunk/test/Transforms/IndVarSimplify/elim-extend.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/IndVarSimplify/elim-extend.ll?rev=132103&r1=132102&r2=132103&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/IndVarSimplify/elim-extend.ll (original)
+++ llvm/trunk/test/Transforms/IndVarSimplify/elim-extend.ll Wed May 25 19:46:11 2011
@@ -2,7 +2,72 @@
 
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
 
-; Tests sign extend elimination in the inner and outer loop.
+; Test reusing the same IV with constant start for preinc and postinc values
+; with and without NSW.
+; IV rewrite only removes one sext. WidenIVs should remove all three.
+define void @postincConstIV(i8* %base, i32 %limit) nounwind {
+entry:
+  br label %loop
+; CHECK: loop:
+; CHECK-NOT: sext
+; CHECK: exit:
+loop:
+  %iv = phi i32 [ %postiv, %loop ], [ 0, %entry ]
+  %ivnsw = phi i32 [ %postivnsw, %loop ], [ 0, %entry ]
+  %preofs = sext i32 %iv to i64
+  %preadr = getelementptr i8* %base, i64 %preofs
+  store i8 0, i8* %preadr
+  %postiv = add i32 %iv, 1
+  %postofs = sext i32 %postiv to i64
+  %postadr = getelementptr i8* %base, i64 %postofs
+  store i8 0, i8* %postadr
+  %postivnsw = add nsw i32 %ivnsw, 1
+  %postofsnsw = sext i32 %postivnsw to i64
+  %postadrnsw = getelementptr i8* %base, i64 %postofsnsw
+  store i8 0, i8* %postadrnsw
+  %cond = icmp sgt i32 %limit, %iv
+  br i1 %cond, label %loop, label %exit
+exit:
+  br label %return
+return:
+  ret void
+}
+
+; Test reusing the same IV with nonconstant start for preinc and postinc values
+; with and without NSW.
+; As with constant IV start, WidenIVs should remove all three.
+;
+; FIXME: WidenIVs should remove %postofs just like %postofsnsw
+define void @postincVarIV(i8* %base, i32 %init, i32 %limit) nounwind {
+entry:
+  br label %loop
+; CHECK: loop:
+; CHECK: sext
+; CHECK-NOT: sext
+; CHECK: exit:
+loop:
+  %iv = phi i32 [ %postiv, %loop ], [ %init, %entry ]
+  %ivnsw = phi i32 [ %postivnsw, %loop ], [ 0, %entry ]
+  %preofs = sext i32 %iv to i64
+  %preadr = getelementptr i8* %base, i64 %preofs
+  store i8 0, i8* %preadr
+  %postiv = add i32 %iv, 1
+  %postofs = sext i32 %postiv to i64
+  %postadr = getelementptr i8* %base, i64 %postofs
+  store i8 0, i8* %postadr
+  %postivnsw = add nsw i32 %ivnsw, 1
+  %postofsnsw = sext i32 %postivnsw to i64
+  %postadrnsw = getelementptr i8* %base, i64 %postofsnsw
+  store i8 0, i8* %postadrnsw
+  %cond = icmp sgt i32 %limit, %iv
+  br i1 %cond, label %loop, label %exit
+exit:
+  br label %return
+return:
+  ret void
+}
+
+; Test sign extend elimination in the inner and outer loop.
 ; %outercount is straightforward to widen, besides being in an outer loop.
 ; %innercount is currently blocked by lcssa, so is not widened.
 ; %inneriv can be widened only after proving it has no signed-overflow





More information about the llvm-commits mailing list