mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-18 12:16:49 +00:00
[LoopPeel] Support min/max intrinsics in loop peeling (#93162)
This patch adds processing of min/max intrinsics in LoopPeel in the similar way as it was done for conditional statements: for min/max(IterVal, BoundVal) we peel iterations where IterVal < BoundVal for monotonically increasing IterVal; for monotonically decreasing IterVal we peel iterations where IterVal > BoundVal (strict comparision predicates are used to minimize number of peeled iterations).
This commit is contained in:
parent
46b3145b7c
commit
f34dedbf44
@ -351,6 +351,21 @@ static unsigned countToEliminateCompares(Loop &L, unsigned MaxPeelCount,
|
||||
MaxPeelCount =
|
||||
std::min((unsigned)SC->getAPInt().getLimitedValue() - 1, MaxPeelCount);
|
||||
|
||||
// Increase PeelCount while (IterVal Pred BoundSCEV) condition is satisfied;
|
||||
// return true if inversed condition become known before reaching the
|
||||
// MaxPeelCount limit.
|
||||
auto PeelWhilePredicateIsKnown =
|
||||
[&](unsigned &PeelCount, const SCEV *&IterVal, const SCEV *BoundSCEV,
|
||||
const SCEV *Step, ICmpInst::Predicate Pred) {
|
||||
while (PeelCount < MaxPeelCount &&
|
||||
SE.isKnownPredicate(Pred, IterVal, BoundSCEV)) {
|
||||
IterVal = SE.getAddExpr(IterVal, Step);
|
||||
++PeelCount;
|
||||
}
|
||||
return SE.isKnownPredicate(ICmpInst::getInversePredicate(Pred), IterVal,
|
||||
BoundSCEV);
|
||||
};
|
||||
|
||||
const unsigned MaxDepth = 4;
|
||||
std::function<void(Value *, unsigned)> ComputePeelCount =
|
||||
[&](Value *Condition, unsigned Depth) -> void {
|
||||
@ -411,48 +426,73 @@ static unsigned countToEliminateCompares(Loop &L, unsigned MaxPeelCount,
|
||||
Pred = ICmpInst::getInversePredicate(Pred);
|
||||
|
||||
const SCEV *Step = LeftAR->getStepRecurrence(SE);
|
||||
const SCEV *NextIterVal = SE.getAddExpr(IterVal, Step);
|
||||
auto PeelOneMoreIteration = [&IterVal, &NextIterVal, &SE, Step,
|
||||
&NewPeelCount]() {
|
||||
IterVal = NextIterVal;
|
||||
NextIterVal = SE.getAddExpr(IterVal, Step);
|
||||
NewPeelCount++;
|
||||
};
|
||||
|
||||
auto CanPeelOneMoreIteration = [&NewPeelCount, &MaxPeelCount]() {
|
||||
return NewPeelCount < MaxPeelCount;
|
||||
};
|
||||
|
||||
while (CanPeelOneMoreIteration() &&
|
||||
SE.isKnownPredicate(Pred, IterVal, RightSCEV))
|
||||
PeelOneMoreIteration();
|
||||
|
||||
// With *that* peel count, does the predicate !Pred become known in the
|
||||
// first iteration of the loop body after peeling?
|
||||
if (!SE.isKnownPredicate(ICmpInst::getInversePredicate(Pred), IterVal,
|
||||
RightSCEV))
|
||||
return; // If not, give up.
|
||||
if (!PeelWhilePredicateIsKnown(NewPeelCount, IterVal, RightSCEV, Step,
|
||||
Pred))
|
||||
return;
|
||||
|
||||
// However, for equality comparisons, that isn't always sufficient to
|
||||
// eliminate the comparsion in loop body, we may need to peel one more
|
||||
// iteration. See if that makes !Pred become unknown again.
|
||||
const SCEV *NextIterVal = SE.getAddExpr(IterVal, Step);
|
||||
if (ICmpInst::isEquality(Pred) &&
|
||||
!SE.isKnownPredicate(ICmpInst::getInversePredicate(Pred), NextIterVal,
|
||||
RightSCEV) &&
|
||||
!SE.isKnownPredicate(Pred, IterVal, RightSCEV) &&
|
||||
SE.isKnownPredicate(Pred, NextIterVal, RightSCEV)) {
|
||||
if (!CanPeelOneMoreIteration())
|
||||
if (NewPeelCount >= MaxPeelCount)
|
||||
return; // Need to peel one more iteration, but can't. Give up.
|
||||
PeelOneMoreIteration(); // Great!
|
||||
++NewPeelCount; // Great!
|
||||
}
|
||||
|
||||
DesiredPeelCount = std::max(DesiredPeelCount, NewPeelCount);
|
||||
};
|
||||
|
||||
auto ComputePeelCountMinMax = [&](MinMaxIntrinsic *MinMax) {
|
||||
if (!MinMax->getType()->isIntegerTy())
|
||||
return;
|
||||
Value *LHS = MinMax->getLHS(), *RHS = MinMax->getRHS();
|
||||
const SCEV *BoundSCEV, *IterSCEV;
|
||||
if (L.isLoopInvariant(LHS)) {
|
||||
BoundSCEV = SE.getSCEV(LHS);
|
||||
IterSCEV = SE.getSCEV(RHS);
|
||||
} else if (L.isLoopInvariant(RHS)) {
|
||||
BoundSCEV = SE.getSCEV(RHS);
|
||||
IterSCEV = SE.getSCEV(LHS);
|
||||
} else
|
||||
return;
|
||||
const auto *AddRec = dyn_cast<SCEVAddRecExpr>(IterSCEV);
|
||||
// For simplicity, we support only affine recurrences.
|
||||
if (!AddRec || !AddRec->isAffine() || AddRec->getLoop() != &L)
|
||||
return;
|
||||
const SCEV *Step = AddRec->getStepRecurrence(SE);
|
||||
bool IsSigned = MinMax->isSigned();
|
||||
// To minimize number of peeled iterations, we use strict relational
|
||||
// predicates here.
|
||||
ICmpInst::Predicate Pred;
|
||||
if (SE.isKnownPositive(Step))
|
||||
Pred = IsSigned ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT;
|
||||
else if (SE.isKnownNegative(Step))
|
||||
Pred = IsSigned ? ICmpInst::ICMP_SGT : ICmpInst::ICMP_UGT;
|
||||
else
|
||||
return;
|
||||
// Check that AddRec is not wrapping.
|
||||
if (!(IsSigned ? AddRec->hasNoSignedWrap() : AddRec->hasNoUnsignedWrap()))
|
||||
return;
|
||||
unsigned NewPeelCount = DesiredPeelCount;
|
||||
const SCEV *IterVal = AddRec->evaluateAtIteration(
|
||||
SE.getConstant(AddRec->getType(), NewPeelCount), SE);
|
||||
if (!PeelWhilePredicateIsKnown(NewPeelCount, IterVal, BoundSCEV, Step,
|
||||
Pred))
|
||||
return;
|
||||
DesiredPeelCount = NewPeelCount;
|
||||
};
|
||||
|
||||
for (BasicBlock *BB : L.blocks()) {
|
||||
for (Instruction &I : *BB) {
|
||||
if (SelectInst *SI = dyn_cast<SelectInst>(&I))
|
||||
ComputePeelCount(SI->getCondition(), 0);
|
||||
if (MinMaxIntrinsic *MinMax = dyn_cast<MinMaxIntrinsic>(&I))
|
||||
ComputePeelCountMinMax(MinMax);
|
||||
}
|
||||
|
||||
auto *BI = dyn_cast<BranchInst>(BB->getTerminator());
|
||||
|
@ -11,14 +11,37 @@ define void @test_umin(i32 %N) {
|
||||
; CHECK-NEXT: [[CMP5_NOT:%.*]] = icmp eq i32 [[N]], 0
|
||||
; CHECK-NEXT: br i1 [[CMP5_NOT]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY_PREHEADER:%.*]]
|
||||
; CHECK: for.body.preheader:
|
||||
; CHECK-NEXT: br label [[FOR_BODY_PEEL2:%.*]]
|
||||
; CHECK: for.body.peel.begin:
|
||||
; CHECK-NEXT: br label [[FOR_BODY_PEEL:%.*]]
|
||||
; CHECK: for.body.peel:
|
||||
; CHECK-NEXT: [[COND_PEEL:%.*]] = tail call i32 @llvm.umin.i32(i32 0, i32 2)
|
||||
; CHECK-NEXT: tail call void @foo(i32 [[COND_PEEL]])
|
||||
; CHECK-NEXT: [[INC_PEEL:%.*]] = add nuw i32 0, 1
|
||||
; CHECK-NEXT: [[EXITCOND_NOT_PEEL:%.*]] = icmp eq i32 [[INC_PEEL]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[EXITCOND_NOT_PEEL]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]], label [[FOR_BODY_PEEL_NEXT:%.*]]
|
||||
; CHECK: for.body.peel.next:
|
||||
; CHECK-NEXT: br label [[FOR_BODY_PEEL3:%.*]]
|
||||
; CHECK: for.body.peel2:
|
||||
; CHECK-NEXT: [[COND_PEEL3:%.*]] = tail call i32 @llvm.umin.i32(i32 [[INC_PEEL]], i32 2)
|
||||
; CHECK-NEXT: tail call void @foo(i32 [[COND_PEEL3]])
|
||||
; CHECK-NEXT: [[INC_PEEL4:%.*]] = add nuw i32 [[INC_PEEL]], 1
|
||||
; CHECK-NEXT: [[EXITCOND_NOT_PEEL5:%.*]] = icmp eq i32 [[INC_PEEL4]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[EXITCOND_NOT_PEEL5]], label [[FOR_COND_CLEANUP_LOOPEXIT]], label [[FOR_BODY_PEEL_NEXT1:%.*]]
|
||||
; CHECK: for.body.peel.next1:
|
||||
; CHECK-NEXT: br label [[FOR_BODY_PEEL_NEXT6:%.*]]
|
||||
; CHECK: for.body.peel.next6:
|
||||
; CHECK-NEXT: br label [[FOR_BODY_PREHEADER_PEEL_NEWPH:%.*]]
|
||||
; CHECK: for.body.preheader.peel.newph:
|
||||
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
||||
; CHECK: for.body:
|
||||
; CHECK-NEXT: [[I_06:%.*]] = phi i32 [ [[INC:%.*]], [[FOR_BODY]] ], [ 0, [[FOR_BODY_PREHEADER]] ]
|
||||
; CHECK-NEXT: [[COND:%.*]] = tail call i32 @llvm.umin.i32(i32 [[I_06]], i32 2)
|
||||
; CHECK-NEXT: tail call void @foo(i32 [[COND]])
|
||||
; CHECK-NEXT: [[I_06:%.*]] = phi i32 [ [[INC:%.*]], [[FOR_BODY]] ], [ [[INC_PEEL4]], [[FOR_BODY_PREHEADER_PEEL_NEWPH]] ]
|
||||
; CHECK-NEXT: tail call void @foo(i32 2)
|
||||
; CHECK-NEXT: [[INC]] = add nuw i32 [[I_06]], 1
|
||||
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[INC]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]], label [[FOR_BODY]]
|
||||
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_COND_CLEANUP_LOOPEXIT_LOOPEXIT:%.*]], label [[FOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]]
|
||||
; CHECK: for.cond.cleanup.loopexit.loopexit:
|
||||
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_LOOPEXIT]]
|
||||
; CHECK: for.cond.cleanup.loopexit:
|
||||
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
|
||||
; CHECK: for.cond.cleanup:
|
||||
@ -47,14 +70,37 @@ define void @test_umax(i32 %N) {
|
||||
; CHECK-NEXT: [[CMP5_NOT:%.*]] = icmp eq i32 [[N]], 0
|
||||
; CHECK-NEXT: br i1 [[CMP5_NOT]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY_PREHEADER:%.*]]
|
||||
; CHECK: for.body.preheader:
|
||||
; CHECK-NEXT: br label [[FOR_BODY_PEEL2:%.*]]
|
||||
; CHECK: for.body.peel.begin:
|
||||
; CHECK-NEXT: br label [[FOR_BODY_PEEL:%.*]]
|
||||
; CHECK: for.body.peel:
|
||||
; CHECK-NEXT: [[COND_PEEL:%.*]] = tail call i32 @llvm.umax.i32(i32 0, i32 2)
|
||||
; CHECK-NEXT: tail call void @foo(i32 [[COND_PEEL]])
|
||||
; CHECK-NEXT: [[INC_PEEL:%.*]] = add nuw i32 0, 1
|
||||
; CHECK-NEXT: [[EXITCOND_NOT_PEEL:%.*]] = icmp eq i32 [[INC_PEEL]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[EXITCOND_NOT_PEEL]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]], label [[FOR_BODY_PEEL_NEXT:%.*]]
|
||||
; CHECK: for.body.peel.next:
|
||||
; CHECK-NEXT: br label [[FOR_BODY_PEEL3:%.*]]
|
||||
; CHECK: for.body.peel2:
|
||||
; CHECK-NEXT: [[COND_PEEL3:%.*]] = tail call i32 @llvm.umax.i32(i32 [[INC_PEEL]], i32 2)
|
||||
; CHECK-NEXT: tail call void @foo(i32 [[COND_PEEL3]])
|
||||
; CHECK-NEXT: [[INC_PEEL4:%.*]] = add nuw i32 [[INC_PEEL]], 1
|
||||
; CHECK-NEXT: [[EXITCOND_NOT_PEEL5:%.*]] = icmp eq i32 [[INC_PEEL4]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[EXITCOND_NOT_PEEL5]], label [[FOR_COND_CLEANUP_LOOPEXIT]], label [[FOR_BODY_PEEL_NEXT1:%.*]]
|
||||
; CHECK: for.body.peel.next1:
|
||||
; CHECK-NEXT: br label [[FOR_BODY_PEEL_NEXT6:%.*]]
|
||||
; CHECK: for.body.peel.next6:
|
||||
; CHECK-NEXT: br label [[FOR_BODY_PREHEADER_PEEL_NEWPH:%.*]]
|
||||
; CHECK: for.body.preheader.peel.newph:
|
||||
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
||||
; CHECK: for.body:
|
||||
; CHECK-NEXT: [[I_06:%.*]] = phi i32 [ [[INC:%.*]], [[FOR_BODY]] ], [ 0, [[FOR_BODY_PREHEADER]] ]
|
||||
; CHECK-NEXT: [[COND:%.*]] = tail call i32 @llvm.umax.i32(i32 [[I_06]], i32 2)
|
||||
; CHECK-NEXT: tail call void @foo(i32 [[COND]])
|
||||
; CHECK-NEXT: [[I_06:%.*]] = phi i32 [ [[INC:%.*]], [[FOR_BODY]] ], [ [[INC_PEEL4]], [[FOR_BODY_PREHEADER_PEEL_NEWPH]] ]
|
||||
; CHECK-NEXT: tail call void @foo(i32 [[I_06]])
|
||||
; CHECK-NEXT: [[INC]] = add nuw i32 [[I_06]], 1
|
||||
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[INC]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]], label [[FOR_BODY]]
|
||||
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_COND_CLEANUP_LOOPEXIT_LOOPEXIT:%.*]], label [[FOR_BODY]], !llvm.loop [[LOOP2:![0-9]+]]
|
||||
; CHECK: for.cond.cleanup.loopexit.loopexit:
|
||||
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_LOOPEXIT]]
|
||||
; CHECK: for.cond.cleanup.loopexit:
|
||||
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
|
||||
; CHECK: for.cond.cleanup:
|
||||
@ -83,14 +129,37 @@ define void @test_smax(i32 %N) {
|
||||
; CHECK-NEXT: [[CMP5:%.*]] = icmp slt i32 [[N]], 0
|
||||
; CHECK-NEXT: br i1 [[CMP5]], label [[FOR_BODY_PREHEADER:%.*]], label [[FOR_COND_CLEANUP:%.*]]
|
||||
; CHECK: for.body.preheader:
|
||||
; CHECK-NEXT: br label [[FOR_BODY_PEEL2:%.*]]
|
||||
; CHECK: for.body.peel.begin:
|
||||
; CHECK-NEXT: br label [[FOR_BODY_PEEL:%.*]]
|
||||
; CHECK: for.body.peel:
|
||||
; CHECK-NEXT: [[COND_PEEL:%.*]] = tail call i32 @llvm.smax.i32(i32 0, i32 -2)
|
||||
; CHECK-NEXT: tail call void @foo(i32 [[COND_PEEL]])
|
||||
; CHECK-NEXT: [[DEC_PEEL:%.*]] = add nsw i32 0, -1
|
||||
; CHECK-NEXT: [[CMP_PEEL:%.*]] = icmp sgt i32 [[DEC_PEEL]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[CMP_PEEL]], label [[FOR_BODY_PEEL_NEXT:%.*]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]]
|
||||
; CHECK: for.body.peel.next:
|
||||
; CHECK-NEXT: br label [[FOR_BODY_PEEL3:%.*]]
|
||||
; CHECK: for.body.peel2:
|
||||
; CHECK-NEXT: [[COND_PEEL3:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DEC_PEEL]], i32 -2)
|
||||
; CHECK-NEXT: tail call void @foo(i32 [[COND_PEEL3]])
|
||||
; CHECK-NEXT: [[DEC_PEEL4:%.*]] = add nsw i32 [[DEC_PEEL]], -1
|
||||
; CHECK-NEXT: [[CMP_PEEL5:%.*]] = icmp sgt i32 [[DEC_PEEL4]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[CMP_PEEL5]], label [[FOR_BODY_PEEL_NEXT1:%.*]], label [[FOR_COND_CLEANUP_LOOPEXIT]]
|
||||
; CHECK: for.body.peel.next1:
|
||||
; CHECK-NEXT: br label [[FOR_BODY_PEEL_NEXT6:%.*]]
|
||||
; CHECK: for.body.peel.next6:
|
||||
; CHECK-NEXT: br label [[FOR_BODY_PREHEADER_PEEL_NEWPH:%.*]]
|
||||
; CHECK: for.body.preheader.peel.newph:
|
||||
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
||||
; CHECK: for.body:
|
||||
; CHECK-NEXT: [[I_06:%.*]] = phi i32 [ [[DEC:%.*]], [[FOR_BODY]] ], [ 0, [[FOR_BODY_PREHEADER]] ]
|
||||
; CHECK-NEXT: [[COND:%.*]] = tail call i32 @llvm.smax.i32(i32 [[I_06]], i32 -2)
|
||||
; CHECK-NEXT: tail call void @foo(i32 [[COND]])
|
||||
; CHECK-NEXT: [[I_06:%.*]] = phi i32 [ [[DEC:%.*]], [[FOR_BODY]] ], [ [[DEC_PEEL4]], [[FOR_BODY_PREHEADER_PEEL_NEWPH]] ]
|
||||
; CHECK-NEXT: tail call void @foo(i32 -2)
|
||||
; CHECK-NEXT: [[DEC]] = add nsw i32 [[I_06]], -1
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[DEC]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]]
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP_LOOPEXIT_LOOPEXIT:%.*]], !llvm.loop [[LOOP3:![0-9]+]]
|
||||
; CHECK: for.cond.cleanup.loopexit.loopexit:
|
||||
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_LOOPEXIT]]
|
||||
; CHECK: for.cond.cleanup.loopexit:
|
||||
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
|
||||
; CHECK: for.cond.cleanup:
|
||||
@ -119,14 +188,37 @@ define void @test_smin(i32 %N) {
|
||||
; CHECK-NEXT: [[CMP5:%.*]] = icmp slt i32 [[N]], 0
|
||||
; CHECK-NEXT: br i1 [[CMP5]], label [[FOR_BODY_PREHEADER:%.*]], label [[FOR_COND_CLEANUP:%.*]]
|
||||
; CHECK: for.body.preheader:
|
||||
; CHECK-NEXT: br label [[FOR_BODY_PEEL2:%.*]]
|
||||
; CHECK: for.body.peel.begin:
|
||||
; CHECK-NEXT: br label [[FOR_BODY_PEEL:%.*]]
|
||||
; CHECK: for.body.peel:
|
||||
; CHECK-NEXT: [[COND_PEEL:%.*]] = tail call i32 @llvm.smin.i32(i32 0, i32 -2)
|
||||
; CHECK-NEXT: tail call void @foo(i32 noundef signext [[COND_PEEL]])
|
||||
; CHECK-NEXT: [[DEC_PEEL:%.*]] = add nsw i32 0, -1
|
||||
; CHECK-NEXT: [[CMP_PEEL:%.*]] = icmp sgt i32 [[DEC_PEEL]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[CMP_PEEL]], label [[FOR_BODY_PEEL_NEXT:%.*]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]]
|
||||
; CHECK: for.body.peel.next:
|
||||
; CHECK-NEXT: br label [[FOR_BODY_PEEL3:%.*]]
|
||||
; CHECK: for.body.peel2:
|
||||
; CHECK-NEXT: [[COND_PEEL3:%.*]] = tail call i32 @llvm.smin.i32(i32 [[DEC_PEEL]], i32 -2)
|
||||
; CHECK-NEXT: tail call void @foo(i32 noundef signext [[COND_PEEL3]])
|
||||
; CHECK-NEXT: [[DEC_PEEL4:%.*]] = add nsw i32 [[DEC_PEEL]], -1
|
||||
; CHECK-NEXT: [[CMP_PEEL5:%.*]] = icmp sgt i32 [[DEC_PEEL4]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[CMP_PEEL5]], label [[FOR_BODY_PEEL_NEXT1:%.*]], label [[FOR_COND_CLEANUP_LOOPEXIT]]
|
||||
; CHECK: for.body.peel.next1:
|
||||
; CHECK-NEXT: br label [[FOR_BODY_PEEL_NEXT6:%.*]]
|
||||
; CHECK: for.body.peel.next6:
|
||||
; CHECK-NEXT: br label [[FOR_BODY_PREHEADER_PEEL_NEWPH:%.*]]
|
||||
; CHECK: for.body.preheader.peel.newph:
|
||||
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
||||
; CHECK: for.body:
|
||||
; CHECK-NEXT: [[I_06:%.*]] = phi i32 [ [[DEC:%.*]], [[FOR_BODY]] ], [ 0, [[FOR_BODY_PREHEADER]] ]
|
||||
; CHECK-NEXT: [[COND:%.*]] = tail call i32 @llvm.smin.i32(i32 [[I_06]], i32 -2)
|
||||
; CHECK-NEXT: tail call void @foo(i32 noundef signext [[COND]])
|
||||
; CHECK-NEXT: [[I_06:%.*]] = phi i32 [ [[DEC:%.*]], [[FOR_BODY]] ], [ [[DEC_PEEL4]], [[FOR_BODY_PREHEADER_PEEL_NEWPH]] ]
|
||||
; CHECK-NEXT: tail call void @foo(i32 noundef signext [[I_06]])
|
||||
; CHECK-NEXT: [[DEC]] = add nsw i32 [[I_06]], -1
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[DEC]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]]
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP_LOOPEXIT_LOOPEXIT:%.*]], !llvm.loop [[LOOP4:![0-9]+]]
|
||||
; CHECK: for.cond.cleanup.loopexit.loopexit:
|
||||
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_LOOPEXIT]]
|
||||
; CHECK: for.cond.cleanup.loopexit:
|
||||
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
|
||||
; CHECK: for.cond.cleanup:
|
||||
@ -191,14 +283,14 @@ define void @test_max_count_threshold(i32 %N) {
|
||||
; CHECK-NEXT: [[CMP5_NOT:%.*]] = icmp eq i32 [[N]], 0
|
||||
; CHECK-NEXT: br i1 [[CMP5_NOT]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY_PREHEADER:%.*]]
|
||||
; CHECK: for.body.preheader:
|
||||
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
||||
; CHECK-NEXT: br label [[FOR_BODY1:%.*]]
|
||||
; CHECK: for.body:
|
||||
; CHECK-NEXT: [[I_06:%.*]] = phi i32 [ [[INC:%.*]], [[FOR_BODY]] ], [ 0, [[FOR_BODY_PREHEADER]] ]
|
||||
; CHECK-NEXT: [[COND:%.*]] = tail call i32 @llvm.umin.i32(i32 [[I_06]], i32 5)
|
||||
; CHECK-NEXT: tail call void @foo(i32 [[COND]])
|
||||
; CHECK-NEXT: [[INC]] = add nuw i32 [[I_06]], 1
|
||||
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[INC]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]], label [[FOR_BODY]]
|
||||
; CHECK-NEXT: [[I_6:%.*]] = phi i32 [ [[INC1:%.*]], [[FOR_BODY1]] ], [ 0, [[FOR_BODY_PREHEADER]] ]
|
||||
; CHECK-NEXT: [[COND1:%.*]] = tail call i32 @llvm.umin.i32(i32 [[I_6]], i32 5)
|
||||
; CHECK-NEXT: tail call void @foo(i32 [[COND1]])
|
||||
; CHECK-NEXT: [[INC1]] = add nuw i32 [[I_6]], 1
|
||||
; CHECK-NEXT: [[EXITCOND_NOT1:%.*]] = icmp eq i32 [[INC1]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[EXITCOND_NOT1]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]], label [[FOR_BODY1]]
|
||||
; CHECK: for.cond.cleanup.loopexit:
|
||||
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
|
||||
; CHECK: for.cond.cleanup:
|
||||
@ -227,14 +319,14 @@ define void @test_wrap(i8 %N) {
|
||||
; CHECK-NEXT: [[CMP5_NOT:%.*]] = icmp eq i8 [[N]], 0
|
||||
; CHECK-NEXT: br i1 [[CMP5_NOT]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY_PREHEADER:%.*]]
|
||||
; CHECK: for.body.preheader:
|
||||
; CHECK-NEXT: br label [[FOR_BODY1:%.*]]
|
||||
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
||||
; CHECK: for.body:
|
||||
; CHECK-NEXT: [[I_06:%.*]] = phi i8 [ [[INC1:%.*]], [[FOR_BODY1]] ], [ 0, [[FOR_BODY_PREHEADER]] ]
|
||||
; CHECK-NEXT: [[COND1:%.*]] = tail call i8 @llvm.umin.i8(i8 [[I_06]], i8 -2)
|
||||
; CHECK-NEXT: tail call void @bar(i8 [[COND1]])
|
||||
; CHECK-NEXT: [[INC1]] = add i8 [[I_06]], 127
|
||||
; CHECK-NEXT: [[EXITCOND_NOT1:%.*]] = icmp eq i8 [[INC1]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[EXITCOND_NOT1]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]], label [[FOR_BODY1]]
|
||||
; CHECK-NEXT: [[I_06:%.*]] = phi i8 [ [[INC:%.*]], [[FOR_BODY]] ], [ 0, [[FOR_BODY_PREHEADER]] ]
|
||||
; CHECK-NEXT: [[COND:%.*]] = tail call i8 @llvm.umin.i8(i8 [[I_06]], i8 -2)
|
||||
; CHECK-NEXT: tail call void @bar(i8 [[COND]])
|
||||
; CHECK-NEXT: [[INC]] = add i8 [[I_06]], 127
|
||||
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i8 [[INC]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]], label [[FOR_BODY]]
|
||||
; CHECK: for.cond.cleanup.loopexit:
|
||||
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
|
||||
; CHECK: for.cond.cleanup:
|
||||
@ -255,3 +347,10 @@ for.body:
|
||||
for.cond.cleanup:
|
||||
ret void
|
||||
}
|
||||
;.
|
||||
; CHECK: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]]}
|
||||
; CHECK: [[META1]] = !{!"llvm.loop.peeled.count", i32 2}
|
||||
; CHECK: [[LOOP2]] = distinct !{[[LOOP2]], [[META1]]}
|
||||
; CHECK: [[LOOP3]] = distinct !{[[LOOP3]], [[META1]]}
|
||||
; CHECK: [[LOOP4]] = distinct !{[[LOOP4]], [[META1]]}
|
||||
;.
|
||||
|
Loading…
x
Reference in New Issue
Block a user