forked from OSchip/llvm-project
[FIX] Approximate non-affine loops correctly
Before isValidCFG() could hide the fact that a loop is non-affine by over-approximation. This is problematic if a subregion of the loop contains an exit/latch block and is over-approximated. Now we do not over-approximate in the isValidCFG function if we check loop control. If such control is non-affine the whole loop is over-approximated, not only a subregion. llvm-svn: 249273
This commit is contained in:
parent
30ffb6fcb6
commit
757a32b5b3
|
@ -281,33 +281,37 @@ private:
|
|||
|
||||
/// @brief Check if the switch @p SI with condition @p Condition is valid.
|
||||
///
|
||||
/// @param BB The block to check.
|
||||
/// @param SI The switch to check.
|
||||
/// @param Condition The switch condition.
|
||||
/// @param Context The context of scop detection.
|
||||
/// @param BB The block to check.
|
||||
/// @param SI The switch to check.
|
||||
/// @param Condition The switch condition.
|
||||
/// @param IsLoopBranch Flag to indicate the branch is a loop exit/latch.
|
||||
/// @param Context The context of scop detection.
|
||||
///
|
||||
/// @return True if the branch @p BI is valid.
|
||||
bool isValidSwitch(BasicBlock &BB, SwitchInst *SI, Value *Condition,
|
||||
DetectionContext &Context) const;
|
||||
bool IsLoopBranch, DetectionContext &Context) const;
|
||||
|
||||
/// @brief Check if the branch @p BI with condition @p Condition is valid.
|
||||
///
|
||||
/// @param BB The block to check.
|
||||
/// @param BI The branch to check.
|
||||
/// @param Condition The branch condition.
|
||||
/// @param Context The context of scop detection.
|
||||
/// @param BB The block to check.
|
||||
/// @param BI The branch to check.
|
||||
/// @param Condition The branch condition.
|
||||
/// @param IsLoopBranch Flag to indicate the branch is a loop exit/latch.
|
||||
/// @param Context The context of scop detection.
|
||||
///
|
||||
/// @return True if the branch @p BI is valid.
|
||||
bool isValidBranch(BasicBlock &BB, BranchInst *BI, Value *Condition,
|
||||
DetectionContext &Context) const;
|
||||
bool IsLoopBranch, DetectionContext &Context) const;
|
||||
|
||||
/// @brief Check if the control flow in a basic block is valid.
|
||||
///
|
||||
/// @param BB The BB to check the control flow.
|
||||
/// @param Context The context of scop detection.
|
||||
/// @param BB The BB to check the control flow.
|
||||
/// @param IsLoopBranch Flag to indicate the branch is a loop exit/latch.
|
||||
/// @param Context The context of scop detection.
|
||||
///
|
||||
/// @return True if the BB contains only valid control flow.
|
||||
bool isValidCFG(BasicBlock &BB, DetectionContext &Context) const;
|
||||
bool isValidCFG(BasicBlock &BB, bool IsLoopBranch,
|
||||
DetectionContext &Context) const;
|
||||
|
||||
/// @brief Is a loop valid with respect to a given region.
|
||||
///
|
||||
|
|
|
@ -300,71 +300,79 @@ bool ScopDetection::addOverApproximatedRegion(Region *AR,
|
|||
}
|
||||
|
||||
bool ScopDetection::isValidSwitch(BasicBlock &BB, SwitchInst *SI,
|
||||
Value *Condition,
|
||||
Value *Condition, bool IsLoopBranch,
|
||||
DetectionContext &Context) const {
|
||||
Region &CurRegion = Context.CurRegion;
|
||||
|
||||
Loop *L = LI->getLoopFor(&BB);
|
||||
const SCEV *ConditionSCEV = SE->getSCEVAtScope(Condition, L);
|
||||
|
||||
if (!isAffineExpr(&CurRegion, ConditionSCEV, *SE))
|
||||
if (!AllowNonAffineSubRegions ||
|
||||
!addOverApproximatedRegion(RI->getRegionFor(&BB), Context))
|
||||
return invalid<ReportNonAffBranch>(Context, /*Assert=*/true, &BB,
|
||||
ConditionSCEV, ConditionSCEV, SI);
|
||||
if (isAffineExpr(&CurRegion, ConditionSCEV, *SE))
|
||||
return true;
|
||||
|
||||
return true;
|
||||
if (!IsLoopBranch && AllowNonAffineSubRegions &&
|
||||
addOverApproximatedRegion(RI->getRegionFor(&BB), Context))
|
||||
return true;
|
||||
|
||||
if (IsLoopBranch)
|
||||
return false;
|
||||
|
||||
return invalid<ReportNonAffBranch>(Context, /*Assert=*/true, &BB,
|
||||
ConditionSCEV, ConditionSCEV, SI);
|
||||
}
|
||||
|
||||
bool ScopDetection::isValidBranch(BasicBlock &BB, BranchInst *BI,
|
||||
Value *Condition,
|
||||
Value *Condition, bool IsLoopBranch,
|
||||
DetectionContext &Context) const {
|
||||
Region &CurRegion = Context.CurRegion;
|
||||
|
||||
// Non constant conditions of branches need to be ICmpInst.
|
||||
if (!isa<ICmpInst>(Condition)) {
|
||||
if (!AllowNonAffineSubRegions ||
|
||||
!addOverApproximatedRegion(RI->getRegionFor(&BB), Context))
|
||||
return invalid<ReportInvalidCond>(Context, /*Assert=*/true, BI, &BB);
|
||||
if (!IsLoopBranch && AllowNonAffineSubRegions &&
|
||||
addOverApproximatedRegion(RI->getRegionFor(&BB), Context))
|
||||
return true;
|
||||
return invalid<ReportInvalidCond>(Context, /*Assert=*/true, BI, &BB);
|
||||
}
|
||||
|
||||
if (ICmpInst *ICmp = dyn_cast<ICmpInst>(Condition)) {
|
||||
// Unsigned comparisons are not allowed. They trigger overflow problems
|
||||
// in the code generation.
|
||||
//
|
||||
// TODO: This is not sufficient and just hides bugs. However it does pretty
|
||||
// well.
|
||||
if (ICmp->isUnsigned() && !AllowUnsigned)
|
||||
return invalid<ReportUnsignedCond>(Context, /*Assert=*/true, BI, &BB);
|
||||
ICmpInst *ICmp = cast<ICmpInst>(Condition);
|
||||
// Unsigned comparisons are not allowed. They trigger overflow problems
|
||||
// in the code generation.
|
||||
//
|
||||
// TODO: This is not sufficient and just hides bugs. However it does pretty
|
||||
// well.
|
||||
if (ICmp->isUnsigned() && !AllowUnsigned)
|
||||
return invalid<ReportUnsignedCond>(Context, /*Assert=*/true, BI, &BB);
|
||||
|
||||
// Are both operands of the ICmp affine?
|
||||
if (isa<UndefValue>(ICmp->getOperand(0)) ||
|
||||
isa<UndefValue>(ICmp->getOperand(1)))
|
||||
return invalid<ReportUndefOperand>(Context, /*Assert=*/true, &BB, ICmp);
|
||||
// Are both operands of the ICmp affine?
|
||||
if (isa<UndefValue>(ICmp->getOperand(0)) ||
|
||||
isa<UndefValue>(ICmp->getOperand(1)))
|
||||
return invalid<ReportUndefOperand>(Context, /*Assert=*/true, &BB, ICmp);
|
||||
|
||||
// TODO: FIXME: IslExprBuilder is not capable of producing valid code
|
||||
// for arbitrary pointer expressions at the moment. Until
|
||||
// this is fixed we disallow pointer expressions completely.
|
||||
if (ICmp->getOperand(0)->getType()->isPointerTy())
|
||||
return false;
|
||||
// TODO: FIXME: IslExprBuilder is not capable of producing valid code
|
||||
// for arbitrary pointer expressions at the moment. Until
|
||||
// this is fixed we disallow pointer expressions completely.
|
||||
if (ICmp->getOperand(0)->getType()->isPointerTy())
|
||||
return false;
|
||||
|
||||
Loop *L = LI->getLoopFor(ICmp->getParent());
|
||||
const SCEV *LHS = SE->getSCEVAtScope(ICmp->getOperand(0), L);
|
||||
const SCEV *RHS = SE->getSCEVAtScope(ICmp->getOperand(1), L);
|
||||
Loop *L = LI->getLoopFor(ICmp->getParent());
|
||||
const SCEV *LHS = SE->getSCEVAtScope(ICmp->getOperand(0), L);
|
||||
const SCEV *RHS = SE->getSCEVAtScope(ICmp->getOperand(1), L);
|
||||
|
||||
if (!isAffineExpr(&CurRegion, LHS, *SE) ||
|
||||
!isAffineExpr(&CurRegion, RHS, *SE)) {
|
||||
if (!AllowNonAffineSubRegions ||
|
||||
!addOverApproximatedRegion(RI->getRegionFor(&BB), Context))
|
||||
return invalid<ReportNonAffBranch>(Context, /*Assert=*/true, &BB, LHS,
|
||||
RHS, ICmp);
|
||||
}
|
||||
}
|
||||
if (isAffineExpr(&CurRegion, LHS, *SE) && isAffineExpr(&CurRegion, RHS, *SE))
|
||||
return true;
|
||||
|
||||
return true;
|
||||
if (!IsLoopBranch && AllowNonAffineSubRegions &&
|
||||
addOverApproximatedRegion(RI->getRegionFor(&BB), Context))
|
||||
return true;
|
||||
|
||||
if (IsLoopBranch)
|
||||
return false;
|
||||
|
||||
return invalid<ReportNonAffBranch>(Context, /*Assert=*/true, &BB, LHS, RHS,
|
||||
ICmp);
|
||||
}
|
||||
|
||||
bool ScopDetection::isValidCFG(BasicBlock &BB,
|
||||
bool ScopDetection::isValidCFG(BasicBlock &BB, bool IsLoopBranch,
|
||||
DetectionContext &Context) const {
|
||||
Region &CurRegion = Context.CurRegion;
|
||||
|
||||
|
@ -388,12 +396,12 @@ bool ScopDetection::isValidCFG(BasicBlock &BB,
|
|||
return true;
|
||||
|
||||
if (BranchInst *BI = dyn_cast<BranchInst>(TI))
|
||||
return isValidBranch(BB, BI, Condition, Context);
|
||||
return isValidBranch(BB, BI, Condition, IsLoopBranch, Context);
|
||||
|
||||
SwitchInst *SI = dyn_cast<SwitchInst>(TI);
|
||||
assert(SI && "Terminator was neither branch nor switch");
|
||||
|
||||
return isValidSwitch(BB, SI, Condition, Context);
|
||||
return isValidSwitch(BB, SI, Condition, IsLoopBranch, Context);
|
||||
}
|
||||
|
||||
bool ScopDetection::isValidCallInst(CallInst &CI) {
|
||||
|
@ -735,7 +743,7 @@ bool ScopDetection::canUseISLTripCount(Loop *L,
|
|||
L->getLoopLatches(LoopControlBlocks);
|
||||
L->getExitingBlocks(LoopControlBlocks);
|
||||
for (BasicBlock *ControlBB : LoopControlBlocks) {
|
||||
if (!isValidCFG(*ControlBB, Context))
|
||||
if (!isValidCFG(*ControlBB, true, Context))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -751,9 +759,11 @@ bool ScopDetection::isValidLoop(Loop *L, DetectionContext &Context) const {
|
|||
|
||||
if (AllowNonAffineSubLoops && AllowNonAffineSubRegions) {
|
||||
Region *R = RI->getRegionFor(L->getHeader());
|
||||
if (R->contains(L))
|
||||
if (addOverApproximatedRegion(R, Context))
|
||||
return true;
|
||||
while (R != &Context.CurRegion && !R->contains(L))
|
||||
R = R->getParent();
|
||||
|
||||
if (addOverApproximatedRegion(R, Context))
|
||||
return true;
|
||||
}
|
||||
|
||||
const SCEV *LoopCount = SE->getBackedgeTakenCount(L);
|
||||
|
@ -948,7 +958,7 @@ bool ScopDetection::allBlocksValid(DetectionContext &Context) const {
|
|||
if (isErrorBlock(*BB))
|
||||
continue;
|
||||
|
||||
if (!isValidCFG(*BB, Context) && !KeepGoing)
|
||||
if (!isValidCFG(*BB, false, Context) && !KeepGoing)
|
||||
return false;
|
||||
for (BasicBlock::iterator I = BB->begin(), E = --BB->end(); I != E; ++I)
|
||||
if (!isValidInstruction(*I, Context) && !KeepGoing)
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
|
||||
; RUN: opt %loadPolly -polly-allow-nonaffine-loops -polly-detect -analyze < %s | FileCheck %s --check-prefix=NALOOPS
|
||||
|
||||
; The latch conditions of the outer loop are not affine, thus the loop cannot
|
||||
; handled by the domain generation and needs to be overapproximated.
|
||||
|
||||
; CHECK-NOT: Valid
|
||||
; NALOOPS: Valid Region for Scop: for.body.6 => for.end.45
|
||||
|
||||
; ModuleID = '/home/johannes/Downloads/bug.ll'
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define void @kernel_reg_detect([6 x i32]* %path) #0 {
|
||||
entry:
|
||||
br label %for.body.6
|
||||
|
||||
for.body.6: ; preds = %for.inc.43, %for.body.6, %entry
|
||||
%indvars.iv9 = phi i64 [ %indvars.iv.next10, %for.body.6 ], [ 0, %for.inc.43 ], [ 0, %entry ]
|
||||
%indvars.iv.next10 = add nuw nsw i64 %indvars.iv9, 1
|
||||
%lftr.wideiv = trunc i64 %indvars.iv.next10 to i32
|
||||
%exitcond = icmp ne i32 %lftr.wideiv, 6
|
||||
br i1 %exitcond, label %for.body.6, label %for.inc.40
|
||||
|
||||
for.inc.40: ; preds = %for.inc.40, %for.body.6
|
||||
%arrayidx28 = getelementptr inbounds [6 x i32], [6 x i32]* %path, i64 0, i64 0
|
||||
%tmp = load i32, i32* %arrayidx28, align 4
|
||||
%arrayidx36 = getelementptr inbounds [6 x i32], [6 x i32]* %path, i64 0, i64 0
|
||||
store i32 0, i32* %arrayidx36, align 4
|
||||
%exitcond22 = icmp ne i64 0, 6
|
||||
br i1 %exitcond22, label %for.inc.40, label %for.inc.43
|
||||
|
||||
for.inc.43: ; preds = %for.inc.40
|
||||
%exitcond23 = icmp ne i32 0, 10000
|
||||
br i1 %exitcond23, label %for.body.6, label %for.end.45
|
||||
|
||||
for.end.45: ; preds = %for.inc.43
|
||||
ret void
|
||||
}
|
Loading…
Reference in New Issue