mirror of
https://github.com/RPCSX/llvm.git
synced 2025-02-01 10:02:42 +00:00
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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@64866 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
f284ce203b
commit
d2067fd730
@ -463,21 +463,24 @@ static const Type *getEffectiveIndvarType(const PHINode *Phi) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// TestOrigIVForWrap - Analyze the original induction variable
|
/// TestOrigIVForWrap - Analyze the original induction variable
|
||||||
/// in the loop to determine whether it would ever undergo signed
|
/// that controls the loop's iteration to determine whether it
|
||||||
/// or unsigned overflow.
|
/// 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.
|
/// TODO: This duplicates a fair amount of ScalarEvolution logic.
|
||||||
/// Perhaps this can be merged with ScalarEvolution::getIterationCount
|
/// Perhaps this can be merged with ScalarEvolution::getIterationCount
|
||||||
/// and/or ScalarEvolution::get{Sign,Zero}ExtendExpr.
|
/// and/or ScalarEvolution::get{Sign,Zero}ExtendExpr.
|
||||||
///
|
///
|
||||||
static void TestOrigIVForWrap(const Loop *L,
|
static const PHINode *TestOrigIVForWrap(const Loop *L,
|
||||||
const BranchInst *BI,
|
const BranchInst *BI,
|
||||||
const Instruction *OrigCond,
|
const Instruction *OrigCond,
|
||||||
bool &NoSignedWrap,
|
bool &NoSignedWrap,
|
||||||
bool &NoUnsignedWrap) {
|
bool &NoUnsignedWrap) {
|
||||||
// Verify that the loop is sane and find the exit condition.
|
// Verify that the loop is sane and find the exit condition.
|
||||||
const ICmpInst *Cmp = dyn_cast<ICmpInst>(OrigCond);
|
const ICmpInst *Cmp = dyn_cast<ICmpInst>(OrigCond);
|
||||||
if (!Cmp) return;
|
if (!Cmp) return 0;
|
||||||
|
|
||||||
const Value *CmpLHS = Cmp->getOperand(0);
|
const Value *CmpLHS = Cmp->getOperand(0);
|
||||||
const Value *CmpRHS = Cmp->getOperand(1);
|
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.
|
// For now, analyze only LT loops for signed overflow.
|
||||||
if (Pred != ICmpInst::ICMP_SLT && Pred != ICmpInst::ICMP_ULT)
|
if (Pred != ICmpInst::ICMP_SLT && Pred != ICmpInst::ICMP_ULT)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
bool isSigned = Pred == ICmpInst::ICMP_SLT;
|
bool isSigned = Pred == ICmpInst::ICMP_SLT;
|
||||||
|
|
||||||
@ -543,7 +546,7 @@ static void TestOrigIVForWrap(const Loop *L,
|
|||||||
if (!isa<ConstantInt>(CmpRHS) ||
|
if (!isa<ConstantInt>(CmpRHS) ||
|
||||||
!cast<ConstantInt>(CmpRHS)->getValue()
|
!cast<ConstantInt>(CmpRHS)->getValue()
|
||||||
.isSignedIntN(IncrVal->getType()->getPrimitiveSizeInBits()))
|
.isSignedIntN(IncrVal->getType()->getPrimitiveSizeInBits()))
|
||||||
return;
|
return 0;
|
||||||
IncrVal = SI->getOperand(0);
|
IncrVal = SI->getOperand(0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -551,7 +554,7 @@ static void TestOrigIVForWrap(const Loop *L,
|
|||||||
if (!isa<ConstantInt>(CmpRHS) ||
|
if (!isa<ConstantInt>(CmpRHS) ||
|
||||||
!cast<ConstantInt>(CmpRHS)->getValue()
|
!cast<ConstantInt>(CmpRHS)->getValue()
|
||||||
.isIntN(IncrVal->getType()->getPrimitiveSizeInBits()))
|
.isIntN(IncrVal->getType()->getPrimitiveSizeInBits()))
|
||||||
return;
|
return 0;
|
||||||
IncrVal = ZI->getOperand(0);
|
IncrVal = ZI->getOperand(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -562,26 +565,26 @@ static void TestOrigIVForWrap(const Loop *L,
|
|||||||
IncrOp->getOpcode() != Instruction::Add ||
|
IncrOp->getOpcode() != Instruction::Add ||
|
||||||
!isa<ConstantInt>(IncrOp->getOperand(1)) ||
|
!isa<ConstantInt>(IncrOp->getOperand(1)) ||
|
||||||
!cast<ConstantInt>(IncrOp->getOperand(1))->equalsInt(1))
|
!cast<ConstantInt>(IncrOp->getOperand(1))->equalsInt(1))
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
// Make sure the PHI looks like a normal IV.
|
// Make sure the PHI looks like a normal IV.
|
||||||
const PHINode *PN = dyn_cast<PHINode>(IncrOp->getOperand(0));
|
const PHINode *PN = dyn_cast<PHINode>(IncrOp->getOperand(0));
|
||||||
if (!PN || PN->getNumIncomingValues() != 2)
|
if (!PN || PN->getNumIncomingValues() != 2)
|
||||||
return;
|
return 0;
|
||||||
unsigned IncomingEdge = L->contains(PN->getIncomingBlock(0));
|
unsigned IncomingEdge = L->contains(PN->getIncomingBlock(0));
|
||||||
unsigned BackEdge = !IncomingEdge;
|
unsigned BackEdge = !IncomingEdge;
|
||||||
if (!L->contains(PN->getIncomingBlock(BackEdge)) ||
|
if (!L->contains(PN->getIncomingBlock(BackEdge)) ||
|
||||||
PN->getIncomingValue(BackEdge) != IncrOp)
|
PN->getIncomingValue(BackEdge) != IncrOp)
|
||||||
return;
|
return 0;
|
||||||
if (!L->contains(TrueBB))
|
if (!L->contains(TrueBB))
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
// For now, only analyze loops with a constant start value, so that
|
// 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
|
// we can easily determine if the start value is not a maximum value
|
||||||
// which would wrap on the first iteration.
|
// which would wrap on the first iteration.
|
||||||
const Value *InitialVal = PN->getIncomingValue(IncomingEdge);
|
const Value *InitialVal = PN->getIncomingValue(IncomingEdge);
|
||||||
if (!isa<ConstantInt>(InitialVal))
|
if (!isa<ConstantInt>(InitialVal))
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
// The original induction variable will start at some non-max value,
|
// The original induction variable will start at some non-max value,
|
||||||
// it counts up by one, and the loop iterates only while it remans
|
// 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 &&
|
else if (!isSigned &&
|
||||||
!cast<ConstantInt>(InitialVal)->getValue().isMaxValue())
|
!cast<ConstantInt>(InitialVal)->getValue().isMaxValue())
|
||||||
NoUnsignedWrap = true;
|
NoUnsignedWrap = true;
|
||||||
|
return PN;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IndVarSimplify::runOnLoop(Loop *L, LPPassManager &LPM) {
|
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.
|
// using it. We can currently only handle loops with a single exit.
|
||||||
bool NoSignedWrap = false;
|
bool NoSignedWrap = false;
|
||||||
bool NoUnsignedWrap = false;
|
bool NoUnsignedWrap = false;
|
||||||
|
const PHINode *OrigControllingPHI = 0;
|
||||||
if (!isa<SCEVCouldNotCompute>(IterationCount) && ExitingBlock)
|
if (!isa<SCEVCouldNotCompute>(IterationCount) && ExitingBlock)
|
||||||
// Can't rewrite non-branch yet.
|
// Can't rewrite non-branch yet.
|
||||||
if (BranchInst *BI = dyn_cast<BranchInst>(ExitingBlock->getTerminator())) {
|
if (BranchInst *BI = dyn_cast<BranchInst>(ExitingBlock->getTerminator())) {
|
||||||
if (Instruction *OrigCond = dyn_cast<Instruction>(BI->getCondition())) {
|
if (Instruction *OrigCond = dyn_cast<Instruction>(BI->getCondition())) {
|
||||||
// Determine if the OrigIV will ever undergo overflow.
|
// Determine if the OrigIV will ever undergo overflow.
|
||||||
TestOrigIVForWrap(L, BI, OrigCond,
|
OrigControllingPHI =
|
||||||
NoSignedWrap, NoUnsignedWrap);
|
TestOrigIVForWrap(L, BI, OrigCond,
|
||||||
|
NoSignedWrap, NoUnsignedWrap);
|
||||||
|
|
||||||
// We'll be replacing the original condition, so it'll be dead.
|
// We'll be replacing the original condition, so it'll be dead.
|
||||||
DeadInsts.insert(OrigCond);
|
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,
|
/// 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
|
/// and the original has uses that are casts to wider types, see if the
|
||||||
/// truncate and extend can be omitted.
|
/// 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();
|
for (Value::use_iterator UI = PN->use_begin(), UE = PN->use_end();
|
||||||
UI != UE; ++UI) {
|
UI != UE; ++UI) {
|
||||||
if (isa<SExtInst>(UI) && NoSignedWrap) {
|
if (isa<SExtInst>(UI) && NoSignedWrap) {
|
||||||
|
38
test/Transforms/IndVarSimplify/preserve-signed-wrap.ll
Normal file
38
test/Transforms/IndVarSimplify/preserve-signed-wrap.ll
Normal file
@ -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 ; <i1> [#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 ] ; <i32> [#uses=2]
|
||||||
|
%p.01 = phi i8 [ %4, %bb1 ], [ -1, %bb.nph ] ; <i8> [#uses=2]
|
||||||
|
%1 = sext i8 %p.01 to i32 ; <i32> [#uses=1]
|
||||||
|
%2 = sext i32 %i.02 to i64 ; <i64> [#uses=1]
|
||||||
|
%3 = getelementptr i32* %d, i64 %2 ; <i32*> [#uses=1]
|
||||||
|
store i32 %1, i32* %3, align 4
|
||||||
|
%4 = add i8 %p.01, 1 ; <i8> [#uses=1]
|
||||||
|
%5 = add i32 %i.02, 1 ; <i32> [#uses=2]
|
||||||
|
br label %bb1
|
||||||
|
|
||||||
|
bb1: ; preds = %bb
|
||||||
|
%6 = icmp slt i32 %5, %n ; <i1> [#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
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user