Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
756be4b
[LV] Vectorize conditional scalar assignments
huntergr-arm Mar 26, 2025
d3c1a9c
Apply suggestion from @MacDue
huntergr-arm Nov 11, 2025
b1e535e
Remove LVL param
huntergr-arm Nov 11, 2025
0083cd5
Remove VPLastActiveMaskPHIRecipe
huntergr-arm Nov 12, 2025
1fdc629
Add regex matches to vplan test
huntergr-arm Nov 12, 2025
0972c1b
Use find_if
huntergr-arm Nov 12, 2025
26a6c71
Handle FindLast properly in unrolling, test
huntergr-arm Nov 19, 2025
140a0d3
Remove instcombine from AArch64 FindLast runlines
huntergr-arm Nov 19, 2025
fd27c9f
Switched vplan print test to use fixed VF instead of scalable
huntergr-arm Nov 19, 2025
ddaa28e
Moved vectorized epilogue ICE test to separate file, removed unnecess…
huntergr-arm Nov 19, 2025
3bdc7ff
Updated check output after rebase
huntergr-arm Nov 19, 2025
9fe220d
Move epilogue vectorization test back to LV
huntergr-arm Nov 20, 2025
da25c67
Improve IVDesc comments
huntergr-arm Nov 20, 2025
f7618a3
Remove traces of dedicated FindLast phi recipe
huntergr-arm Nov 20, 2025
dda8a83
Move and improve convertFindLastRecurrences
huntergr-arm Nov 20, 2025
f2fe1ae
Add test with extra user for select
huntergr-arm Nov 20, 2025
6aa9dc1
Call xform earlier
huntergr-arm Nov 25, 2025
01fc553
Use Plan.getFalse()
huntergr-arm Nov 25, 2025
cef6c7a
Add a test case with extra arithmetic operations
huntergr-arm Nov 25, 2025
b0486fa
Adjust tests post-rebase
huntergr-arm Nov 26, 2025
4eb54d6
Unify Find recurrence detection.
huntergr-arm Nov 26, 2025
a2f3644
Clean up any_of with values() iterator
huntergr-arm Dec 2, 2025
b5bf664
Formatting
huntergr-arm Dec 2, 2025
8656c46
Cleanups
huntergr-arm Dec 4, 2025
2ac7132
Improve comments, restore original cast
huntergr-arm Dec 5, 2025
a9d29c5
Add test operating on bytes, then add an equivalent test file for X86
huntergr-arm Dec 5, 2025
dde18ff
Formatting
huntergr-arm Dec 5, 2025
1f1bcb7
Remove mention of NEON from X86 test file
huntergr-arm Dec 5, 2025
78682bf
Disable use on X86 without AVX512
huntergr-arm Dec 10, 2025
ce7a1bc
Cleanups, interleave test
huntergr-arm Dec 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions llvm/include/llvm/Analysis/IVDescriptors.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ enum class RecurKind {
FindLastIVUMax, ///< FindLast reduction with select(cmp(),x,y) where one of
///< (x,y) is increasing loop induction, and both x and y
///< are integer type, producing a UMax reduction.
FindLast, ///< FindLast reduction with select(cmp(),x,y) where x and y
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think at least loop-unrolling also needs to be thought about the new kind, seeing crashes when building the test suite currently. I think to reproduce you can just add a loop with CAS to https://github.com/llvm/llvm-project/blob/main/llvm/test/Transforms/LoopUnroll/partial-unroll-reductions.ll.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done. I think I left it alone originally since I made FindLast a generic RecurKind that could handle int, float, and pointer types (and it therefore didn't appear in the isIntegerRecurrenceKind list.) I figured that could be a follow-up PR (and could potentially convert AnyOf at the same time).

///< are an integer type, one is the current recurrence value,
///< and the other is an arbitrary value.
// clang-format on
// TODO: Any_of and FindLast reduction need not be restricted to integer type
// only.
Expand Down Expand Up @@ -180,13 +183,11 @@ class RecurrenceDescriptor {
/// Returns a struct describing whether the instruction is either a
/// Select(ICmp(A, B), X, Y), or
/// Select(FCmp(A, B), X, Y)
/// where one of (X, Y) is an increasing (FindLast) or decreasing (FindFirst)
/// loop induction variable, and the other is a PHI value.
// TODO: Support non-monotonic variable. FindLast does not need be restricted
// to increasing loop induction variables.
LLVM_ABI static InstDesc isFindIVPattern(RecurKind Kind, Loop *TheLoop,
PHINode *OrigPhi, Instruction *I,
ScalarEvolution &SE);
/// where one of (X, Y) is an increasing (FindLastIV) or decreasing
/// (FindFirstIV) loop induction variable, or an arbitrary integer value
/// (FindLast), and the other is a PHI value.
LLVM_ABI static InstDesc isFindPattern(Loop *TheLoop, PHINode *OrigPhi,
Instruction *I, ScalarEvolution &SE);

/// Returns a struct describing if the instruction is a
/// Select(FCmp(X, Y), (Z = X op PHINode), PHINode) instruction pattern.
Expand Down Expand Up @@ -310,6 +311,17 @@ class RecurrenceDescriptor {
isFindLastIVRecurrenceKind(Kind);
}

/// Returns true if the recurrence kind is of the form
/// select(cmp(),x,y) where one of (x,y) is an arbitrary value and the
/// other is a recurrence.
static bool isFindLastRecurrenceKind(RecurKind Kind) {
return Kind == RecurKind::FindLast;
}

static bool isFindRecurrenceKind(RecurKind Kind) {
return isFindLastRecurrenceKind(Kind) || isFindIVRecurrenceKind(Kind);
}

/// Returns the type of the recurrence. This type can be narrower than the
/// actual type of the Phi if the recurrence has been type-promoted.
Type *getRecurrenceType() const { return RecurrenceType; }
Expand Down
93 changes: 50 additions & 43 deletions llvm/lib/Analysis/IVDescriptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ bool RecurrenceDescriptor::isIntegerRecurrenceKind(RecurKind Kind) {
case RecurKind::FindFirstIVUMin:
case RecurKind::FindLastIVSMax:
case RecurKind::FindLastIVUMax:
// TODO: Make type-agnostic.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is not type-agnostic, should this be reflected in the name of the recurrence kind?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It isn't for the other FindFirst/FindLast (though that might be inferred by U/S Min/Max) or AnyOf. I think it's just the fp-based reduction types that are prefixed with an extra F.

I did experiment with treating FindLast separately in AddReductionVar when it checks the type and everything was fine, but decided to leave that out of the initial patch.

case RecurKind::FindLast:
return true;
}
return false;
Expand Down Expand Up @@ -721,9 +723,15 @@ RecurrenceDescriptor::isAnyOfPattern(Loop *Loop, PHINode *OrigPhi,
// if (src[i] > 3)
// r = i;
// }
// or like this:
// int r = 0;
// for (int i = 0; i < n; i++) {
// if (src[i] > 3)
// r = <loop-varying value>;
// }
// The reduction value (r) is derived from either the values of an induction
// variable (i) sequence, or from the start value (0). The LLVM IR generated for
// such loops would be as follows:
// variable (i) sequence, an arbitrary loop-varying value, or from the start
// value (0). The LLVM IR generated for such loops would be as follows:
// for.body:
// %r = phi i32 [ %spec.select, %for.body ], [ 0, %entry ]
// %i = phi i32 [ %inc, %for.body ], [ 0, %entry ]
Expand All @@ -732,23 +740,27 @@ RecurrenceDescriptor::isAnyOfPattern(Loop *Loop, PHINode *OrigPhi,
// %spec.select = select i1 %cmp, i32 %i, i32 %r
// %inc = add nsw i32 %i, 1
// ...
// Since 'i' is an induction variable, the reduction value after the loop will
// be the maximum (increasing induction) or minimum (decreasing induction) value
// of 'i' that the condition (src[i] > 3) is satisfied, or the start value (0 in
// the example above). When the start value of the induction variable 'i' is
// greater than the minimum (increasing induction) or maximum (decreasing
// induction) value of the data type, we can use the minimum (increasing
// induction) or maximum (decreasing induction) value of the data type as a
// sentinel value to replace the start value. This allows us to perform a single
// reduction max (increasing induction) or min (decreasing induction) operation
// to obtain the final reduction result.
// When searching for an induction variable (i), the reduction value after the
// loop will be the maximum (increasing induction) or minimum (decreasing
// induction) value of 'i' that the condition (src[i] > 3) is satisfied, or the
// start value (0 in the example above). When the start value of the induction
// variable 'i' is greater than the minimum (increasing induction) or maximum
// (decreasing induction) value of the data type, we can use the minimum
// (increasing induction) or maximum (decreasing induction) value of the data
// type as a sentinel value to replace the start value. This allows us to
// perform a single reduction max (increasing induction) or min (decreasing
// induction) operation to obtain the final reduction result.
Comment on lines +743 to +752
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this isn't your writing, but this is very difficult to follow..

// TODO: It is possible to solve the case where the start value is the minimum
// value of the data type or a non-constant value by using mask and multiple
// reduction operations.
//
// When searching for an arbitrary loop-varying value, the reduction value will
// either be the initial value (0) if the condition was never met, or the value
// of the loop-varying value in the most recent loop iteration where the
// condition was met.
RecurrenceDescriptor::InstDesc
RecurrenceDescriptor::isFindIVPattern(RecurKind Kind, Loop *TheLoop,
PHINode *OrigPhi, Instruction *I,
ScalarEvolution &SE) {
RecurrenceDescriptor::isFindPattern(Loop *TheLoop, PHINode *OrigPhi,
Instruction *I, ScalarEvolution &SE) {
// TODO: Support the vectorization of FindLastIV when the reduction phi is
// used by more than one select instruction. This vectorization is only
// performed when the SCEV of each increasing induction variable used by the
Expand All @@ -757,8 +769,10 @@ RecurrenceDescriptor::isFindIVPattern(RecurKind Kind, Loop *TheLoop,
return InstDesc(false, I);

// We are looking for selects of the form:
// select(cmp(), phi, loop_induction) or
// select(cmp(), loop_induction, phi)
// select(cmp(), phi, value) or
// select(cmp(), value, phi)
// where 'value' must be a loop induction variable
// (for FindFirstIV/FindLastIV) or an arbitrary value (for FindLast).
// TODO: Match selects with multi-use cmp conditions.
Value *NonRdxPhi = nullptr;
if (!match(I, m_CombineOr(m_Select(m_OneUse(m_Cmp()), m_Value(NonRdxPhi),
Expand All @@ -769,7 +783,7 @@ RecurrenceDescriptor::isFindIVPattern(RecurKind Kind, Loop *TheLoop,

// Returns either FindFirstIV/FindLastIV, if such a pattern is found, or
// std::nullopt.
auto GetRecurKind = [&](Value *V) -> std::optional<RecurKind> {
auto GetFindFirstLastIVRecurKind = [&](Value *V) -> std::optional<RecurKind> {
Type *Ty = V->getType();
if (!SE.isSCEVable(Ty))
return std::nullopt;
Expand All @@ -780,8 +794,9 @@ RecurrenceDescriptor::isFindIVPattern(RecurKind Kind, Loop *TheLoop,
m_SpecificLoop(TheLoop))))
return std::nullopt;

if ((isFindFirstIVRecurrenceKind(Kind) && !SE.isKnownNegative(Step)) ||
(isFindLastIVRecurrenceKind(Kind) && !SE.isKnownPositive(Step)))
// We must have a known positive or negative step for FindIV
const bool PositiveStep = SE.isKnownPositive(Step);
if (!SE.isKnownNonZero(Step))
return std::nullopt;

// Check if the minimum (FindLast) or maximum (FindFirst) value of the
Expand All @@ -797,7 +812,7 @@ RecurrenceDescriptor::isFindIVPattern(RecurKind Kind, Loop *TheLoop,
IsSigned ? SE.getSignedRange(AR) : SE.getUnsignedRange(AR);
unsigned NumBits = Ty->getIntegerBitWidth();
ConstantRange ValidRange = ConstantRange::getEmpty(NumBits);
if (isFindLastIVRecurrenceKind(Kind)) {
if (PositiveStep) {
APInt Sentinel = IsSigned ? APInt::getSignedMinValue(NumBits)
: APInt::getMinValue(NumBits);
ValidRange = ConstantRange::getNonEmpty(Sentinel + 1, Sentinel);
Expand All @@ -811,26 +826,22 @@ RecurrenceDescriptor::isFindIVPattern(RecurKind Kind, Loop *TheLoop,
APInt::getMinValue(NumBits), APInt::getMaxValue(NumBits) - 1);
}

LLVM_DEBUG(dbgs() << "LV: "
<< (isFindLastIVRecurrenceKind(Kind) ? "FindLastIV"
: "FindFirstIV")
<< " valid range is " << ValidRange
<< ", and the range of " << *AR << " is " << IVRange
<< "\n");
LLVM_DEBUG(
dbgs() << "LV: " << (PositiveStep ? "FindLastIV" : "FindFirstIV")
<< " valid range is " << ValidRange << ", and the range of "
<< *AR << " is " << IVRange << "\n");

// Ensure the induction variable does not wrap around by verifying that
// its range is fully contained within the valid range.
return ValidRange.contains(IVRange);
};
if (isFindLastIVRecurrenceKind(Kind)) {
if (PositiveStep) {
if (CheckRange(true))
return RecurKind::FindLastIVSMax;
if (CheckRange(false))
return RecurKind::FindLastIVUMax;
return std::nullopt;
}
assert(isFindFirstIVRecurrenceKind(Kind) &&
"Kind must either be a FindLastIV or FindFirstIV");

if (CheckRange(true))
return RecurKind::FindFirstIVSMin;
Expand All @@ -839,10 +850,11 @@ RecurrenceDescriptor::isFindIVPattern(RecurKind Kind, Loop *TheLoop,
return std::nullopt;
};

if (auto RK = GetRecurKind(NonRdxPhi))
if (auto RK = GetFindFirstLastIVRecurKind(NonRdxPhi))
return InstDesc(I, *RK);

return InstDesc(false, I);
// If the recurrence is not specific to an IV, return a generic FindLast.
return InstDesc(I, RecurKind::FindLast);
}

RecurrenceDescriptor::InstDesc
Expand Down Expand Up @@ -976,8 +988,8 @@ RecurrenceDescriptor::InstDesc RecurrenceDescriptor::isRecurrenceInstr(
Kind == RecurKind::Add || Kind == RecurKind::Mul ||
Kind == RecurKind::Sub || Kind == RecurKind::AddChainWithSubs)
return isConditionalRdxPattern(I);
if (isFindIVRecurrenceKind(Kind) && SE)
return isFindIVPattern(Kind, L, OrigPhi, I, *SE);
if (isFindRecurrenceKind(Kind) && SE)
return isFindPattern(L, OrigPhi, I, *SE);
[[fallthrough]];
case Instruction::FCmp:
case Instruction::ICmp:
Expand Down Expand Up @@ -1117,14 +1129,9 @@ bool RecurrenceDescriptor::isReductionPHI(PHINode *Phi, Loop *TheLoop,
<< "\n");
return true;
}
if (AddReductionVar(Phi, RecurKind::FindLastIVSMax, TheLoop, FMF, RedDes, DB,
AC, DT, SE)) {
LLVM_DEBUG(dbgs() << "Found a FindLastIV reduction PHI." << *Phi << "\n");
return true;
}
if (AddReductionVar(Phi, RecurKind::FindFirstIVSMin, TheLoop, FMF, RedDes, DB,
AC, DT, SE)) {
LLVM_DEBUG(dbgs() << "Found a FindFirstIV reduction PHI." << *Phi << "\n");
if (AddReductionVar(Phi, RecurKind::FindLast, TheLoop, FMF, RedDes, DB, AC,
DT, SE)) {
LLVM_DEBUG(dbgs() << "Found a Find reduction PHI." << *Phi << "\n");
return true;
}
if (AddReductionVar(Phi, RecurKind::FMul, TheLoop, FMF, RedDes, DB, AC, DT,
Expand Down Expand Up @@ -1174,7 +1181,6 @@ bool RecurrenceDescriptor::isReductionPHI(PHINode *Phi, Loop *TheLoop,
<< "\n");
return true;
}

// Not a reduction of known type.
return false;
}
Expand Down Expand Up @@ -1299,6 +1305,7 @@ unsigned RecurrenceDescriptor::getOpcode(RecurKind Kind) {
case RecurKind::FMaximumNum:
case RecurKind::FMinimumNum:
return Instruction::FCmp;
case RecurKind::FindLast:
case RecurKind::AnyOf:
case RecurKind::FindFirstIVSMin:
case RecurKind::FindFirstIVUMin:
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5523,6 +5523,7 @@ bool AArch64TTIImpl::isLegalToVectorizeReduction(
case RecurKind::FMax:
case RecurKind::FMulAdd:
case RecurKind::AnyOf:
case RecurKind::FindLast:
return true;
default:
return false;
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/Target/X86/X86TargetTransformInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4604,6 +4604,13 @@ X86TTIImpl::getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA,
break;
}

// FIXME: There's a bug in SelectionDAG legalization for some data types
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be great if you could file an issue for that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raised as #171831

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great thanks! Do we still need anotther check to also avoid forced vectorization if the cost of the intrinsic is invalid?

// between a select and an extract when using this intrinsic for X86 without
// AVX512.
if (IID == Intrinsic::experimental_vector_extract_last_active &&
!ST->hasAVX512())
return InstructionCost::getInvalid();

if (ISD != ISD::DELETED_NODE) {
auto adjustTableCost = [&](int ISD, unsigned Cost,
std::pair<InstructionCost, MVT> LT,
Expand Down
5 changes: 3 additions & 2 deletions llvm/lib/Transforms/Utils/LoopUnroll.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1258,9 +1258,10 @@ llvm::canParallelizeReductionWhenUnrolling(PHINode &Phi, Loop *L,
return std::nullopt;
RecurKind RK = RdxDesc.getRecurrenceKind();
// Skip unsupported reductions.
// TODO: Handle additional reductions, including min-max reductions.
// TODO: Handle additional reductions, including FP and min-max
// reductions.
if (RecurrenceDescriptor::isAnyOfRecurrenceKind(RK) ||
RecurrenceDescriptor::isFindIVRecurrenceKind(RK) ||
RecurrenceDescriptor::isFindRecurrenceKind(RK) ||
RecurrenceDescriptor::isMinMaxRecurrenceKind(RK))
return std::nullopt;

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/Utils/LoopUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1491,7 +1491,7 @@ Value *llvm::createSimpleReduction(IRBuilderBase &Builder, Value *Src,
Value *llvm::createSimpleReduction(IRBuilderBase &Builder, Value *Src,
RecurKind Kind, Value *Mask, Value *EVL) {
assert(!RecurrenceDescriptor::isAnyOfRecurrenceKind(Kind) &&
!RecurrenceDescriptor::isFindIVRecurrenceKind(Kind) &&
!RecurrenceDescriptor::isFindRecurrenceKind(Kind) &&
"AnyOf and FindIV reductions are not supported.");
Intrinsic::ID Id = getReductionIntrinsicID(Kind);
auto VPID = VPIntrinsic::getForIntrinsic(Id);
Expand Down
45 changes: 38 additions & 7 deletions llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4326,11 +4326,15 @@ bool LoopVectorizationPlanner::isCandidateForEpilogueVectorization(
ElementCount VF) const {
// Cross iteration phis such as fixed-order recurrences and FMaxNum/FMinNum
// reductions need special handling and are currently unsupported.
// FindLast reductions also require special handling for the synthesized
// mask PHI.
if (any_of(OrigLoop->getHeader()->phis(), [&](PHINode &Phi) {
if (!Legal->isReductionVariable(&Phi))
return Legal->isFixedOrderRecurrence(&Phi);
return RecurrenceDescriptor::isFPMinMaxNumRecurrenceKind(
Legal->getRecurrenceDescriptor(&Phi).getRecurrenceKind());
RecurKind Kind =
Legal->getRecurrenceDescriptor(&Phi).getRecurrenceKind();
return RecurrenceDescriptor::isFindLastRecurrenceKind(Kind) ||
RecurrenceDescriptor::isFPMinMaxNumRecurrenceKind(Kind);
}))
return false;

Expand Down Expand Up @@ -4636,6 +4640,14 @@ LoopVectorizationPlanner::selectInterleaveCount(VPlan &Plan, ElementCount VF,
any_of(Plan.getVectorLoopRegion()->getEntryBasicBlock()->phis(),
IsaPred<VPReductionPHIRecipe>);

// FIXME: implement interleaving for FindLast transform correctly.
if (any_of(make_second_range(Legal->getReductionVars()),
[](const RecurrenceDescriptor &RdxDesc) {
return RecurrenceDescriptor::isFindLastRecurrenceKind(
RdxDesc.getRecurrenceKind());
}))
return 1;
Comment on lines +4643 to +4649
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to move this check earlier. (see the check a bit before the call to selectInterleaveCount that handles isSafeForAnyVectorwidth). We take the max of UserIC (set via flag or pragma) and the IC returned here, so we still may end up interleaving if the user requests it. Would be good to add a test with forced interleaving.

Copy link
Collaborator Author

@huntergr-arm huntergr-arm Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a second check in processLoop which blocks interleaving for FindLast reductions. This check is just to avoid confusing debug/remark messages that indicate we're going to interleave due to reductions, then immediate say interleaving was disabled due to a FindLast reduction.

Trying to override UserIC early on results in an ICE for the assert with !LVL.isSafeForAnyVectorWidth() after the cost model has been checked.

I have added a test with an interleaving hint to both the AArch64 and X86 test files.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh right.


// If we did not calculate the cost for VF (because the user selected the VF)
// then we calculate the cost of VF here.
if (LoopCost == 0) {
Expand Down Expand Up @@ -8623,6 +8635,11 @@ VPlanPtr LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(
*Plan))
return nullptr;

// Create whole-vector selects for find-last recurrences.
if (!VPlanTransforms::runPass(VPlanTransforms::handleFindLastReductions,
*Plan))
return nullptr;

// Transform recipes to abstract recipes if it is legal and beneficial and
// clamp the range for better cost estimation.
// TODO: Enable following transform when the EVL-version of extended-reduction
Expand Down Expand Up @@ -8744,10 +8761,11 @@ void LoopVectorizationPlanner::adjustRecipesForReductions(
continue;

RecurKind Kind = PhiR->getRecurrenceKind();
assert(
!RecurrenceDescriptor::isAnyOfRecurrenceKind(Kind) &&
!RecurrenceDescriptor::isFindIVRecurrenceKind(Kind) &&
"AnyOf and FindIV reductions are not allowed for in-loop reductions");
assert(!RecurrenceDescriptor::isFindLastRecurrenceKind(Kind) &&
!RecurrenceDescriptor::isAnyOfRecurrenceKind(Kind) &&
!RecurrenceDescriptor::isFindIVRecurrenceKind(Kind) &&
"AnyOf, FindIV, and FindLast reductions are not allowed for in-loop "
"reductions");

bool IsFPRecurrence =
RecurrenceDescriptor::isFloatingPointRecurrenceKind(Kind);
Expand Down Expand Up @@ -9059,7 +9077,8 @@ void LoopVectorizationPlanner::adjustRecipesForReductions(
RecurKind RK = RdxDesc.getRecurrenceKind();
if ((!RecurrenceDescriptor::isAnyOfRecurrenceKind(RK) &&
!RecurrenceDescriptor::isFindIVRecurrenceKind(RK) &&
!RecurrenceDescriptor::isMinMaxRecurrenceKind(RK))) {
!RecurrenceDescriptor::isMinMaxRecurrenceKind(RK) &&
!RecurrenceDescriptor::isFindLastRecurrenceKind(RK))) {
VPBuilder PHBuilder(Plan->getVectorPreheader());
VPValue *Iden = Plan->getOrAddLiveIn(
getRecurrenceIdentity(RK, PhiTy, RdxDesc.getFastMathFlags()));
Expand Down Expand Up @@ -10194,6 +10213,18 @@ bool LoopVectorizePass::processLoop(Loop *L) {
// Override IC if user provided an interleave count.
IC = UserIC > 0 ? UserIC : IC;

// FIXME: Enable interleaving for FindLast reductions.
if (any_of(LVL.getReductionVars().values(), [](auto &RdxDesc) {
return RecurrenceDescriptor::isFindLastRecurrenceKind(
RdxDesc.getRecurrenceKind());
})) {
LLVM_DEBUG(dbgs() << "LV: Not interleaving due to FindLast reduction.\n");
IntDiagMsg = {"FindLastPreventsScalarInterleaving",
"Unable to interleave due to FindLast reduction."};
InterleaveLoop = false;
IC = 1;
}

// Emit diagnostic messages, if any.
const char *VAPassName = Hints.vectorizeAnalysisPassName();
if (!VectorizeLoop && !InterleaveLoop) {
Expand Down
Loading