Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 15 additions & 0 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
///< can be any scalar type, one is the current recurrence
Copy link
Contributor

Choose a reason for hiding this comment

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

Since isIntegerRecurrenceKind returns true for FindLast, I suggest

Suggested change
///< can be any scalar type, one is the current recurrence
///< are 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 @@ -183,6 +186,12 @@ class RecurrenceDescriptor {
PHINode *OrigPhi, Instruction *I,
ScalarEvolution &SE);

/// Returns a struct describing whether the instruction is of the form
/// Select(Cmp(A, B), X, Y)
/// where one of (X, Y) is the Phi value and the other is an arbitrary value.
LLVM_ABI static InstDesc isFindLastPattern(Instruction *I, PHINode *Phi,
Loop *TheLoop);

/// Returns a struct describing if the instruction is a
/// Select(FCmp(X, Y), (Z = X op PHINode), PHINode) instruction pattern.
LLVM_ABI static InstDesc isConditionalRdxPattern(Instruction *I);
Expand Down Expand Up @@ -299,6 +308,12 @@ 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.
static bool isFindLastRecurrenceKind(RecurKind Kind) {
return Kind == RecurKind::FindLast;
}

/// 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
45 changes: 44 additions & 1 deletion llvm/lib/Analysis/IVDescriptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ bool RecurrenceDescriptor::isIntegerRecurrenceKind(RecurKind Kind) {
case RecurKind::FindFirstIVUMin:
case RecurKind::FindLastIVSMax:
case RecurKind::FindLastIVUMax:
// TODO: Make type-agnostic.
case RecurKind::FindLast:
return true;
}
return false;
Expand Down Expand Up @@ -426,6 +428,8 @@ bool RecurrenceDescriptor::AddReductionVar(
++NumCmpSelectPatternInst;
if (isAnyOfRecurrenceKind(Kind) && IsASelect)
++NumCmpSelectPatternInst;
if (isFindLastRecurrenceKind(Kind) && IsASelect)
++NumCmpSelectPatternInst;
Comment on lines +431 to +432
Copy link
Contributor

Choose a reason for hiding this comment

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

Why we need this?


// Check whether we found a reduction operator.
FoundReduxOp |= !IsAPhi && Cur != Start;
Expand Down Expand Up @@ -789,6 +793,38 @@ RecurrenceDescriptor::isFindIVPattern(RecurKind Kind, Loop *TheLoop,
return InstDesc(false, I);
}

RecurrenceDescriptor::InstDesc
RecurrenceDescriptor::isFindLastPattern(Instruction *I, PHINode *Phi,
Loop *TheLoop) {
Comment on lines +797 to +798
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we reuse RecurrenceDescriptor::isFindIVPattern?

// Must be a scalar.
Type *Type = Phi->getType();
if (!Type->isIntegerTy() && !Type->isFloatingPointTy() &&
!Type->isPointerTy())
return InstDesc(false, I);

SelectInst *Select = dyn_cast<SelectInst>(I);
if (!Select)
return InstDesc(false, I);

// FIXME: Support more complex patterns, including multiple selects.
// Phi or Select must be used only outside the loop,
// except for each other.
auto IsOnlyUsedOutsideLoop = [&](Value *V, Value *Ignore) {
return all_of(V->users(), [Ignore, TheLoop](User *U) {
if (U == Ignore)
return true;
if (auto *I = dyn_cast<Instruction>(U))
return !TheLoop->contains(I);
return false;
});
};
if (!IsOnlyUsedOutsideLoop(Phi, Select) ||
!IsOnlyUsedOutsideLoop(Select, Phi))
return InstDesc(false, I);

return InstDesc(I, RecurKind::FindLast);
}

RecurrenceDescriptor::InstDesc
RecurrenceDescriptor::isMinMaxPattern(Instruction *I, RecurKind Kind,
const InstDesc &Prev) {
Expand Down Expand Up @@ -927,6 +963,8 @@ RecurrenceDescriptor::InstDesc RecurrenceDescriptor::isRecurrenceInstr(
return isConditionalRdxPattern(I);
if (isFindIVRecurrenceKind(Kind) && SE)
return isFindIVPattern(Kind, L, OrigPhi, I, *SE);
if (isFindLastRecurrenceKind(Kind))
return isFindLastPattern(I, OrigPhi, L);
[[fallthrough]];
case Instruction::FCmp:
case Instruction::ICmp:
Expand Down Expand Up @@ -1123,7 +1161,11 @@ bool RecurrenceDescriptor::isReductionPHI(PHINode *Phi, Loop *TheLoop,
<< "\n");
return true;
}

if (AddReductionVar(Phi, RecurKind::FindLast, TheLoop, FMF, RedDes, DB, AC,
DT, SE)) {
LLVM_DEBUG(dbgs() << "Found a FindLast reduction PHI." << *Phi << "\n");
return true;
}
// Not a reduction of known type.
return false;
}
Expand Down Expand Up @@ -1245,6 +1287,7 @@ unsigned RecurrenceDescriptor::getOpcode(RecurKind Kind) {
case RecurKind::SMin:
case RecurKind::UMax:
case RecurKind::UMin:
case RecurKind::FindLast:
return Instruction::ICmp;
case RecurKind::FMax:
case RecurKind::FMin:
Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1004,6 +1004,13 @@ AArch64TTIImpl::getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA,
}
break;
}
case Intrinsic::experimental_vector_extract_last_active:
if (ST->isSVEAvailable()) {
auto [LegalCost, _] = getTypeLegalizationCost(ICA.getArgTypes()[0]);
// This should turn into chained clastb instructions.
return LegalCost;
}
break;
default:
break;
}
Expand Down Expand Up @@ -5325,6 +5332,7 @@ bool AArch64TTIImpl::isLegalToVectorizeReduction(
case RecurKind::FMax:
case RecurKind::FMulAdd:
case RecurKind::AnyOf:
case RecurKind::FindLast:
return true;
default:
return false;
Expand Down
35 changes: 34 additions & 1 deletion llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4047,6 +4047,7 @@ static bool willGenerateVectors(VPlan &Plan, ElementCount VF,
case VPDef::VPWidenIntrinsicSC:
case VPDef::VPWidenSC:
case VPDef::VPWidenSelectSC:
case VPDef::VPWidenSelectVectorSC:
case VPDef::VPBlendSC:
case VPDef::VPFirstOrderRecurrencePHISC:
case VPDef::VPHistogramSC:
Expand Down Expand Up @@ -4546,6 +4547,12 @@ LoopVectorizationPlanner::selectInterleaveCount(VPlan &Plan, ElementCount VF,
any_of(Plan.getVectorLoopRegion()->getEntryBasicBlock()->phis(),
IsaPred<VPReductionPHIRecipe>);

// FIXME: implement interleaving for FindLast transform correctly.
for (auto &[_, RdxDesc] : Legal->getReductionVars())
if (RecurrenceDescriptor::isFindLastRecurrenceKind(
RdxDesc.getRecurrenceKind()))
return 1;

// 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 @@ -8687,6 +8694,10 @@ VPlanPtr LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(
*Plan, Builder))
return nullptr;

// Create whole-vector selects for find-last recurrences.
VPlanTransforms::runPass(VPlanTransforms::convertFindLastRecurrences, *Plan,
RecipeBuilder, Legal);

if (useActiveLaneMask(Style)) {
// TODO: Move checks to VPlanTransforms::addActiveLaneMask once
// TailFoldingStyle is visible there.
Expand Down Expand Up @@ -8779,6 +8790,7 @@ void LoopVectorizationPlanner::adjustRecipesForReductions(

RecurKind Kind = PhiR->getRecurrenceKind();
assert(
!RecurrenceDescriptor::isFindLastRecurrenceKind(Kind) &&
!RecurrenceDescriptor::isAnyOfRecurrenceKind(Kind) &&
!RecurrenceDescriptor::isFindIVRecurrenceKind(Kind) &&
"AnyOf and FindIV reductions are not allowed for in-loop reductions");
Expand Down Expand Up @@ -8987,6 +8999,10 @@ void LoopVectorizationPlanner::adjustRecipesForReductions(
FinalReductionResult =
Builder.createNaryOp(VPInstruction::ComputeAnyOfResult,
{PhiR, Start, NewExitingVPV}, ExitDL);
} else if (RecurrenceDescriptor::isFindLastRecurrenceKind(
RdxDesc.getRecurrenceKind())) {
FinalReductionResult = Builder.createNaryOp(
VPInstruction::ExtractLastActive, {NewExitingVPV}, ExitDL);
} else {
VPIRFlags Flags =
RecurrenceDescriptor::isFloatingPointRecurrenceKind(RecurrenceKind)
Expand Down Expand Up @@ -9076,7 +9092,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 @@ -10069,6 +10086,22 @@ bool LoopVectorizePass::processLoop(Loop *L) {
// Override IC if user provided an interleave count.
IC = UserIC > 0 ? UserIC : IC;

// FIXME: Enable interleaving for last_active reductions.
if (any_of(LVL.getReductionVars(), [&](auto &Reduction) -> bool {
const RecurrenceDescriptor &RdxDesc = Reduction.second;
return RecurrenceDescriptor::isFindLastRecurrenceKind(
RdxDesc.getRecurrenceKind());
})) {
LLVM_DEBUG(dbgs() << "LV: Not interleaving without vectorization due "
<< "to conditional scalar assignments.\n");
IntDiagMsg = {
"ConditionalAssignmentPreventsScalarInterleaving",
"Unable to interleave without vectorization due to conditional "
"assignments"};
InterleaveLoop = false;
IC = 1;
}

// Emit diagnostic messages, if any.
const char *VAPassName = Hints.vectorizeAnalysisPassName();
if (!VectorizeLoop && !InterleaveLoop) {
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24868,6 +24868,7 @@ class HorizontalReduction {
case RecurKind::FindFirstIVUMin:
case RecurKind::FindLastIVSMax:
case RecurKind::FindLastIVUMax:
case RecurKind::FindLast:
case RecurKind::FMaxNum:
case RecurKind::FMinNum:
case RecurKind::FMaximumNum:
Expand Down Expand Up @@ -25009,6 +25010,7 @@ class HorizontalReduction {
case RecurKind::FindFirstIVUMin:
case RecurKind::FindLastIVSMax:
case RecurKind::FindLastIVUMax:
case RecurKind::FindLast:
case RecurKind::FMaxNum:
case RecurKind::FMinNum:
case RecurKind::FMaximumNum:
Expand Down Expand Up @@ -25115,6 +25117,7 @@ class HorizontalReduction {
case RecurKind::FindFirstIVUMin:
case RecurKind::FindLastIVSMax:
case RecurKind::FindLastIVUMax:
case RecurKind::FindLast:
case RecurKind::FMaxNum:
case RecurKind::FMinNum:
case RecurKind::FMaximumNum:
Expand Down
44 changes: 44 additions & 0 deletions llvm/lib/Transforms/Vectorize/VPlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,7 @@ class VPSingleDefRecipe : public VPRecipeBase, public VPValue {
case VPRecipeBase::VPWidenIntrinsicSC:
case VPRecipeBase::VPWidenSC:
case VPRecipeBase::VPWidenSelectSC:
case VPRecipeBase::VPWidenSelectVectorSC:
case VPRecipeBase::VPBlendSC:
case VPRecipeBase::VPPredInstPHISC:
case VPRecipeBase::VPCanonicalIVPHISC:
Expand Down Expand Up @@ -1059,6 +1060,8 @@ class LLVM_ABI_FOR_TEST VPInstruction : public VPRecipeWithIRFlags,
ResumeForEpilogue,
/// Returns the value for vscale.
VScale,
// Extracts the last active lane based on a predicate vector operand.
ExtractLastActive,
};

private:
Expand Down Expand Up @@ -1749,6 +1752,47 @@ struct LLVM_ABI_FOR_TEST VPWidenSelectRecipe : public VPRecipeWithIRFlags,

unsigned getOpcode() const { return Instruction::Select; }

VPValue *getCond() const { return getOperand(0); }

bool isInvariantCond() const {
return getCond()->isDefinedOutsideLoopRegions();
}

/// Returns true if the recipe only uses the first lane of operand \p Op.
bool onlyFirstLaneUsed(const VPValue *Op) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return Op == getCond() && isInvariantCond();
}
};

/// A recipe for selecting whole vector values.
struct VPWidenSelectVectorRecipe : public VPRecipeWithIRFlags {
VPWidenSelectVectorRecipe(ArrayRef<VPValue *> Operands)
: VPRecipeWithIRFlags(VPDef::VPWidenSelectVectorSC, Operands) {}

~VPWidenSelectVectorRecipe() override = default;

VPWidenSelectVectorRecipe *clone() override {
SmallVector<VPValue *, 3> Operands(operands());
return new VPWidenSelectVectorRecipe(Operands);
}

VP_CLASSOF_IMPL(VPDef::VPWidenSelectVectorSC)

/// Produce a widened version of the select instruction.
void execute(VPTransformState &State) override;

/// Return the cost of this VPWidenSelectVectorRecipe.
InstructionCost computeCost(ElementCount VF,
VPCostContext &Ctx) const override;

#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif

VPValue *getCond() const {
return getOperand(0);
}
Expand Down
9 changes: 7 additions & 2 deletions llvm/lib/Transforms/Vectorize/VPlanAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPInstruction *R) {
case VPInstruction::FirstActiveLane:
return Type::getIntNTy(Ctx, 64);
case VPInstruction::ExtractLastElement:
case VPInstruction::ExtractPenultimateElement: {
case VPInstruction::ExtractPenultimateElement:
case VPInstruction::ExtractLastActive: {
Type *BaseTy = inferScalarType(R->getOperand(0));
if (auto *VecTy = dyn_cast<VectorType>(BaseTy))
return VecTy->getElementType();
Expand Down Expand Up @@ -308,7 +309,11 @@ Type *VPTypeAnalysis::inferScalarType(const VPValue *V) {
})
.Case<VPExpressionRecipe>([this](const auto *R) {
return inferScalarType(R->getOperandOfResultType());
});
})
.Case<VPWidenSelectVectorRecipe>(
[this](const VPWidenSelectVectorRecipe *R) {
return inferScalarType(R->getOperand(1));
});

assert(ResultTy && "could not infer type for the given VPValue");
CachedTypes[V] = ResultTy;
Expand Down
Loading