From 3fc2e6714009aa35a7bdee0454eb517c985195ae Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 18 Feb 2009 00:52:00 +0000 Subject: [PATCH] Fix a corner case in the new indvars promotion logic: if there are multiple IV's in a loop, some of them may under go signed or unsigned wrapping even if the IV that's used in the loop exit condition doesn't. Restrict sign-extension-elimination and zero-extension-elimination to only those that operate on the original loop-controlling IV. llvm-svn: 64866 --- lib/Transforms/Scalar/IndVarSimplify.cpp | 44 +++++++++++-------- .../IndVarSimplify/preserve-signed-wrap.ll | 38 ++++++++++++++++ 2 files changed, 63 insertions(+), 19 deletions(-) create mode 100644 test/Transforms/IndVarSimplify/preserve-signed-wrap.ll diff --git a/lib/Transforms/Scalar/IndVarSimplify.cpp b/lib/Transforms/Scalar/IndVarSimplify.cpp index 4cfe3595bee..c496c57836f 100644 --- a/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -463,21 +463,24 @@ static const Type *getEffectiveIndvarType(const PHINode *Phi) { } /// TestOrigIVForWrap - Analyze the original induction variable -/// in the loop to determine whether it would ever undergo signed -/// or unsigned overflow. +/// that controls the loop's iteration to determine whether it +/// would ever undergo signed or unsigned overflow. +/// +/// In addition to setting the NoSignedWrap and NoUnsignedWrap +/// variables, return the PHI for this induction variable. /// /// TODO: This duplicates a fair amount of ScalarEvolution logic. /// Perhaps this can be merged with ScalarEvolution::getIterationCount /// and/or ScalarEvolution::get{Sign,Zero}ExtendExpr. /// -static void TestOrigIVForWrap(const Loop *L, - const BranchInst *BI, - const Instruction *OrigCond, - bool &NoSignedWrap, - bool &NoUnsignedWrap) { +static const PHINode *TestOrigIVForWrap(const Loop *L, + const BranchInst *BI, + const Instruction *OrigCond, + bool &NoSignedWrap, + bool &NoUnsignedWrap) { // Verify that the loop is sane and find the exit condition. const ICmpInst *Cmp = dyn_cast(OrigCond); - if (!Cmp) return; + if (!Cmp) return 0; const Value *CmpLHS = Cmp->getOperand(0); const Value *CmpRHS = Cmp->getOperand(1); @@ -530,7 +533,7 @@ static void TestOrigIVForWrap(const Loop *L, } // For now, analyze only LT loops for signed overflow. if (Pred != ICmpInst::ICMP_SLT && Pred != ICmpInst::ICMP_ULT) - return; + return 0; bool isSigned = Pred == ICmpInst::ICMP_SLT; @@ -543,7 +546,7 @@ static void TestOrigIVForWrap(const Loop *L, if (!isa(CmpRHS) || !cast(CmpRHS)->getValue() .isSignedIntN(IncrVal->getType()->getPrimitiveSizeInBits())) - return; + return 0; IncrVal = SI->getOperand(0); } } else { @@ -551,7 +554,7 @@ static void TestOrigIVForWrap(const Loop *L, if (!isa(CmpRHS) || !cast(CmpRHS)->getValue() .isIntN(IncrVal->getType()->getPrimitiveSizeInBits())) - return; + return 0; IncrVal = ZI->getOperand(0); } } @@ -562,26 +565,26 @@ static void TestOrigIVForWrap(const Loop *L, IncrOp->getOpcode() != Instruction::Add || !isa(IncrOp->getOperand(1)) || !cast(IncrOp->getOperand(1))->equalsInt(1)) - return; + return 0; // Make sure the PHI looks like a normal IV. const PHINode *PN = dyn_cast(IncrOp->getOperand(0)); if (!PN || PN->getNumIncomingValues() != 2) - return; + return 0; unsigned IncomingEdge = L->contains(PN->getIncomingBlock(0)); unsigned BackEdge = !IncomingEdge; if (!L->contains(PN->getIncomingBlock(BackEdge)) || PN->getIncomingValue(BackEdge) != IncrOp) - return; + return 0; if (!L->contains(TrueBB)) - return; + return 0; // For now, only analyze loops with a constant start value, so that // we can easily determine if the start value is not a maximum value // which would wrap on the first iteration. const Value *InitialVal = PN->getIncomingValue(IncomingEdge); if (!isa(InitialVal)) - return; + return 0; // The original induction variable will start at some non-max value, // it counts up by one, and the loop iterates only while it remans @@ -592,6 +595,7 @@ static void TestOrigIVForWrap(const Loop *L, else if (!isSigned && !cast(InitialVal)->getValue().isMaxValue()) NoUnsignedWrap = true; + return PN; } bool IndVarSimplify::runOnLoop(Loop *L, LPPassManager &LPM) { @@ -675,13 +679,15 @@ bool IndVarSimplify::runOnLoop(Loop *L, LPPassManager &LPM) { // using it. We can currently only handle loops with a single exit. bool NoSignedWrap = false; bool NoUnsignedWrap = false; + const PHINode *OrigControllingPHI = 0; if (!isa(IterationCount) && ExitingBlock) // Can't rewrite non-branch yet. if (BranchInst *BI = dyn_cast(ExitingBlock->getTerminator())) { if (Instruction *OrigCond = dyn_cast(BI->getCondition())) { // Determine if the OrigIV will ever undergo overflow. - TestOrigIVForWrap(L, BI, OrigCond, - NoSignedWrap, NoUnsignedWrap); + OrigControllingPHI = + TestOrigIVForWrap(L, BI, OrigCond, + NoSignedWrap, NoUnsignedWrap); // We'll be replacing the original condition, so it'll be dead. DeadInsts.insert(OrigCond); @@ -722,7 +728,7 @@ bool IndVarSimplify::runOnLoop(Loop *L, LPPassManager &LPM) { /// If the new canonical induction variable is wider than the original, /// and the original has uses that are casts to wider types, see if the /// truncate and extend can be omitted. - if (PN->getType() != LargestType) + if (PN == OrigControllingPHI && PN->getType() != LargestType) for (Value::use_iterator UI = PN->use_begin(), UE = PN->use_end(); UI != UE; ++UI) { if (isa(UI) && NoSignedWrap) { diff --git a/test/Transforms/IndVarSimplify/preserve-signed-wrap.ll b/test/Transforms/IndVarSimplify/preserve-signed-wrap.ll new file mode 100644 index 00000000000..0a91ec88064 --- /dev/null +++ b/test/Transforms/IndVarSimplify/preserve-signed-wrap.ll @@ -0,0 +1,38 @@ +; RUN: llvm-as < %s | opt -indvars | llvm-dis > %t +; RUN: grep sext %t | count 1 +; RUN: grep phi %t | count 1 +; RUN: grep {phi i64} %t + +; Indvars should insert a 64-bit induction variable to eliminate the +; sext for the addressing, however it shouldn't eliminate the sext +; on the other phi, since that value undergoes signed wrapping. + +define void @foo(i32* nocapture %d, i32 %n) nounwind { +entry: + %0 = icmp sgt i32 %n, 0 ; [#uses=1] + br i1 %0, label %bb.nph, label %return + +bb.nph: ; preds = %entry + br label %bb + +bb: ; preds = %bb1, %bb.nph + %i.02 = phi i32 [ %5, %bb1 ], [ 0, %bb.nph ] ; [#uses=2] + %p.01 = phi i8 [ %4, %bb1 ], [ -1, %bb.nph ] ; [#uses=2] + %1 = sext i8 %p.01 to i32 ; [#uses=1] + %2 = sext i32 %i.02 to i64 ; [#uses=1] + %3 = getelementptr i32* %d, i64 %2 ; [#uses=1] + store i32 %1, i32* %3, align 4 + %4 = add i8 %p.01, 1 ; [#uses=1] + %5 = add i32 %i.02, 1 ; [#uses=2] + br label %bb1 + +bb1: ; preds = %bb + %6 = icmp slt i32 %5, %n ; [#uses=1] + br i1 %6, label %bb, label %bb1.return_crit_edge + +bb1.return_crit_edge: ; preds = %bb1 + br label %return + +return: ; preds = %bb1.return_crit_edge, %entry + ret void +}