Index: llvm/lib/Analysis/ScalarEvolution.cpp =================================================================== --- llvm/lib/Analysis/ScalarEvolution.cpp +++ llvm/lib/Analysis/ScalarEvolution.cpp @@ -9009,6 +9009,18 @@ SCEV::FlagNSW); Pred = ICmpInst::ICMP_SLT; Changed = true; + } else if (const SCEVAddRecExpr *AddRec = dyn_cast(LHS)) { + const SCEV *Stride = AddRec->getStepRecurrence(*this); + // If Stride is positive, Start is not min signed value and LHS has + // FlagNSW, we can canonicalize sle to slt. + if (isKnownPositive(Stride) && + !getSignedRangeMin(AddRec->getStart()).isMinSignedValue() && + AddRec->hasNoSignedWrap()) { + LHS = getAddExpr(getConstant(RHS->getType(), (uint64_t)-1, true), LHS, + SCEV::FlagNSW); + Pred = ICmpInst::ICMP_SLT; + Changed = true; + } } break; case ICmpInst::ICMP_SGE: @@ -9034,6 +9046,18 @@ LHS = getAddExpr(getConstant(RHS->getType(), (uint64_t)-1, true), LHS); Pred = ICmpInst::ICMP_ULT; Changed = true; + } else if (const SCEVAddRecExpr *AddRec = dyn_cast(LHS)) { + const SCEV *Stride = AddRec->getStepRecurrence(*this); + // If Stride is positive, Start is not min value and LHS has FlagNUW, we + // can canonicalize ule to ult. + if (isKnownPositive(Stride) && + !getUnsignedRangeMin(AddRec->getStart()).isMinValue() && + AddRec->hasNoUnsignedWrap()) { + LHS = getAddExpr(getConstant(RHS->getType(), (uint64_t)-1, true), LHS, + SCEV::FlagNUW); + Pred = ICmpInst::ICMP_ULT; + Changed = true; + } } break; case ICmpInst::ICMP_UGE: Index: llvm/test/Analysis/ScalarEvolution/trip-count15.ll =================================================================== --- /dev/null +++ llvm/test/Analysis/ScalarEvolution/trip-count15.ll @@ -0,0 +1,112 @@ +; RUN: opt -S -analyze -scalar-evolution < %s | FileCheck %s + +; CHECK-LABEL: Determining loop execution counts for: @sle_nsw +; CHECK: Loop %for.body: backedge-taken count is ((-1 * %a) + (%a smax %b)) +; CHECK: Loop %for.body: max backedge-taken count is -1 +define void @sle_nsw(i8* %p, i32 %a, i32 %b) { +entry: + %cmp3 = icmp sle i32 %a, %b + br i1 %cmp3, label %for.body.lr.ph, label %for.end + +for.body.lr.ph: ; preds = %entry + br label %for.body + +for.body: ; preds = %for.body.lr.ph, %for.body + %i.04 = phi i32 [ %a, %for.body.lr.ph ], [ %inc, %for.body ] + %arrayidx = getelementptr inbounds i8, i8* %p, i32 %i.04 + %0 = load i8, i8* %arrayidx, align 1 + %conv = zext i8 %0 to i32 + %add = add nsw i32 %conv, 1 + %conv1 = trunc i32 %add to i8 + store i8 %conv1, i8* %arrayidx, align 1 + %inc = add nsw i32 %i.04, 1 + %cmp = icmp sle i32 %inc, %b + br i1 %cmp, label %for.body, label %for.end + +for.end: ; preds = %for.body, %entry + ret void +} + +; CHECK-LABEL: Determining loop execution counts for: @sle +; CHECK: Loop %for.body: Unpredictable backedge-taken count. +; CHECK: Loop %for.body: Unpredictable max backedge-taken count. +; CHECK: Loop %for.body: Unpredictable predicated backedge-taken count. +define void @sle(i8* %p, i32 %a, i32 %b) { +entry: + %cmp3 = icmp sle i32 %a, %b + br i1 %cmp3, label %for.body.lr.ph, label %for.end + +for.body.lr.ph: ; preds = %entry + br label %for.body + +for.body: ; preds = %for.body.lr.ph, %for.body + %i.04 = phi i32 [ %a, %for.body.lr.ph ], [ %inc, %for.body ] + %arrayidx = getelementptr inbounds i8, i8* %p, i32 %i.04 + %0 = load i8, i8* %arrayidx, align 1 + %conv = zext i8 %0 to i32 + %add = add nsw i32 %conv, 1 + %conv1 = trunc i32 %add to i8 + store i8 %conv1, i8* %arrayidx, align 1 + %inc = add i32 %i.04, 1 + %cmp = icmp sle i32 %inc, %b + br i1 %cmp, label %for.body, label %for.end + +for.end: ; preds = %for.body, %entry + ret void +} + +; CHECK-LABEL: Determining loop execution counts for: @ule_nuw +; CHECK: Loop %for.body: backedge-taken count is ((-1 * %a) + (%a umax %b)) +; CHECK: Loop %for.body: max backedge-taken count is -1 +; CHECK: Loop %for.body: Predicated backedge-taken count is ((-1 * %a) + (%a umax %b)) +define void @ule_nuw(i8* %p, i32 zeroext %a, i32 zeroext %b) { +entry: + %cmp3 = icmp ule i32 %a, %b + br i1 %cmp3, label %for.body.lr.ph, label %for.end + +for.body.lr.ph: ; preds = %entry + br label %for.body + +for.body: ; preds = %for.body.lr.ph, %for.body + %i.04 = phi i32 [ %a, %for.body.lr.ph ], [ %inc, %for.body ] + %arrayidx = getelementptr inbounds i8, i8* %p, i32 %i.04 + %0 = load i8, i8* %arrayidx, align 1 + %conv = zext i8 %0 to i32 + %add = add nsw i32 %conv, 1 + %conv1 = trunc i32 %add to i8 + store i8 %conv1, i8* %arrayidx, align 1 + %inc = add nuw i32 %i.04, 1 + %cmp = icmp ule i32 %inc, %b + br i1 %cmp, label %for.body, label %for.end + +for.end: ; preds = %for.body, %entry + ret void +} + +; CHECK-LABEL: Determining loop execution counts for: @ule +; CHECK: Loop %for.body: Unpredictable backedge-taken count. +; CHECK: Loop %for.body: Unpredictable max backedge-taken count. +; CHECK: Loop %for.body: Unpredictable predicated backedge-taken count. +define void @ule(i8* %p, i32 zeroext %a, i32 zeroext %b) { +entry: + %cmp3 = icmp ule i32 %a, %b + br i1 %cmp3, label %for.body.lr.ph, label %for.end + +for.body.lr.ph: ; preds = %entry + br label %for.body + +for.body: ; preds = %for.body.lr.ph, %for.body + %i.04 = phi i32 [ %a, %for.body.lr.ph ], [ %inc, %for.body ] + %arrayidx = getelementptr inbounds i8, i8* %p, i32 %i.04 + %0 = load i8, i8* %arrayidx, align 1 + %conv = zext i8 %0 to i32 + %add = add nsw i32 %conv, 1 + %conv1 = trunc i32 %add to i8 + store i8 %conv1, i8* %arrayidx, align 1 + %inc = add i32 %i.04, 1 + %cmp = icmp ule i32 %inc, %b + br i1 %cmp, label %for.body, label %for.end + +for.end: ; preds = %for.body, %entry + ret void +} Index: llvm/test/CodeGen/PowerPC/ctrloop-le.ll =================================================================== --- llvm/test/CodeGen/PowerPC/ctrloop-le.ll +++ llvm/test/CodeGen/PowerPC/ctrloop-le.ll @@ -293,8 +293,7 @@ ; CHECK: test_pos1_rr_sle -; FIXME: Support this loop! -; CHECK-NOT: bdnz +; CHECK: bdnz ; a < b define void @test_pos1_rr_sle(i8* nocapture %p, i32 %a, i32 %b) nounwind { entry: @@ -323,8 +322,7 @@ ; CHECK: test_pos2_rr_sle -; FIXME: Support this loop! -; CHECK-NOT: bdnz +; CHECK: bdnz ; a < b define void @test_pos2_rr_sle(i8* nocapture %p, i32 %a, i32 %b) nounwind { entry: @@ -353,8 +351,7 @@ ; CHECK: test_pos4_rr_sle -; FIXME: Support this loop! -; CHECK-NOT: bdnz +; CHECK: bdnz ; a < b define void @test_pos4_rr_sle(i8* nocapture %p, i32 %a, i32 %b) nounwind { entry: @@ -383,8 +380,7 @@ ; CHECK: test_pos8_rr_sle -; FIXME: Support this loop! -; CHECK-NOT: bdnz +; CHECK: bdnz ; a < b define void @test_pos8_rr_sle(i8* nocapture %p, i32 %a, i32 %b) nounwind { entry: @@ -413,8 +409,7 @@ ; CHECK: test_pos16_rr_sle -; FIXME: Support this loop! -; CHECK-NOT: bdnz +; CHECK: bdnz ; a < b define void @test_pos16_rr_sle(i8* nocapture %p, i32 %a, i32 %b) nounwind { entry: