[llvm] [VPlan] Wrap SCEVAddRecExprs in VPExpandSCEVRecipe in VPSCEVExpander. (PR #210013)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 16 02:10:52 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Florian Hahn (fhahn)
<details>
<summary>Changes</summary>
Handle remaining missing case in VPSCEVExpander: SCEVAddRecExpr.
Currently all AddRecs must be outside the scope of VPlan, and may need
to be expanded in an unrelated loop.
This cannot be done with VPInstructions; wrap them in a
VPExpandSCEVRecipe in the entry block. Also assert that the header of
the AddRec's loop dominates VPlan's entry.
---
Full diff: https://github.com/llvm/llvm-project/pull/210013.diff
9 Files Affected:
- (modified) llvm/lib/Transforms/Vectorize/VPlanConstruction.cpp (+1-5)
- (modified) llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp (+3-9)
- (modified) llvm/lib/Transforms/Vectorize/VPlanTransforms.h (+2-3)
- (modified) llvm/lib/Transforms/Vectorize/VPlanUtils.cpp (+57-39)
- (modified) llvm/lib/Transforms/Vectorize/VPlanUtils.h (+8-5)
- (modified) llvm/test/Transforms/LoopVectorize/VPlan/expand-scev.ll (+3-4)
- (modified) llvm/test/Transforms/LoopVectorize/pr55100-expand-scev-predicate-used.ll (+2-2)
- (modified) llvm/test/Transforms/LoopVectorize/reuse-lcssa-phi-scev-expansion.ll (+4-4)
- (modified) llvm/test/Transforms/LoopVectorize/trip-count-expansion-may-introduce-ub.ll (+1-1)
``````````diff
diff --git a/llvm/lib/Transforms/Vectorize/VPlanConstruction.cpp b/llvm/lib/Transforms/Vectorize/VPlanConstruction.cpp
index 1a135b8549514..8b7584b7c7652 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanConstruction.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanConstruction.cpp
@@ -1545,12 +1545,8 @@ void VPlanTransforms::addMinimumIterationCheck(
TripCount, Step)) {
// Generate the minimum iteration check only if we cannot prove the
// check is known to be true, or known to be false.
- // Try to expand Step into VPInstructions in CheckBlock; otherwise fall
- // back to a VPExpandSCEV recipe in the plan's entry block.
VPValue *MinTripCountVPV =
- VPSCEVExpander(Builder, *PSE.getSE(), DL).tryToExpand(Step);
- if (!MinTripCountVPV)
- MinTripCountVPV = VPBuilder(Plan.getEntry()).createExpandSCEV(Step);
+ VPSCEVExpander(Builder, *PSE.getSE(), DL).expand(Step);
TripCountCheck = Builder.createICmp(
CmpPred, TripCountVPV, MinTripCountVPV, DL, "min.iters.check");
} // else step known to be < trip count, use TripCountCheck preset to false.
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index e447fa2491d58..2b86fade36578 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -5801,17 +5801,13 @@ void VPlanTransforms::expandSCEVsToVPInstructions(VPlan &Plan,
->getDebugLoc();
VPSCEVExpander Expander(Builder, SE, DL);
- // Expand VPExpandSCEVRecipes to VPInstructions using VPSCEVExpander. During
- // the transition, unsupported VPExpandSCEVRecipes are skipped and left for
- // late expansion.
+ // Expand VPExpandSCEVRecipes to VPInstructions using VPSCEVExpander.
for (VPRecipeBase &R : make_early_inc_range(*Entry)) {
auto *ExpSCEV = dyn_cast<VPExpandSCEVRecipe>(&R);
if (!ExpSCEV || ExpSCEV->user_empty())
continue;
Builder.setInsertPoint(ExpSCEV);
- VPValue *Expanded = Expander.tryToExpand(ExpSCEV->getSCEV());
- if (!Expanded)
- continue;
+ VPValue *Expanded = Expander.expand(ExpSCEV->getSCEV());
ExpSCEV->replaceAllUsesWith(Expanded);
// TripCount should not be used after expansion to VPInstructions. Reset to
// poison to avoid dangling references.
@@ -7770,9 +7766,7 @@ void VPlanTransforms::convertToStridedAccesses(VPlan &Plan,
// supports a general VPValue as the start value.
VPValue *StartVPV =
VPSCEVExpander(Builder, *PSE.getSE(), LoadR->getDebugLoc())
- .tryToExpand(Start);
- if (!StartVPV)
- StartVPV = VPBuilder(Plan.getEntry()).createExpandSCEV(Start);
+ .expand(Start);
VPValue *StrideInBytes = Plan.getOrAddLiveIn(Step->getValue());
Type *IndexTy = Plan.getDataLayout().getIndexType(Ptr->getScalarType());
assert(IndexTy == StrideInBytes->getScalarType() &&
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
index 85375625d34b5..fa2b3438ea724 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
@@ -480,9 +480,8 @@ struct VPlanTransforms {
static void materializeAliasMaskCheckBlock(
VPlan &Plan, ArrayRef<PointerDiffInfo> DiffChecks, bool HasBranchWeights);
- /// Try to expand VPExpandSCEVRecipes in \p Plan's entry block to
- /// VPInstructions. Recipes that cannot be expanded (like casts, min/max) are
- /// kept for later IR-level expansion.
+ /// Expand VPExpandSCEVRecipes in \p Plan's entry block to VPInstructions.
+ /// Recipes wrapping a SCEVAddRecExpr are kept for later IR-level expansion.
static void expandSCEVsToVPInstructions(VPlan &Plan, ScalarEvolution &SE);
/// Expand remaining VPExpandSCEVRecipes in \p Plan's entry block using
diff --git a/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp b/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp
index 03e1ead89c169..d1a9c9dbb5cbb 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp
@@ -13,6 +13,7 @@
#include "VPlanDominatorTree.h"
#include "VPlanPatternMatch.h"
#include "llvm/ADT/TypeSwitch.h"
+#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/MemoryLocation.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Analysis/ScalarEvolutionPatternMatch.h"
@@ -760,7 +761,7 @@ VPValue *VPSCEVExpander::tryToReuseIRValue(const SCEV *S) {
return nullptr;
}
-VPValue *VPSCEVExpander::tryToExpand(const SCEV *S) {
+VPValue *VPSCEVExpander::expand(const SCEV *S) {
if (VPValue *V = tryToReuseIRValue(S))
return V;
@@ -777,15 +778,11 @@ VPValue *VPSCEVExpander::tryToExpand(const SCEV *S) {
VPIRFlags::WrapFlagsTy WrapFlags(NAry->hasNoUnsignedWrap(),
NAry->hasNoSignedWrap());
- // Expanded poiner SCEVAddExpr as a ptradd of the pointer base and the
+ // Expand pointer SCEVAddExpr as a ptradd of the pointer base and the
// integer offset, matching SCEVExpander.
if (S->getType()->isPointerTy()) {
- VPValue *Base = tryToExpand(SE.getPointerBase(S));
- if (!Base)
- return nullptr;
- VPValue *Offset = tryToExpand(SE.removePointerBase(S));
- if (!Offset)
- return nullptr;
+ VPValue *Base = expand(SE.getPointerBase(S));
+ VPValue *Offset = expand(SE.removePointerBase(S));
GEPNoWrapFlags GEPFlags = WrapFlags.HasNUW
? GEPNoWrapFlags::noUnsignedWrap()
: GEPNoWrapFlags::none();
@@ -796,12 +793,8 @@ VPValue *VPSCEVExpander::tryToExpand(const SCEV *S) {
S->getSCEVType() == scAddExpr ? Instruction::Add : Instruction::Mul;
// Iterate in reverse so that constants are emitted last.
SmallVector<VPValue *, 2> Ops;
- for (const SCEVUse &Op : reverse(NAry->operands())) {
- VPValue *OpV = tryToExpand(Op);
- if (!OpV)
- return nullptr;
- Ops.push_back(OpV);
- }
+ for (const SCEVUse &Op : reverse(NAry->operands()))
+ Ops.push_back(expand(Op));
VPValue *Result = Ops.front();
for (VPValue *Op : drop_begin(Ops))
Result = Builder.createOverflowingOp(Opcode, {Result, Op}, WrapFlags, DL);
@@ -809,12 +802,22 @@ VPValue *VPSCEVExpander::tryToExpand(const SCEV *S) {
}
case scUDivExpr: {
auto *UDiv = cast<SCEVUDivExpr>(S);
- VPValue *LHS = tryToExpand(UDiv->getLHS());
- if (!LHS)
- return nullptr;
- VPValue *RHS = tryToExpand(UDiv->getRHS());
- if (!RHS)
- return nullptr;
+ VPValue *LHS = expand(UDiv->getLHS());
+ const SCEV *RHSExpr = UDiv->getRHS();
+ VPValue *RHS = expand(RHSExpr);
+ if (SafeUDivMode) {
+ // Make sure the UDiv's divisor is guaranteed to not be zero/poison, to
+ // avoid UB.
+ Type *RHSTy = RHSExpr->getType();
+ bool GuaranteedNotPoison =
+ ScalarEvolution::isGuaranteedNotToBePoison(RHSExpr);
+ if (!GuaranteedNotPoison)
+ RHS = Builder.createScalarFreeze(RHS, RHSTy, DL);
+ if (!SE.isKnownNonZero(RHSExpr) || !GuaranteedNotPoison)
+ RHS = Builder.createScalarIntrinsic(
+ Intrinsic::umax, {RHS, Builder.getPlan().getConstantInt(RHSTy, 1)},
+ RHSTy, DL);
+ }
return Builder.createNaryOp(Instruction::UDiv, {LHS, RHS},
VPIRFlags::getDefaultFlags(Instruction::UDiv),
DL);
@@ -825,9 +828,7 @@ VPValue *VPSCEVExpander::tryToExpand(const SCEV *S) {
case scPtrToInt:
case scPtrToAddr: {
auto *Cast = cast<SCEVCastExpr>(S);
- VPValue *Op = tryToExpand(Cast->getOperand());
- if (!Op)
- return nullptr;
+ VPValue *Op = expand(Cast->getOperand());
Instruction::CastOps Opcode;
switch (S->getSCEVType()) {
case scTruncate:
@@ -853,8 +854,9 @@ VPValue *VPSCEVExpander::tryToExpand(const SCEV *S) {
case scUMaxExpr:
case scSMaxExpr:
case scUMinExpr:
- case scSMinExpr: {
- auto *MinMax = cast<SCEVMinMaxExpr>(S);
+ case scSMinExpr:
+ case scSequentialUMinExpr: {
+ auto *MinMax = cast<SCEVNAryExpr>(S);
Intrinsic::ID IntrinsicID;
switch (S->getSCEVType()) {
case scUMaxExpr:
@@ -864,6 +866,7 @@ VPValue *VPSCEVExpander::tryToExpand(const SCEV *S) {
IntrinsicID = Intrinsic::smax;
break;
case scUMinExpr:
+ case scSequentialUMinExpr:
IntrinsicID = Intrinsic::umin;
break;
case scSMinExpr:
@@ -873,22 +876,37 @@ VPValue *VPSCEVExpander::tryToExpand(const SCEV *S) {
llvm_unreachable("Unexpected min/max SCEV type");
}
// Chain operands in reverse order matching SCEVExpander's expansion of
- // min/max expressions.
- SmallVector<VPValue *, 2> Ops;
- for (const SCEVUse &Op : reverse(MinMax->operands())) {
- VPValue *OpV = tryToExpand(Op);
- if (!OpV)
- return nullptr;
- Ops.push_back(OpV);
- }
+ // min/max expressions. In SafeUDivMode freeze expansion results of operands
+ // other than the first for sequential UMins, to avoid short-circuiting
+ // divide-by-0/poison.
+ bool IsSequential = S->getSCEVType() == scSequentialUMinExpr;
Type *ResultTy = MinMax->getType();
- VPValue *Result = Ops.front();
- for (VPValue *Op : drop_begin(Ops))
- Result = Builder.createScalarIntrinsic(IntrinsicID, {Result, Op},
- ResultTy, DL);
+ bool PrevSafeMode = SafeUDivMode;
+ VPValue *Result = nullptr;
+ for (const auto &[I, SCEVOp] : enumerate(reverse(MinMax->operands()))) {
+ bool MayShortCircuit = IsSequential && I != MinMax->getNumOperands() - 1;
+ SafeUDivMode = MayShortCircuit || PrevSafeMode;
+ VPValue *Op = expand(SCEVOp);
+ SafeUDivMode = PrevSafeMode;
+ if (MayShortCircuit)
+ Op = Builder.createScalarFreeze(Op, ResultTy, DL);
+ Result = Result ? Builder.createScalarIntrinsic(IntrinsicID, {Result, Op},
+ ResultTy, DL)
+ : Op;
+ }
return Result;
}
- default:
- return nullptr;
+ case scAddRecExpr: {
+ [[maybe_unused]] BasicBlock *PH =
+ cast<VPIRBasicBlock>(Builder.getPlan().getEntry())->getIRBasicBlock();
+ assert(
+ SE.DT.dominates(cast<SCEVAddRecExpr>(S)->getLoop()->getHeader(), PH) &&
+ "can only expand AddRecs for loops outside VPlan's scope");
+ // AddRecs outside VPlan's scope must be expanded via VPExpandSCEV.
+ return vputils::getOrCreateVPValueForSCEVExpr(Builder.getPlan(), S);
+ }
+ case scCouldNotCompute:
+ llvm_unreachable("Attempt to expand a SCEVCouldNotCompute");
}
+ llvm_unreachable("Unknown SCEV kind!");
}
diff --git a/llvm/lib/Transforms/Vectorize/VPlanUtils.h b/llvm/lib/Transforms/Vectorize/VPlanUtils.h
index 2980b704ec8da..ab7d18412dfa2 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanUtils.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanUtils.h
@@ -170,13 +170,17 @@ VPValue *findIncomingAliasMask(const VPlan &Plan);
} // namespace vputils
/// Lightweight SCEV-to-VPlan expander. Converts SCEV expressions into
-/// VPInstructions where possible, and returning nullptr for unsupported
-/// expressions (like adds, casts, min/max).
+/// VPInstructions and live-ins. SCEVAddRecExprs are wrapped in a
+/// VPExpandSCEVRecipe to be expanded to IR later.
class VPSCEVExpander {
VPBuilder &Builder;
ScalarEvolution &SE;
DebugLoc DL;
+ /// When true, nested SCEVUDivExprs are expanded so that they cannot divide by
+ /// zero, matching SCEVExpander's SafeUDivMode.
+ bool SafeUDivMode = false;
+
/// Try to find a loop-invariant IR value in the plan's entry block whose
/// SCEV matches \p S. Returns the corresponding live-in VPValue, or nullptr
/// if none is found.
@@ -186,9 +190,8 @@ class VPSCEVExpander {
VPSCEVExpander(VPBuilder &Builder, ScalarEvolution &SE, DebugLoc DL)
: Builder(Builder), SE(SE), DL(DL) {}
- /// Try to expand \p S into recipes and live-ins using the builder. Returns
- /// nullptr if \p S cannot be expanded yet.
- VPValue *tryToExpand(const SCEV *S);
+ /// Expand \p S into recipes and live-ins using the builder.
+ VPValue *expand(const SCEV *S);
};
//===----------------------------------------------------------------------===//
// Utilities for modifying predecessors and successors of VPlan blocks.
diff --git a/llvm/test/Transforms/LoopVectorize/VPlan/expand-scev.ll b/llvm/test/Transforms/LoopVectorize/VPlan/expand-scev.ll
index 1e55658ce19ae..a3eb8b2f574bb 100644
--- a/llvm/test/Transforms/LoopVectorize/VPlan/expand-scev.ll
+++ b/llvm/test/Transforms/LoopVectorize/VPlan/expand-scev.ll
@@ -321,14 +321,13 @@ exit:
define void @scev_addrec_expanded(ptr %dst) {
; CHECK-LABEL: VPlan for loop in 'scev_addrec_expanded'
; CHECK: VPlan 'Final VPlan for VF={4},UF={1}' {
-; CHECK-NEXT: Live-in ir<%2> = original trip-count
; CHECK-EMPTY:
; CHECK-NEXT: ir-bb<outer>:
; CHECK-NEXT: IR %outer.iv = phi i64 [ 0, %entry ], [ %outer.iv.next, %outer.latch ]
; CHECK-NEXT: IR %0 = add i64 %outer.iv, 4
-; CHECK-NEXT: IR %1 = udiv i64 %0, 3
-; CHECK-NEXT: IR %2 = add nuw nsw i64 %1, 1
-; CHECK-NEXT: EMIT vp<%min.iters.check> = icmp ult ir<%2>, ir<4>
+; CHECK-NEXT: EMIT vp<[[VP2:%[0-9]+]]> = udiv ir<%0>, ir<3>
+; CHECK-NEXT: EMIT vp<[[VP3:%[0-9]+]]> = add nuw nsw vp<[[VP2]]>, ir<1>
+; CHECK-NEXT: EMIT vp<%min.iters.check> = icmp ult vp<[[VP3]]>, ir<4>
; CHECK-NEXT: EMIT branch-on-cond vp<%min.iters.check>
; CHECK-NEXT: Successor(s): ir-bb<scalar.ph>, vector.ph
;
diff --git a/llvm/test/Transforms/LoopVectorize/pr55100-expand-scev-predicate-used.ll b/llvm/test/Transforms/LoopVectorize/pr55100-expand-scev-predicate-used.ll
index d3b8dafaf0002..2aead0ee79aac 100644
--- a/llvm/test/Transforms/LoopVectorize/pr55100-expand-scev-predicate-used.ll
+++ b/llvm/test/Transforms/LoopVectorize/pr55100-expand-scev-predicate-used.ll
@@ -10,11 +10,11 @@ define void @test_pr55100(i32 %N) {
; CHECK-NEXT: [[IV_1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_1_NEXT:%.*]], [[LOOP_1_LATCH:%.*]] ]
; CHECK-NEXT: [[TMP1:%.*]] = mul nuw nsw i32 [[IV_1]], -1
; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[TMP0]], [[TMP1]]
-; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP2]], i32 18)
-; CHECK-NEXT: [[TMP3:%.*]] = add nuw nsw i32 [[UMIN]], 1
; CHECK-NEXT: [[C_2:%.*]] = icmp ugt i32 [[IV_1]], 10
; CHECK-NEXT: br i1 [[C_2]], label [[LOOP_2_HEADER_PREHEADER:%.*]], label [[EXIT_LOOPEXIT1:%.*]]
; CHECK: loop.2.header.preheader:
+; CHECK-NEXT: [[TMP7:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP2]], i32 18)
+; CHECK-NEXT: [[TMP3:%.*]] = add nuw nsw i32 [[TMP7]], 1
; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ule i32 [[TMP3]], 2
; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label [[SCALAR_PH:%.*]], label [[VECTOR_PH:%.*]]
; CHECK: vector.ph:
diff --git a/llvm/test/Transforms/LoopVectorize/reuse-lcssa-phi-scev-expansion.ll b/llvm/test/Transforms/LoopVectorize/reuse-lcssa-phi-scev-expansion.ll
index 26f7fc23d7ef7..2cb95300509fa 100644
--- a/llvm/test/Transforms/LoopVectorize/reuse-lcssa-phi-scev-expansion.ll
+++ b/llvm/test/Transforms/LoopVectorize/reuse-lcssa-phi-scev-expansion.ll
@@ -206,12 +206,10 @@ define void @expand_diff_scev_unknown(ptr %dst, i1 %invar.c, i32 %step) mustprog
; CHECK-NEXT: br i1 [[INVAR_C]], label %[[LOOP_2_PREHEADER:.*]], label %[[LOOP_1]]
; CHECK: [[LOOP_2_PREHEADER]]:
; CHECK-NEXT: [[IV_1_LCSSA:%.*]] = phi i32 [ [[IV_1]], %[[LOOP_1]] ]
-; CHECK-NEXT: [[TMP0:%.*]] = sub i32 2, [[STEP]]
-; CHECK-NEXT: [[TMP12:%.*]] = add i32 [[IV_1_LCSSA]], [[TMP0]]
-; CHECK-NEXT: [[SMAX1:%.*]] = call i32 @llvm.smax.i32(i32 [[TMP12]], i32 0)
; CHECK-NEXT: [[TMP3:%.*]] = mul i32 [[INDVAR]], -1
; CHECK-NEXT: [[TMP14:%.*]] = add i32 [[TMP3]], -1
-; CHECK-NEXT: [[TMP15:%.*]] = add i32 [[SMAX1]], [[TMP14]]
+; CHECK-NEXT: [[TMP16:%.*]] = sub i32 2, [[STEP]]
+; CHECK-NEXT: [[TMP17:%.*]] = add i32 [[IV_1_LCSSA]], [[TMP16]]
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[IV_1_LCSSA]], [[STEP]]
; CHECK-NEXT: [[SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[TMP1]], i32 0)
; CHECK-NEXT: [[TMP2:%.*]] = mul i32 [[STEP]], -2
@@ -223,6 +221,8 @@ define void @expand_diff_scev_unknown(ptr %dst, i1 %invar.c, i32 %step) mustprog
; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[STEP]], i32 1)
; CHECK-NEXT: [[TMP8:%.*]] = udiv i32 [[TMP7]], [[UMAX]]
; CHECK-NEXT: [[TMP9:%.*]] = add i32 [[TMP6]], [[TMP8]]
+; CHECK-NEXT: [[TMP12:%.*]] = call i32 @llvm.smax.i32(i32 [[TMP17]], i32 0)
+; CHECK-NEXT: [[TMP15:%.*]] = add i32 [[TMP12]], [[TMP14]]
; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i32 [[TMP15]], 2
; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_SCEVCHECK:.*]]
; CHECK: [[VECTOR_SCEVCHECK]]:
diff --git a/llvm/test/Transforms/LoopVectorize/trip-count-expansion-may-introduce-ub.ll b/llvm/test/Transforms/LoopVectorize/trip-count-expansion-may-introduce-ub.ll
index c02847c55f23b..0cbb2aac3c22c 100644
--- a/llvm/test/Transforms/LoopVectorize/trip-count-expansion-may-introduce-ub.ll
+++ b/llvm/test/Transforms/LoopVectorize/trip-count-expansion-may-introduce-ub.ll
@@ -916,7 +916,7 @@ define i64 @multi_exit_4_exit_count_with_urem_by_value_in_latch(ptr %dst, i64 %N
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP12:%.*]] = call i64 @llvm.umax.i64(i64 [[N]], i64 1)
; CHECK-NEXT: [[TMP0:%.*]] = udiv i64 42, [[TMP12]]
-; CHECK-NEXT: [[TMP1:%.*]] = mul nuw i64 [[N]], [[TMP0]]
+; CHECK-NEXT: [[TMP1:%.*]] = mul i64 [[N]], [[TMP0]]
; CHECK-NEXT: [[TMP2:%.*]] = sub i64 42, [[TMP1]]
; CHECK-NEXT: [[SMAX1:%.*]] = call i64 @llvm.smax.i64(i64 [[TMP2]], i64 0)
; CHECK-NEXT: [[TMP10:%.*]] = freeze i64 [[SMAX1]]
``````````
</details>
https://github.com/llvm/llvm-project/pull/210013
More information about the llvm-commits
mailing list