52 const VectorizeOptions &Opts =
60 const VectorizeOptions &Opts =
62 return Opts.vplan_print_before_all || Opts.vplan_print_after_all ||
63 !Opts.vplan_print_before.empty() || !Opts.vplan_print_after.empty();
68 const VectorizeOptions &Opts =
70 bool All = After ? Opts.vplan_print_after_all : Opts.vplan_print_before_all;
72 After ? Opts.vplan_print_after : Opts.vplan_print_before;
77 dbgs() <<
"VPlan for loop in '" << Fn->
getName() <<
"' "
78 << (After ?
"after" :
"before") <<
" " << NumberedPassName <<
'\n';
82 dbgs() << Plan <<
'\n';
100 auto IsConsecutiveAccess = [&](
VPValue *Addr,
Type *AccessTy) {
109 if (!VPBB->getParent())
112 auto EndIter = Term ? Term->getIterator() : VPBB->end();
117 VPValue *VPV = Ingredient.getVPSingleValue();
133 IsConsecutiveAccess(VPI->getOperand(0), VPI->getScalarType());
135 nullptr , IsConsecutive,
136 *VPI, Ingredient.getDebugLoc());
138 bool IsConsecutive = IsConsecutiveAccess(
139 VPI->getOperand(1), VPI->getOperand(0)->getScalarType());
141 *
Store, Ingredient.getOperand(1), Ingredient.getOperand(0),
142 nullptr , IsConsecutive, *VPI, Ingredient.getDebugLoc());
145 Ingredient.operands(), *VPI,
146 Ingredient.getDebugLoc(),
GEP);
158 if (VectorID == Intrinsic::experimental_noalias_scope_decl)
163 if (VectorID == Intrinsic::assume ||
164 VectorID == Intrinsic::lifetime_end ||
165 VectorID == Intrinsic::lifetime_start ||
166 VectorID == Intrinsic::sideeffect ||
167 VectorID == Intrinsic::pseudoprobe) {
172 const bool IsSingleScalar = VectorID != Intrinsic::assume &&
173 VectorID != Intrinsic::pseudoprobe;
177 Ingredient.getDebugLoc());
179 assert(!CI->hasOperandBundles() &&
180 "calls with operand bundles must not be widened");
182 *CI, VectorID,
drop_end(Ingredient.operands()), CI->getType(),
183 VPIRFlags(*CI), *VPI, CI->getDebugLoc());
187 CI->getOpcode(), Ingredient.getOperand(0), CI->getType(), CI,
191 *VPI, Ingredient.getDebugLoc());
195 "inductions must be created earlier");
204 "Only recpies with zero or one defined values expected");
205 Ingredient.eraseFromParent();
216 const Loop *L =
nullptr;
221 if (
A->getOpcode() != Instruction::Store ||
222 B->getOpcode() != Instruction::Store)
235 const APInt *Distance;
241 Type *TyA =
A->getOperand(0)->getScalarType();
242 uint64_t SizeA =
DL.getTypeStoreSize(TyA);
243 Type *TyB =
B->getOperand(0)->getScalarType();
244 uint64_t SizeB =
DL.getTypeStoreSize(TyB);
249 uint64_t MaxStoreSize = std::max(SizeA, SizeB);
251 auto VFs =
B->getParent()->getPlan()->vectorFactors();
262 : ExcludeRecipes(ExcludeRecipes.begin(), ExcludeRecipes.end()),
263 GroupLeader(GroupLeader), PSE(&PSE), L(&L) {}
272 return ExcludeRecipes.contains(
Store) ||
273 (
Store && isNoAliasViaDistance(
Store, &GroupLeader));
286 std::optional<SinkStoreInfo> SinkInfo = {}) {
287 bool CheckReads = SinkInfo.has_value();
291 if (SinkInfo && SinkInfo->shouldSkip(R))
295 if (!
R.mayWriteToMemory() && !(CheckReads &&
R.mayReadFromMemory()))
314 return (IsLoad ? R : R->getOperand(0))->getScalarType();
320template <
unsigned Opcode>
325 static_assert(Opcode == Instruction::Load || Opcode == Instruction::Store,
326 "Only Load and Store opcodes supported");
327 constexpr bool IsLoad = (Opcode == Instruction::Load);
330 RecipesByAddressAndType;
334 if (RepR.getOpcode() != Opcode || !FilterFn(&RepR))
338 VPValue *Addr = RepR.getOperand(IsLoad ? 0 : 1);
342 RecipesByAddressAndType[{AddrSCEV, LoadStoreTy}].push_back(&RepR);
347 for (
auto &Group :
Groups) {
362 auto InsertIfValidSinkCandidate = [ScalarVFOnly, &WorkList](
369 if (Candidate->getParent() == SinkTo ||
370 all_of(Candidate->operands(),
371 [](
VPValue *
Op) { return Op->isDefinedOutsideLoopRegions(); }) ||
383 WorkList.
insert({SinkTo, Candidate});
395 for (
auto &Recipe : *VPBB)
397 InsertIfValidSinkCandidate(VPBB,
Op);
401 for (
unsigned I = 0;
I != WorkList.
size(); ++
I) {
404 std::tie(SinkTo, SinkCandidate) = WorkList[
I];
409 auto UsersOutsideSinkTo =
411 return cast<VPRecipeBase>(U)->getParent() != SinkTo;
413 if (
any_of(UsersOutsideSinkTo, [SinkCandidate](
VPUser *U) {
414 return !U->usesFirstLaneOnly(SinkCandidate);
417 bool NeedsDuplicating = !UsersOutsideSinkTo.empty();
419 if (NeedsDuplicating) {
423 if (
auto *SinkCandidateRepR =
428 SinkCandidateRepR->getOpcode(), SinkCandidate->
operands(),
429 nullptr, *SinkCandidateRepR, *SinkCandidateRepR,
434 Clone = SinkCandidate->
clone();
444 InsertIfValidSinkCandidate(SinkTo,
Op);
453 if (EntryBB->getNumSuccessors() != 2)
458 if (!Succ0 || !Succ1)
461 if (Succ0->getNumSuccessors() + Succ1->getNumSuccessors() != 1)
463 if (Succ0->getSingleSuccessor() == Succ1)
465 if (Succ1->getSingleSuccessor() == Succ0)
482 if (!Region1->isReplicator())
484 auto *MiddleBasicBlock =
486 if (!MiddleBasicBlock || !MiddleBasicBlock->empty())
491 if (!Region2 || !Region2->isReplicator())
494 VPValue *Mask1 = Region1->getEntryBranchOnMask()->getOperand(0);
495 VPValue *Mask2 = Region2->getEntryBranchOnMask()->getOperand(0);
496 if (!Mask1 || Mask1 != Mask2)
499 assert(Mask1 && Mask2 &&
"both region must have conditions");
505 if (TransformedRegions.
contains(Region1))
512 if (!Then1 || !Then2)
520 std::optional<VPExecutionFrequency> Freq1 =
523 if (Freq1 && Freq2) {
524 if (Freq2->Freq < Freq1->Freq) {
527 Freq1.emplace(Freq1->Freq, Freq1->IsEstimated || Freq2->IsEstimated);
551 VPValue *Phi1ToMoveV = Phi1ToMove.getVPSingleValue();
557 if (Phi1ToMove.getVPSingleValue()->user_empty()) {
558 Phi1ToMove.eraseFromParent();
561 Phi1ToMove.moveBefore(*Merge2, Merge2->begin());
575 TransformedRegions.
insert(Region1);
578 return !TransformedRegions.
empty();
586 std::string RegionName = (
Twine(
"pred.") + Instr->getOpcodeName()).str();
587 assert(Instr->getParent() &&
"Predicated instruction not in any basic block");
588 auto *BlockInMask = PredRecipe->
getMask();
603 BOMRecipe->setExecutionFrequency(RecipeWithoutMask->getExecutionFrequency(),
605 RecipeWithoutMask->clearExecutionFrequency();
614 Region->setParent(ParentRegion);
622 if (RecipeWithoutMask->getScalarType()->isStructTy())
623 Defs =
to_vector(RecipeWithoutMask->users());
626 assert((Def == RecipeWithoutMask ||
627 Def->getOpcode() == Instruction::ExtractValue) &&
628 "only extracts can use a predicated struct");
629 Def->moveBefore(*Pred, Pred->end());
630 if (Def->user_empty())
633 Exiting->appendRecipe(PHIRecipe);
634 Def->replaceAllUsesWith(PHIRecipe);
635 PHIRecipe->setOperand(0, Def);
646 if (RepR.isPredicated())
664 if (ParentRegion && ParentRegion->
getExiting() == CurrentBlock)
676 if (!VPBB->getParent())
688 R.moveBefore(*PredVPBB, PredVPBB->
end());
690 auto *ParentRegion = VPBB->getParent();
691 if (ParentRegion && ParentRegion->getExiting() == VPBB)
692 ParentRegion->setExiting(PredVPBB);
696 return !WorkList.
empty();
703 bool ShouldSimplify =
true;
704 while (ShouldSimplify) {
721 if (
IV.isTruncated())
736 for (
auto *U : FindMyCast->
users()) {
738 if (UserCast && UserCast->getUnderlyingValue() == IRCast) {
739 FoundUserCast = UserCast;
746 FindMyCast = FoundUserCast;
748 if (FindMyCast != &
IV)
773 PhiR->replaceAllUsesWith(PhiR->getOperand(0));
775 PhiR->eraseFromParent();
841 Def->user_empty() || !Def->getUnderlyingValue() ||
842 (RepR && (RepR->isSingleScalar() || RepR->isPredicated())))
855 Def->getUnderlyingInstr()->getOpcode(), Def->operands(),
857 Def->getScalarType(), Def->getUnderlyingInstr());
858 Clone->insertAfter(Def);
859 Def->replaceAllUsesWith(Clone);
860 Def->eraseFromParent();
875 PtrIV->replaceAllUsesWith(PtrAdd);
882 if (HasOnlyVectorVFs &&
none_of(WideIV->users(), [WideIV](
VPUser *U) {
883 return U->usesScalars(WideIV);
894 Plan, ID.getKind(), ID.getInductionOpcode(),
896 WideIV->getScalarType(), WideIV->getStartValue(),
897 WideIV->getStepValue(), WideIV->getDebugLoc(), Builder, WrapFlags);
900 if (!HasOnlyVectorVFs) {
902 "plans containing a scalar VF cannot also include scalable VFs");
903 WideIV->replaceAllUsesWith(Steps);
906 WideIV->replaceUsesWithIf(Steps, [WideIV, HasScalableVF](
VPUser *U) {
908 return U->usesFirstLaneOnly(WideIV);
909 return U->usesScalars(WideIV);
925 return (IntOrFpIV && IntOrFpIV->isTruncated()) ? nullptr : WideIV;
930 if (!Def || Def->getNumOperands() != 2)
938 auto IsWideIVInc = [&]() {
939 auto &ID = WideIV->getInductionDescriptor();
942 VPValue *IVStep = WideIV->getStepValue();
943 switch (ID.getInductionOpcode()) {
944 case Instruction::Add:
946 case Instruction::FAdd:
948 case Instruction::FSub:
951 case Instruction::Sub: {
971 return IsWideIVInc() ? WideIV :
nullptr;
995 VPValue *FirstActiveLane =
B.createFirstActiveLane(Mask,
DL);
997 B.createScalarZExtOrTrunc(FirstActiveLane, CanonicalIVType,
DL);
998 VPValue *EndValue =
B.createAdd(CanonicalIV, FirstActiveLane,
DL);
1003 if (Incoming != WideIV) {
1005 EndValue =
B.createAdd(EndValue, One,
DL);
1010 VPValue *Start = WideIV->getStartValue();
1011 VPValue *Step = WideIV->getStepValue();
1012 EndValue =
B.createDerivedIV(
1014 Start, EndValue, Step);
1028 if (WideIntOrFp && WideIntOrFp->isTruncated())
1038 Start, VectorTC, Step);
1070 assert(EndValue &&
"Must have computed the end value up front");
1075 if (Incoming != WideIV)
1087 auto *Zero = Plan.
getZero(StepTy);
1088 return B.createPtrAdd(EndValue,
B.createSub(Zero, Step),
1093 return B.createNaryOp(
1094 ID.getInductionBinOp()->getOpcode() == Instruction::FAdd
1096 : Instruction::FAdd,
1097 {EndValue, Step}, {ID.getInductionBinOp()->getFastMathFlags()});
1114 const SCEV *Start, *Step;
1132 VPValue *ExitCount = Builder.createOverflowingOp(
1135 return Builder.createDerivedIV(Kind,
nullptr, StartVPV, ExitCount,
1144 VPBuilder VectorPHBuilder(VectorPH, VectorPH->getFirstNonPhi());
1151 &WideIV, VectorPHBuilder, ResumeTC))
1152 EndValues[&WideIV] = EndValue;
1162 R.getVPSingleValue()->replaceAllUsesWith(EndValue);
1163 R.eraseFromParent();
1172 for (
auto [Idx, PredVPBB] :
enumerate(ExitVPBB->getPredecessors())) {
1174 if (PredVPBB == MiddleVPBB) {
1176 Plan, ExitIRI->getOperand(Idx), EndValues, PSE);
1179 Plan, ExitIRI->getOperand(Idx), PSE, ResumeTC, L);
1182 Plan, ExitIRI->getOperand(Idx), PSE);
1185 ExitIRI->setOperand(Idx, Escape);
1197 const auto &[V, Inserted] = SCEV2VPV.
try_emplace(ExpR.getSCEV(), &ExpR);
1201 ExpR.replaceAllUsesWith(V->second);
1205 ExpR.eraseFromParent();
1227 return Plan.
getZero(Def->getScalarType());
1244 return Def->getOperand(1);
1255 assert(
X->getScalarType()->isIntegerTy(1) &&
"must have boolean operands");
1271 assert(Weights.
size() == 2 &&
"unexpected branch weights");
1273 LLVMContext::MD_prof,
1305 return Plan.
getZero(Def->getScalarType());
1309 Def->getScalarType() ==
A->getScalarType())
1319 if (Def->getScalarType() ==
A->getScalarType())
1329 A->getScalarType() == Def->getScalarType())
1335 return Def->getOperand(0);
1341 return BuildVector->getLastOperand();
1358 return BuildVector->getOperand(BuildVector->getNumOperands() - 2);
1364 return BuildVector->getOperand(Idx);
1368 if (Def->getNumOperands() == 1) {
1369 return Def->getOperand(0);
1373 return Phi->getOperand(0);
1379 if (Def->getNumOperands() == 1 &&
1385 A->getScalarType() == Def->getScalarType())
1397 return Def->getOperand(1);
1409 return VPR->getOperand(0);
1415 return Steps->getOperand(0);
1433struct VPCombineInserter {
1434 SmallVectorImpl<VPSingleDefRecipe *> &Worklist;
1436 void insertHelper(VPRecipeBase *R, VPBasicBlock *VPBB,
1450 VPCombineBuilder &Builder) {
1452 Def->replaceAllUsesWith(V);
1461 RepR && RepR->isPredicated() && RepR->getOpcode() == Instruction::Store &&
1465 RepR->getUnderlyingInstr(), RepR->operandsWithoutMask(),
1466 RepR->isSingleScalar(),
nullptr, *RepR, *RepR,
1467 RepR->getDebugLoc());
1468 Builder.insert(Unmasked);
1480 bool CanCreateNewRecipe =
1486 if (CanCreateNewRecipe &&
1489 return Builder.createLogicalAnd(
X,
Y);
1492 if (CanCreateNewRecipe &&
1497 (!Def->getOperand(0)->hasMoreThanOneUniqueUser() ||
1498 !Def->getOperand(1)->hasMoreThanOneUniqueUser()))
1499 return Builder.createLogicalAnd(
X, Builder.createOr(
Y, Z));
1502 if (CanCreateNewRecipe &&
1506 return Builder.createLogicalOr(Z,
Y);
1510 if (CanCreateNewRecipe &&
1512 return Builder.createNot(
C);
1516 Def->setOperand(0,
C);
1517 Def->setOperand(1,
Y);
1518 Def->setOperand(2,
X);
1524 if (CanCreateNewRecipe &&
1528 Y->getScalarType()->isIntegerTy(1))
1529 return Builder.createOr(
Y, Builder.createLogicalAnd(
X, Z));
1533 if (CanCreateNewRecipe &&
1539 return Builder.createSelect(Builder.createLogicalAnd(Mask0, Mask1),
X,
Y,
1540 Def->getDebugLoc());
1546 Type *TruncTy = Def->getScalarType();
1547 Type *XTy =
X->getScalarType();
1550 unsigned ExtOpcode =
1554 if (
auto *UnderlyingExt =
Y->getUnderlyingValue()) {
1556 Ext->setUnderlyingValue(UnderlyingExt);
1560 auto *Trunc = Builder.createWidenCast(Instruction::Trunc,
X, TruncTy);
1569 return Builder.createSub(Plan.
getZero(
X->getScalarType()),
X,
1570 Def->getDebugLoc(),
"", NW);
1573 if (CanCreateNewRecipe &&
1581 return Builder.createSub(
X,
Y, Def->getDebugLoc(),
"", NW);
1588 Def->getDebugLoc());
1595 MulR->hasNoSignedWrap() &&
1597 return Builder.createNaryOp(
1600 Def->getDebugLoc());
1605 return Builder.createNaryOp(
1611 if (CanCreateNewRecipe &&
1614 return Builder.createAnd(
1616 Def->getDebugLoc());
1626 return match(U, m_Not(m_Specific(Cmp))) ||
1627 (match(U, m_Select(m_Specific(Cmp), m_VPValue(),
1629 U->getOperand(1) != Cmp && U->getOperand(2) != Cmp);
1636 R->setOperand(1,
Y);
1637 R->setOperand(2,
X);
1642 R->replaceAllUsesWith(Cmp);
1647 if (!Cmp->getDebugLoc() && Def->getDebugLoc())
1648 Cmp->setDebugLoc(Def->getDebugLoc());
1661 if (
Op->getNumUsers() > 1 ||
1665 }
else if (!UnpairedCmp) {
1666 UnpairedCmp =
Op->getDefiningRecipe();
1670 UnpairedCmp =
nullptr;
1677 if (NewOps.
size() < Def->getNumOperands())
1684 if (CanCreateNewRecipe &&
1689 X->getScalarType() ==
Y->getScalarType())
1694 X->getScalarType() != Def->getScalarType())
1695 return Builder.createWidenCast(Instruction::Trunc,
X, Def->getScalarType());
1702 Def->getScalarType()->isIntegerTy(1)) {
1703 Def->setOperand(1, Plan.
getTrue());
1704 Def->setOperand(0,
Y);
1714 Def->replaceUsesWithIf(Def->getOperand(0), [Def](
VPUser *U) {
1715 return U->usesFirstLaneOnly(Def);
1725 "broadcast operand must be single-scalar");
1726 Def->setOperand(0, Z);
1731 Def->replaceUsesWithIf(
1732 X, [Def](
const VPUser *U) {
return U->usesScalars(Def); });
1744 return Builder.createNaryOp(Instruction::ExtractElement, {
X, LaneToExtract},
1745 Def->getDebugLoc());
1757 IVInc->getNumUsers() == 2) {
1763 if ((Phi->getNumUsers() == 1 || (Phi->getNumUsers() == 2 && Inc)) &&
1765 Def->replaceAllUsesWith(IVInc);
1767 Inc->replaceAllUsesWith(Phi);
1768 Phi->setOperand(0,
Y);
1777 Def->replaceUsesWithIf(StartV, [](
const VPUser *U) {
1779 return PhiR && PhiR->isInLoop();
1796 [[maybe_unused]]
unsigned InitWorklistSize = Worklist.
size();
1798 VPCombineBuilder Builder({Worklist});
1799 while (!Worklist.
empty()) {
1800 assert(Worklist.
size() < InitWorklistSize * 2 &&
1801 "Worklist is growing large, possible cycle?");
1803 Builder.setInsertPoint(Def);
1809 Def->replaceAllUsesWith(New);
1810 Def->eraseFromParent();
1814 Def->eraseFromParent();
1832 R.getVPSingleValue()->replaceAllUsesWith(
X);
1848 while (!Worklist.
empty()) {
1857 R->replaceAllUsesWith(
1858 Builder.createLogicalAnd(HeaderMask, Builder.createLogicalAnd(
X,
Y)));
1862static std::optional<Instruction::BinaryOps>
1865 case Intrinsic::masked_udiv:
1866 return Instruction::UDiv;
1867 case Intrinsic::masked_sdiv:
1868 return Instruction::SDiv;
1869 case Intrinsic::masked_urem:
1870 return Instruction::URem;
1871 case Intrinsic::masked_srem:
1872 return Instruction::SRem;
1889 if (RepR && (RepR->isSingleScalar() || RepR->isPredicated()))
1893 if (RepR && RepR->getOpcode() == Instruction::Store &&
1896 RepOrWidenR->getUnderlyingInstr(), RepOrWidenR->operands(),
1897 true ,
nullptr , *RepR ,
1898 *RepR , RepR->getDebugLoc());
1899 Clone->insertBefore(RepOrWidenR);
1901 VPValue *ExtractOp = Clone->getOperand(0);
1907 Clone->setOperand(0, ExtractOp);
1908 RepR->eraseFromParent();
1920 VPValue *SafeDivisor = Builder.createSelect(
1921 IntrR->getOperand(2), IntrR->getOperand(1),
1923 VPValue *Clone = Builder.createNaryOp(
1924 *
Opc, {IntrR->getOperand(0), SafeDivisor},
1927 IntrR->eraseFromParent();
1936 auto IntroducesBCastOf = [](
const VPValue *
Op) {
1945 return !U->usesScalars(
Op);
1949 if (
any_of(RepOrWidenR->users(), IntroducesBCastOf(RepOrWidenR)) &&
1952 make_filter_range(Op->users(), not_equal_to(RepOrWidenR)),
1953 IntroducesBCastOf(Op)))
1957 bool LiveInNeedsBroadcast =
1958 isa<VPIRValue>(Op) && !isa<VPConstant>(Op);
1959 auto *OpR = dyn_cast<VPReplicateRecipe>(Op);
1960 return LiveInNeedsBroadcast || (OpR && OpR->isSingleScalar());
1968 RepOrWidenR->getUnderlyingInstr());
1969 Clone->insertBefore(RepOrWidenR);
1970 RepOrWidenR->replaceAllUsesWith(Clone);
1972 RepOrWidenR->eraseFromParent();
2005 if (Blend.isNormalized() || !
match(Blend.getMask(0),
m_False()))
2006 UniqueValues.
insert(Blend.getIncomingValue(0));
2007 for (
unsigned I = 1;
I != Blend.getNumIncomingValues(); ++
I)
2009 UniqueValues.
insert(Blend.getIncomingValue(
I));
2011 if (UniqueValues.
size() == 1) {
2012 Blend.replaceAllUsesWith(*UniqueValues.
begin());
2013 Blend.eraseFromParent();
2017 if (Blend.isNormalized())
2023 unsigned StartIndex = 0;
2024 for (
unsigned I = 0;
I != Blend.getNumIncomingValues(); ++
I) {
2036 OperandsWithMask.
push_back(Blend.getIncomingValue(StartIndex));
2038 for (
unsigned I = 0;
I != Blend.getNumIncomingValues(); ++
I) {
2039 if (
I == StartIndex)
2041 OperandsWithMask.
push_back(Blend.getIncomingValue(
I));
2042 OperandsWithMask.
push_back(Blend.getMask(
I));
2047 OperandsWithMask, Blend, Blend.getDebugLoc());
2048 NewBlend->insertBefore(&Blend);
2050 VPValue *DeadMask = Blend.getMask(StartIndex);
2052 Blend.eraseFromParent();
2057 if (NewBlend->getNumOperands() == 3 &&
2059 VPValue *Inc0 = NewBlend->getOperand(0);
2060 VPValue *Inc1 = NewBlend->getOperand(1);
2061 VPValue *OldMask = NewBlend->getOperand(2);
2062 NewBlend->setOperand(0, Inc1);
2063 NewBlend->setOperand(1, Inc0);
2064 NewBlend->setOperand(2, NewMask);
2091 APInt MaxVal = AlignedTC - 1;
2094 unsigned NewBitWidth =
2100 bool MadeChange =
false;
2125 "canonical IV is not expected to have a truncation");
2130 NewWideIV->insertBefore(WideIV);
2137 Cmp->replaceAllUsesWith(
2138 VPBuilder(Cmp).createICmp(Cmp->getPredicate(), NewWideIV, NewBTC));
2152 return any_of(
Cond->getDefiningRecipe()->operands(), [&Plan, BestVF, BestUF,
2154 return isConditionTrueViaVFAndUF(C, Plan, BestVF, BestUF, PSE);
2168 const SCEV *VectorTripCount =
2173 "Trip count SCEV must be computable");
2188 bool MadeChange =
false;
2196 for (
VPBasicBlock *VPBB : {PreheaderVPBB, ExitingVPBB}) {
2205 Builder.setInsertPoint(Extract);
2208 Start = Builder.createAdd(
2213 Extract->eraseFromParent();
2228 auto *Term = &ExitingVPBB->
back();
2234 bool MatchedCanIVInc =
2240 if (MatchedCanIVInc ||
2248 const SCEV *VectorTripCount =
2254 "Trip count SCEV must be computable");
2273 Term->setOperand(1, Plan.
getTrue());
2278 {}, Term->getDebugLoc());
2280 Term->eraseFromParent();
2288 assert(Plan.
hasVF(BestVF) &&
"BestVF is not available in Plan");
2289 assert(Plan.
hasUF(BestUF) &&
"BestUF is not available in Plan");
2305 RecurKind RK = PhiR.getRecurrenceKind();
2312 RecWithFlags->dropPoisonGeneratingFlags();
2318struct VPCSEDenseMapInfo :
public DenseMapInfo<VPSingleDefRecipe *> {
2327 return GEP->getSourceElementType();
2330 .Case<VPVectorPointerRecipe, VPWidenGEPRecipe>(
2331 [](
auto *
I) {
return I->getSourceElementType(); })
2332 .
Default([](
auto *) {
return nullptr; });
2336 static bool canHandle(
const VPSingleDefRecipe *Def) {
2343 if (!
C || (!
C->first &&
C->second == Instruction::Alloca))
2349 if (
Def->mayWriteToMemory())
2351 return !
Def->mayReadFromMemory() ||
2356 static unsigned getHashValue(
const VPSingleDefRecipe *Def) {
2359 getGEPSourceElementType(Def),
Def->getScalarType(),
2362 if (RFlags->hasPredicate())
2365 return hash_combine(Result, SIVSteps->getInductionOpcode());
2374 static bool isEqual(
const VPSingleDefRecipe *L,
const VPSingleDefRecipe *R) {
2375 if (
L->getVPRecipeID() !=
R->getVPRecipeID() ||
2378 getGEPSourceElementType(L) != getGEPSourceElementType(R) ||
2380 !
equal(
L->operands(),
R->operands()))
2384 "must have valid opcode info for both recipes");
2386 if (LFlags->hasPredicate() &&
2387 LFlags->getPredicate() !=
2391 if (LSIV->getInductionOpcode() !=
2406 const VPRegionBlock *RegionL =
L->getRegion();
2407 const VPRegionBlock *RegionR =
R->getRegion();
2410 L->getParent() !=
R->getParent())
2412 return L->getScalarType() ==
R->getScalarType();
2430 if (R.mayWriteToMemory())
2433 if (!Def || !VPCSEDenseMapInfo::canHandle(Def))
2436 auto [It, Inserted] =
2437 (IsLoad ? LoadCSEMap : CSEMap).try_emplace(Def, Def);
2442 if (!VPDT.
dominates(V->getParent(), VPBB))
2447 if (EarlierLoad->getAlign() <
Load->getAlign()) {
2454 EarlierLoad->intersect(*
Load);
2462 Def->replaceAllUsesWith(V);
2473 bool Sinking =
false) {
2502 "Expected vector prehader's successor to be the vector loop region");
2510 return !Op->isDefinedOutsideLoopRegions();
2516 R.moveBefore(*Preheader, Preheader->
end());
2534 assert(!RepR->isPredicated() &&
2535 "Expected prior transformation of predicated replicates to "
2536 "replicate regions");
2541 if (!RepR->isSingleScalar())
2545 if (RepR->getOpcode() == Instruction::Store &&
2546 !RepR->getOperand(1)->isDefinedOutsideLoopRegions())
2554 if (
any_of(Def->users(), [&SinkBB, &LoopRegion](
VPUser *U) {
2555 auto *UserR = cast<VPRecipeBase>(U);
2556 VPBasicBlock *Parent = UserR->getParent();
2558 if (SinkBB && SinkBB != Parent)
2563 return UserR->isPhi() || Parent->getEnclosingLoopRegion() ||
2564 Parent->getSinglePredecessor() != LoopRegion;
2574 assert((!R.mayWriteToMemory() ||
2575 (RepR && RepR->getOpcode() == Instruction::Store &&
2576 RepR->getOperand(1)->isDefinedOutsideLoopRegions())) &&
2577 "The only recipes that may write to memory are expected to be "
2578 "stores with invariant pointer-operand");
2586 "Defining block must dominate sink block");
2611 VPValue *ResultVPV = R.getVPSingleValue();
2613 unsigned NewResSizeInBits = MinBWs.
lookup(UI);
2614 if (!NewResSizeInBits)
2627 (void)OldResSizeInBits;
2635 VPW->dropPoisonGeneratingFlags();
2637 assert((OldResSizeInBits != NewResSizeInBits ||
2639 "Only ICmps should not need extending the result.");
2652 unsigned OpSizeInBits =
Op->getScalarType()->getScalarSizeInBits();
2653 if (OpSizeInBits == NewResSizeInBits)
2655 assert(OpSizeInBits > NewResSizeInBits &&
"nothing to truncate");
2656 auto [ProcessedIter, Inserted] = ProcessedTruncs.
try_emplace(
Op);
2660 Builder.setInsertPoint(PH);
2662 Builder.setInsertPoint(&R);
2663 ProcessedIter->second =
2664 Builder.createWidenCast(Instruction::Trunc,
Op, NewResTy);
2666 Op = ProcessedIter->second;
2670 NWR->insertBefore(&R);
2675 VPValue *Replacement = NWR->getVPSingleValue();
2682 R.eraseFromParent();
2688 std::optional<VPDominatorTree> VPDT;
2696 bool SimplifiedPhi =
false;
2707 "Two successors expected for BranchOnCond");
2708 unsigned RemovedIdx;
2719 "There must be a single edge between VPBB and its successor");
2724 SimplifiedPhi =
true;
2728 if (!PhiR || PhiR->getNumIncoming() != 1)
2730 PhiR->replaceAllUsesWith(PhiR->getOperand(0));
2731 PhiR->eraseFromParent();
2748 if (Reachable.contains(
B))
2759 for (
VPValue *Def : R.definedValues())
2760 Def->replaceAllUsesWith(&Tmp);
2761 R.eraseFromParent();
2765 return SimplifiedPhi;
2793 auto GetSimplifiedLiveInViaSCEV = [&](
VPValue *VPV) ->
VPValue * {
2802 if (
VPValue *SimplifiedLiveIn = GetSimplifiedLiveInViaSCEV(LiveIn))
2803 LiveIn->replaceAllUsesWith(SimplifiedLiveIn);
2814 "expected to run before loop regions are created");
2816 auto CanUseVersionedStride = [&VPDT, Header = Header, &Plan](
VPUser *U) {
2822 return VPDT.
dominates(Header, R->getParent());
2826 Value *StrideV = Stride->getValue();
2827 const APInt *StrideConst;
2834 CanUseVersionedStride);
2848 CanUseVersionedStride);
2850 RewriteMap[StrideV] = StrideExpr;
2855 const SCEV *ScevExpr = ExpSCEV.getSCEV();
2858 if (NewSCEV != ScevExpr) {
2860 ExpSCEV.replaceAllUsesWith(NewExp);
2871 auto CollectPoisonGeneratingInstrsInBackwardSlice([&](
VPRecipeBase *Root) {
2876 while (!Worklist.
empty()) {
2879 if (!Visited.
insert(CurRec).second)
2901 RecWithFlags->isDisjoint()) {
2904 Builder.createAdd(
A,
B, RecWithFlags->getDebugLoc());
2905 New->setUnderlyingValue(RecWithFlags->getUnderlyingValue());
2906 RecWithFlags->replaceAllUsesWith(New);
2907 RecWithFlags->eraseFromParent();
2910 RecWithFlags->dropPoisonGeneratingFlags();
2915 assert((!Instr || !Instr->hasPoisonGeneratingFlags()) &&
2916 "found instruction with poison generating flags not covered by "
2917 "VPRecipeWithIRFlags");
2922 if (
VPRecipeBase *OpDef = Operand->getDefiningRecipe())
2944 VPRecipeBase *AddrDef = WidenRec->getAddr()->getDefiningRecipe();
2945 if (AddrDef && WidenRec->isConsecutive() && WidenRec->getMask() &&
2946 match(WidenRec->getMask(), m_UnlessHdrMask))
2947 CollectPoisonGeneratingInstrsInBackwardSlice(AddrDef);
2949 VPRecipeBase *AddrDef = InterleaveRec->getAddr()->getDefiningRecipe();
2950 if (AddrDef && InterleaveRec->getMask() &&
2951 match(InterleaveRec->getMask(), m_UnlessHdrMask))
2952 CollectPoisonGeneratingInstrsInBackwardSlice(AddrDef);
2962 const bool &EpilogueAllowed) {
2963 if (InterleaveGroups.empty())
2974 IRMemberToRecipe[&MemR->getIngredient()] = MemR;
2981 for (
const auto *IG : InterleaveGroups) {
2984 for (
auto *Member : IG->members())
2986 StartMember = Member;
2994 for (
unsigned I = 0;
I < IG->getFactor(); ++
I) {
3000 StoredValues.
push_back(StoreR->getStoredValue());
3007 bool NeedsMaskForGaps =
3008 (IG->requiresScalarEpilogue() && !EpilogueAllowed) ||
3009 (!StoredValues.
empty() && !IG->isFull());
3012 auto *InsertPos = IRMemberToRecipe.
lookup(IRInsertPos);
3016 "Dead member in non-load group?");
3021 InsertPos->getAsRecipe()))
3022 InsertPos = MemberR;
3023 IRInsertPos = &InsertPos->getIngredient();
3033 VPValue *Addr = Start->getAddr();
3035 if (IG->getIndex(StartMember) != 0 ||
3043 assert(IG->getIndex(IRInsertPos) != 0 &&
3044 "index of insert position shouldn't be zero");
3048 IG->getIndex(IRInsertPos),
3052 Addr =
B.createNoWrapPtrAdd(InsertPos->getAddr(), OffsetVPV, NW);
3058 if (IG->isReverse()) {
3061 -(int64_t)IG->getFactor(), NW, InsertPosR->
getDebugLoc());
3062 ReversePtr->insertBefore(InsertPosR);
3066 IG, Addr, StoredValues, InsertPos->getMask(), NeedsMaskForGaps,
3068 VPIG->insertBefore(InsertPosR);
3071 for (
unsigned i = 0; i < IG->getFactor(); ++i)
3074 if (!Member->getType()->isVoidTy()) {
3096struct CountableConditionMatch {
3098 PredicatedScalarEvolution &PSE;
3101 CountableConditionMatch(VPValue *&Cmp, PredicatedScalarEvolution &PSE,
3105 template <
typename ITy>
bool match(ITy *V)
const {
3125 return CountableConditionMatch(Cmp, PSE, L);
3144 VPValue *Uncountable =
nullptr;
3161 if (ExitBlocks.
size() != 1)
3168 if (!ExitBlocks.
front()->phis().empty())
3184 LatchVPBB->clearSuccessors();
3194 Term->setOperand(0, Countable);
3258 VPValue *UncountableCondition =
nullptr;
3265 Worklist.
push_back(UncountableCondition);
3266 while (!Worklist.
empty()) {
3270 if (V->isDefinedOutsideLoopRegions())
3303 if (Recipes.
empty() ||
3307 return UncountableCondition;
3362 for (
auto &Exit : Exits) {
3363 if (Exit.EarlyExitingVPBB == LatchVPBB)
3367 cast<VPIRPhi>(&R)->removeIncomingValueFor(Exit.EarlyExitingVPBB);
3368 Exit.EarlyExitingVPBB->getTerminator()->eraseFromParent();
3382 "loop with side effects",
3383 "EarlyExitSideEffectsCond", ORE, TheLoop);
3398 assert(
Load &&
"Couldn't find exactly one load");
3401 "Uncountable exit condition load is conditional.");
3415 DL.getTypeStoreSize(
Load->getScalarType()).getFixedValue());
3421 "load used by the exit condition that may "
3423 "EarlyExitSideEffectsFaultingLoad", ORE,
3436 "load used by the exit condition with an "
3437 "unsupported memory access pattern",
3438 "EarlyExitSideEffectsBadLoadAccessPattern", ORE,
3446 "load used by the exit condition with an "
3447 "unsupported memory access pattern",
3448 "EarlyExitSideEffectsBadLoadAccessPattern", ORE,
3458 while (InsertIt != HeaderVPBB->
end() &&
3460 erase(ConditionRecipes, &*InsertIt);
3463 for (
auto *Recipe :
reverse(ConditionRecipes))
3464 Recipe->moveBefore(*HeaderVPBB, InsertIt);
3468 VPBuilder MaskBuilder(HeaderVPBB, InsertIt);
3470 Type *IVScalarTy =
IV->getScalarType();
3476 "uncountable.exit.mask");
3481 if (R.mayReadOrWriteMemory() && &R !=
Load) {
3483 if (!VPDT.
dominates(R.getParent(), LatchVPBB)) {
3485 "Early exit loop with side effects contains unsupported "
3486 "conditional memory operations",
3487 "EarlyExitSideEffectsUnsupportedConditionalMemOps", ORE, TheLoop);
3498 "Expected BranchOnCond terminator for MiddleVPBB");
3509 auto Phis = ScalarPH->
phis();
3514 "Early exit loop with side effects contains "
3515 "unsupported reductions, inductions or recurrences",
3516 "EarlyExitSideEffectsReductions", ORE, TheLoop);
3524 "Continuing from different IV");
3560 "Auto-vectorization of early exit loops with potentially "
3561 "faulting loads is not supported",
3562 "EarlyExitFaultingLoads", ORE, TheLoop);
3566 VPBuilder LatchBuilder(LatchVPBB->getTerminator());
3568 for (
auto [EarlyExitingVPBB, ExitBlock] :
3572 VPValue *CondOfEarlyExitingVPBB;
3573 [[maybe_unused]]
bool Matched =
3574 match(EarlyExitingVPBB->getTerminator(),
3576 assert(Matched &&
"Terminator must be BranchOnCond");
3580 VPBuilder EarlyExitingBuilder(EarlyExitingVPBB->getTerminator());
3581 auto *CondToEarlyExit = EarlyExitingBuilder.
createNaryOp(
3583 TrueSucc == ExitBlock
3584 ? CondOfEarlyExitingVPBB
3585 : EarlyExitingBuilder.
createNot(CondOfEarlyExitingVPBB));
3591 "exit condition must dominate the latch");
3599 assert(!Exits.
empty() &&
"must have at least one early exit");
3606 for (
const auto &[Num, VPB] :
enumerate(RPOT))
3609 return RPOIdx[
A.EarlyExitingVPBB] < RPOIdx[
B.EarlyExitingVPBB];
3615 for (
unsigned I = 0;
I + 1 < Exits.
size(); ++
I)
3616 for (
unsigned J =
I + 1; J < Exits.
size(); ++J)
3618 Exits[
I].EarlyExitingVPBB) &&
3619 "RPO sort must place dominating exits before dominated ones");
3625 VPValue *Combined = Exits[0].CondToExit;
3647 "Unexpected terminator");
3648 VPValue *IsLatchExitTaken = LatchExitingBranch->getOperand(0);
3649 DebugLoc LatchDL = LatchExitingBranch->getDebugLoc();
3650 LatchExitingBranch->eraseFromParent();
3653 {IsAnyExitTaken, IsLatchExitTaken}, LatchDL);
3654 LatchVPBB->clearSuccessors();
3659 LatchVPBB->setSuccessors({MiddleVPBB, MiddleVPBB, HeaderVPBB});
3660 MiddleVPBB->clearPredecessors();
3661 MiddleVPBB->setPredecessors({LatchVPBB, LatchVPBB});
3663 LatchVPBB, MiddleVPBB, ORE,
3664 TheLoop, PSE, DT, AC);
3669 for (
unsigned Idx = 0; Idx != Exits.
size(); ++Idx) {
3673 VectorEarlyExitVPBBs[Idx] = VectorEarlyExitVPBB;
3681 Exits.
size() == 1 ? VectorEarlyExitVPBBs[0]
3684 LatchVPBB->setSuccessors({DispatchVPBB, MiddleVPBB, HeaderVPBB});
3716 for (
auto [Exit, VectorEarlyExitVPBB] :
3717 zip_equal(Exits, VectorEarlyExitVPBBs)) {
3718 auto &[EarlyExitingVPBB, EarlyExitVPBB,
_] = Exit;
3730 ExitIRI->getIncomingValueForBlock(EarlyExitingVPBB);
3731 VPValue *NewIncoming = IncomingVal;
3733 VPBuilder EarlyExitBuilder(VectorEarlyExitVPBB);
3738 ExitIRI->removeIncomingValueFor(EarlyExitingVPBB);
3739 ExitIRI->addIncoming(NewIncoming);
3742 EarlyExitingVPBB->getTerminator()->eraseFromParent();
3777 bool IsLastDispatch = (
I + 2 == Exits.
size());
3779 IsLastDispatch ? VectorEarlyExitVPBBs.
back()
3785 VectorEarlyExitVPBBs[
I]->setPredecessors({CurrentBB});
3788 CurrentBB = FalseBB;
3803 VPValue *VecOp = Red->getVecOp();
3806 if (Red->isPartialReduction())
3810 auto IsExtendedRedValidAndClampRange =
3823 "getExtendedReductionCost only supports integer types");
3824 ExtRedCost = Ctx.TTI.getExtendedReductionCost(
3825 Opcode, ExtOpc == Instruction::CastOps::ZExt, RedTy, SrcVecTy,
3826 Red->getFastMathFlagsOrNone(),
CostKind);
3827 return ExtRedCost.
isValid() && ExtRedCost < ExtCost + RedCost;
3835 IsExtendedRedValidAndClampRange(
3855 Type *LHSSrcTy =
LHS->getOperand(0)->getScalarType();
3857 Type *RHSSrcTy =
RHS ?
RHS->getOperand(0)->getScalarType() : LHSSrcTy;
3859 if (
Mul->getScalarType()->getScalarSizeInBits() >=
3862 if (ExtKind == ExtendKind::PR_ZeroExtend)
3863 return Mul->hasNoUnsignedWrap();
3864 return ExtKind == ExtendKind::PR_SignExtend &&
Mul->hasNoSignedWrap();
3880 if (Opcode != Instruction::Add && Opcode != Instruction::Sub &&
3881 Opcode != Instruction::FAdd)
3885 if (Red->isPartialReduction())
3891 auto IsMulAccValidAndClampRange =
3903 (Ext0->getOpcode() != Ext1->getOpcode() ||
3904 Ext0->getOpcode() == Instruction::CastOps::FPExt))
3908 !Ext0 || Ext0->getOpcode() == Instruction::CastOps::ZExt;
3910 MulAccCost = Ctx.TTI.getMulAccReductionCost(IsZExt, Opcode, RedTy,
3917 ExtCost += Ext0->computeCost(VF, Ctx);
3919 ExtCost += Ext1->computeCost(VF, Ctx);
3921 ExtCost += OuterExt->computeCost(VF, Ctx);
3923 return MulAccCost.
isValid() &&
3924 MulAccCost < ExtCost + MulCost + RedCost;
3929 VPValue *VecOp = Red->getVecOp();
3967 Builder.createWidenCast(Instruction::CastOps::Trunc, ValB, NarrowTy);
3969 ValB = ExtB = Builder.createWidenCast(ExtOpc, Trunc, WideTy);
3970 Mul->setOperand(1, ExtB);
3980 ExtendAndReplaceConstantOp(RecipeA, RecipeB,
B,
Mul);
3985 IsMulAccValidAndClampRange(
Mul, RecipeA, RecipeB,
nullptr)) {
3992 if (!
Sub && IsMulAccValidAndClampRange(
Mul,
nullptr,
nullptr,
nullptr))
4009 ExtendAndReplaceConstantOp(Ext0, Ext1,
B,
Mul);
4018 (Ext->getOpcode() == Ext0->getOpcode() ||
4019 (Ext0 == Ext1 && Ext0->getOpcode() == Instruction::SExt)) &&
4020 Ext0->getOpcode() == Ext1->getOpcode() &&
Mul->hasOneUse() &&
4022 IsMulAccValidAndClampRange(
Mul, Ext0, Ext1, Ext)) {
4024 Ext0->getOpcode(), Ext0->getOperand(0), Ext->getScalarType(),
nullptr,
4025 *Ext0, *Ext0, Ext0->getDebugLoc());
4026 NewExt0->insertBefore(Ext0);
4031 Ext->getScalarType(),
nullptr, *Ext1,
4032 *Ext1, Ext1->getDebugLoc());
4035 auto *NewMul =
Mul->cloneWithOperands({NewExt0, NewExt1});
4036 NewMul->insertBefore(
Mul);
4037 Ext->replaceAllUsesWith(NewMul);
4038 Ext->eraseFromParent();
4039 Mul->eraseFromParent();
4053 if (Red->isPartialReduction())
4057 auto IP = std::next(Red->getIterator());
4068 Red->replaceAllUsesWith(AbstractR);
4090 return CommonMetadata;
4093template <
unsigned Opcode>
4098 static_assert(Opcode == Instruction::Load || Opcode == Instruction::Store,
4099 "Only Load and Store opcodes supported");
4106 for (
auto Recipes :
Groups) {
4107 if (Recipes.size() < 2)
4111 "Expected all recipes in group to have the same load-store type");
4118 VPValue *MaskI = RecipeI->getMask();
4124 bool HasComplementaryMask =
false;
4129 VPValue *MaskJ = RecipeJ->getMask();
4138 if (HasComplementaryMask) {
4139 assert(Group.
size() >= 2 &&
"must have at least 2 entries");
4149template <
typename InstType>
4167 for (
auto &Group :
Groups) {
4187 return R->isSingleScalar() == IsSingleScalar;
4189 "all members in group must agree on IsSingleScalar");
4194 LoadWithMinAlign->getUnderlyingInstr(), {EarliestLoad->getOperand(0)},
4195 IsSingleScalar,
nullptr, *EarliestLoad, CommonMetadata);
4197 UnpredicatedLoad->insertBefore(EarliestLoad);
4201 Load->replaceAllUsesWith(UnpredicatedLoad);
4202 Load->eraseFromParent();
4211 if (!StoreLoc || !StoreLoc->AATags.Scope)
4218 SinkStoreInfo SinkInfo(StoresToSink, *StoresToSink[0], PSE, L);
4230 for (
auto &Group :
Groups) {
4243 VPValue *SelectedValue = Group[0]->getOperand(0);
4246 bool IsSingleScalar = Group[0]->isSingleScalar();
4247 for (
unsigned I = 1;
I < Group.size(); ++
I) {
4248 assert(IsSingleScalar == Group[
I]->isSingleScalar() &&
4249 "all members in group must agree on IsSingleScalar");
4250 VPValue *Mask = Group[
I]->getMask();
4252 SelectedValue = Builder.createSelect(
4255 Value->getScalarType()));
4263 StoreWithMinAlign->getUnderlyingInstr(),
4264 {SelectedValue, LastStore->getOperand(1)}, IsSingleScalar,
4265 nullptr, *LastStore, CommonMetadata);
4266 UnpredicatedStore->insertBefore(*InsertBB, LastStore->
getIterator());
4270 Store->eraseFromParent();
4277 assert(UF > 1 &&
"Expected plan to have an UF > 1");
4283 VPValue *StoredValue =
nullptr;
4289 assert(
MemOp->isConsecutive() &&
"Expected consecutive load/store");
4293 assert(!
MemOp->isMasked() &&
"Masked accesses are not supported yet");
4296 : R.getVPSingleValue()->getScalarType();
4298 std::optional<Instruction::CastOps> CastHint;
4300 : R.getVPSingleValue()->getSingleUser();
4302 CastHint = Cast->getOpcode();
4305 if (!
TTI.hasMultiVectorLoadStore(
4307 VectorAccessType, IsStore, CastHint))
4315 VPBuilder Builder(VPBB, R.getIterator());
4317 VPValue *WideStoredValue = Builder.createNaryOp(
4320 {Multiplier, Ptr,
Align, WideStoredValue},
nullptr,
4321 {}, *
MemOp, R.getDebugLoc());
4323 VPValue *OldLoad = R.getVPSingleValue();
4333 R.eraseFromParent();
4349 VPValue *OpV,
unsigned Idx,
bool IsScalable) {
4354 if (Member0Op == OpV)
4364 return !IsScalable && !W->getMask() && W->isConsecutive() &&
4367 return IR->getInterleaveGroup()->isFull() &&
IR->getVPValue(Idx) == OpV;
4387 if (R->getScalarType() != WideMember0->getScalarType())
4389 if (R->hasPredicate() && R->getPredicate() != WideMember0->getPredicate())
4397 if (V->isDefinedOutsideLoopRegions())
4399 auto [It, Inserted] = FirstMembersOf.try_emplace(V,
Ops);
4400 if (!Inserted && (It->second.front() == V || V == WideMember0) &&
4405 for (
unsigned Idx = 0; Idx != WideMember0->getNumOperands(); ++Idx) {
4408 OpsI.
push_back(
Op->getDefiningRecipe()->getOperand(Idx));
4413 if (
any_of(
enumerate(OpsI), [WideMember0, Idx, IsScalable](
const auto &
P) {
4414 const auto &[OpIdx, OpV] =
P;
4415 return !
canNarrowLoad(WideMember0, Idx, OpV, OpIdx, IsScalable);
4426static std::optional<ElementCount>
4430 if (!InterleaveR || InterleaveR->
getMask())
4431 return std::nullopt;
4433 Type *GroupElementTy =
nullptr;
4437 return Op->getScalarType() == GroupElementTy;
4439 return std::nullopt;
4443 return Op->getScalarType() == GroupElementTy;
4445 return std::nullopt;
4449 if (IG->getFactor() != IG->getNumMembers() || IG->isReverse())
4450 return std::nullopt;
4456 assert(
Size.isScalable() == VF.isScalable() &&
4457 "if Size is scalable, VF must be scalable and vice versa");
4458 return Size.getKnownMinValue();
4462 unsigned MinVal = VF.getKnownMinValue();
4464 if (IG->getFactor() == MinVal && GroupSize == GetVectorBitWidthForVF(VF))
4467 return std::nullopt;
4475 return RepR && RepR->isSingleScalar();
4489 if (V->isDefinedOutsideLoopRegions()) {
4492 return M->isDefinedOutsideLoopRegions() &&
4493 M->getScalarType() == V->getScalarType();
4495 "expected distinct loop-invariant values of matching scalar type");
4510 for (
unsigned Idx = 0,
E = WideMember0->getNumOperands(); Idx !=
E; ++Idx) {
4512 for (
VPValue *Member : Members)
4513 OpsI.
push_back(Member->getDefiningRecipe()->getOperand(Idx));
4514 WideMember0->setOperand(
4523 auto *LI =
cast<LoadInst>(LoadGroup->getInterleaveGroup()->getInsertPos());
4525 *LI, LoadGroup->getAddr(), LoadGroup->getMask(),
true,
4526 *LoadGroup, LoadGroup->getDebugLoc());
4532 assert(RepR->isSingleScalar() && RepR->getOpcode() == Instruction::Load &&
4533 "must be a single scalar load");
4534 NarrowedOps.
insert(RepR);
4539 VPValue *PtrOp = WideLoad->getAddr();
4541 PtrOp = VecPtr->getOperand(0);
4546 nullptr, {}, *WideLoad);
4547 N->insertBefore(WideLoad);
4552std::unique_ptr<VPlan>
4572 "unexpected branch-on-count");
4576 std::optional<ElementCount> VFToOptimize;
4590 if (R.mayWriteToMemory() && !InterleaveR)
4596 return any_of(V->users(), [&](VPUser *U) {
4597 auto *UR = cast<VPRecipeBase>(U);
4598 return UR->getParent()->getParent() != VectorLoop;
4615 std::optional<ElementCount> NarrowedVF =
4617 if (!NarrowedVF || (VFToOptimize && NarrowedVF != VFToOptimize))
4619 VFToOptimize = NarrowedVF;
4622 if (InterleaveR->getStoredValues().empty())
4627 auto *Member0 = InterleaveR->getStoredValues()[0];
4637 VPRecipeBase *DefR = Op.value()->getDefiningRecipe();
4640 auto *IR = dyn_cast<VPInterleaveRecipe>(DefR);
4641 return IR && IR->getInterleaveGroup()->isFull() &&
4642 IR->getVPValue(Op.index()) == Op.value();
4651 VFToOptimize->isScalable(), FirstMembersOf))
4656 if (StoreGroups.empty())
4660 bool RequiresScalarEpilogue =
4671 std::unique_ptr<VPlan> NewPlan;
4673 NewPlan = std::unique_ptr<VPlan>(Plan.
duplicate());
4674 Plan.
setVF(*VFToOptimize);
4675 NewPlan->removeVF(*VFToOptimize);
4682 for (
auto *StoreGroup : StoreGroups) {
4684 NarrowedOps, Preheader);
4690 StoreGroup->getDebugLoc());
4697 Type *CanIVTy = VectorLoop->getCanonicalIVType();
4703 if (VFToOptimize->isScalable()) {
4706 Step = PHBuilder.createOverflowingOp(Instruction::Mul, {VScale,
UF},
4714 materializeVectorTripCount(Plan, VectorPH,
false,
4715 RequiresScalarEpilogue, Step);
4720 removeDeadRecipes(Plan);
4723 "All VPVectorPointerRecipes should have been removed");
4741 "Cannot handle loops with uncountable early exits");
4748 assert(RecurSplice &&
"expected FirstOrderRecurrenceSplice");
4755 if (
any_of(RecurSplice->users(),
4756 [](
VPUser *U) { return !cast<VPRecipeBase>(U)->getRegion(); }) &&
4837 {},
"vector.recur.extract.for.phi");
4840 ExitPhi->replaceUsesOfWith(ExtractR, PenultimateElement);
4854 VPValue *WidenIVCandidate = BinOp->getOperand(0);
4855 VPValue *InvariantCandidate = BinOp->getOperand(1);
4857 std::swap(WidenIVCandidate, InvariantCandidate);
4871 auto *ClonedOp = BinOp->
clone();
4872 if (ClonedOp->getOperand(0) == WidenIV) {
4873 ClonedOp->setOperand(0, ScalarIV);
4875 assert(ClonedOp->getOperand(1) == WidenIV &&
"one operand must be WideIV");
4876 ClonedOp->setOperand(1, ScalarIV);
4890 return std::nullopt;
4895 return std::nullopt;
4907 auto CheckSentinel = [&SE](
const SCEV *IVSCEV,
4908 bool UseMax) -> std::optional<APSInt> {
4910 for (
bool Signed : {
true,
false}) {
4919 return std::nullopt;
4927 PhiR->getRecurrenceKind()))
4936 VPValue *BackedgeVal = PhiR->getBackedgeValue();
4950 !
match(FindLastSelect,
4959 IVOfExpressionToSink ? IVOfExpressionToSink : FindLastExpression, PSE,
4964 "IVOfExpressionToSink not being an AddRec must imply "
4965 "FindLastExpression not being an AddRec.");
4974 bool UseMax = *StepDirection;
4975 std::optional<APSInt> SentinelVal = CheckSentinel(IVSCEV, UseMax);
4976 bool UseSigned = SentinelVal && SentinelVal->isSigned();
4983 if (IVOfExpressionToSink) {
4984 const SCEV *FindLastExpressionSCEV =
4986 if (std::optional<bool> NewUseMax =
4988 if (
auto NewSentinel =
4989 CheckSentinel(FindLastExpressionSCEV, *NewUseMax)) {
4992 SentinelVal = *NewSentinel;
4993 UseSigned = NewSentinel->isSigned();
4994 UseMax = *NewUseMax;
4995 IVSCEV = FindLastExpressionSCEV;
4996 IVOfExpressionToSink =
nullptr;
5006 if (AR->hasNoSignedWrap())
5008 else if (AR->hasNoUnsignedWrap())
5018 VPValue *NewFindLastSelect = BackedgeVal;
5020 if (!SentinelVal || IVOfExpressionToSink) {
5023 DebugLoc DL = FindLastSelect->getDefiningRecipe()->getDebugLoc();
5024 VPBuilder LoopBuilder(FindLastSelect->getDefiningRecipe());
5025 if (
match(FindLastSelect,
5027 SelectCond = LoopBuilder.
createNot(SelectCond);
5034 if (SelectCond !=
Cond || IVOfExpressionToSink) {
5037 IVOfExpressionToSink ? IVOfExpressionToSink : FindLastExpression,
5046 VPIRFlags Flags(MinMaxKind,
false,
false,
5052 NewFindLastSelect, Flags, ExitDL);
5055 VPValue *VectorRegionExitingVal = ReducedIV;
5056 bool SunkExpression =
false;
5057 if (IVOfExpressionToSink) {
5058 VectorRegionExitingVal =
5060 ReducedIV, IVOfExpressionToSink);
5061 SunkExpression =
true;
5065 VPValue *StartVPV = PhiR->getStartValue();
5072 NewRdxResult = MiddleBuilder.
createSelect(Cmp, VectorRegionExitingVal,
5082 AnyOfPhi->insertAfter(PhiR);
5089 OrVal, VectorRegionExitingVal, StartVPV, ExitDL);
5102 PhiR->hasUsesOutsideReductionChain());
5104 NewPhiR->setExpressionSunk();
5105 NewPhiR->insertBefore(PhiR);
5106 PhiR->replaceAllUsesWith(NewPhiR);
5107 PhiR->eraseFromParent();
5113struct ReductionExtend {
5114 Type *SrcType =
nullptr;
5121struct ExtendedReductionOperand {
5125 ReductionExtend ExtendA, ExtendB;
5133struct PartialReductionDescriptor {
5136 VPWidenRecipe *ReductionBinOp =
nullptr;
5138 ExtendedReductionOperand ExtendedOp;
5145 unsigned AccumulatorOpIdx;
5146 unsigned ScaleFactor;
5149 VPBlendRecipe *Blend =
nullptr;
5154static std::optional<unsigned>
5158 "Expected a non-normalized blend with two incoming values");
5164 return std::nullopt;
5165 return FirstIncomingHasOneUse ? 0 : 1;
5177 if (!
Op->hasOneUse() ||
5183 auto *Trunc = Builder.createWidenCast(Instruction::CastOps::Trunc,
5184 Op->getOperand(1), NarrowTy);
5186 Op->setOperand(1, Builder.createWidenCast(ExtOpc, Trunc, WideTy));
5195 auto *
Sub =
Op->getOperand(0)->getDefiningRecipe();
5197 assert(Ext->getOpcode() ==
5199 "Expected both the LHS and RHS extends to be the same");
5200 bool IsSigned = Ext->getOpcode() == Instruction::SExt;
5203 auto *FreezeX = Builder.insert(
new VPWidenRecipe(Instruction::Freeze, {
X}));
5204 auto *FreezeY = Builder.insert(
new VPWidenRecipe(Instruction::Freeze, {
Y}));
5205 auto *
Max = Builder.insert(
5207 {FreezeX, FreezeY}, SrcTy));
5208 auto *Min = Builder.insert(
5210 {FreezeX, FreezeY}, SrcTy));
5211 auto *AbsDiff = Builder.insert(
5214 return Builder.createWidenCast(Instruction::CastOps::ZExt, AbsDiff,
5215 Op->getScalarType());
5227 assert(
Mul->hasOneUse() && Ext->getOpcode() == MulLHS->getOpcode() &&
5228 MulLHS->getOpcode() == MulRHS->getOpcode() &&
5230 "Expected the outer extend to be foldable");
5232 auto *NewLHS = Builder.createWidenCast(
5233 MulLHS->getOpcode(), MulLHS->getOperand(0), Ext->getScalarType());
5234 auto *NewRHS = MulLHS == MulRHS
5236 : Builder.createWidenCast(MulRHS->getOpcode(),
5237 MulRHS->getOperand(0),
5238 Ext->getScalarType());
5239 auto *NewMul =
Mul->cloneWithOperands({NewLHS, NewRHS});
5240 Builder.insert(NewMul);
5241 Op->replaceAllUsesWith(NewMul);
5242 Op->eraseFromParent();
5243 Mul->eraseFromParent();
5252 VPValue *VecOp = Red->getVecOp();
5305static void transformToPartialReduction(
const PartialReductionDescriptor &Link,
5313 WidenRecipe->
getOperand(1 - Link.AccumulatorOpIdx));
5316 ExtendedOp = optimizeExtendsForPartialReduction(ExtendedOp);
5332 if ((WidenRecipe->
getOpcode() == Instruction::Sub &&
5334 (WidenRecipe->
getOpcode() == Instruction::FSub &&
5339 if (WidenRecipe->
getOpcode() == Instruction::FSub) {
5351 Builder.insert(NegRecipe);
5352 ExtendedOp = NegRecipe;
5367 std::optional<unsigned> BlendReductionIdx =
5368 getBlendReductionUpdateValueIdx(Link.Blend);
5369 assert(BlendReductionIdx &&
5371 "Expected blend to contain the reduction update");
5385 [[maybe_unused]]
bool IsLastInChain =
5389 assert((!ExitValue || IsLastInChain) &&
5390 "if we found ExitValue, it must match RdxPhi's backedge value");
5401 PartialRed->insertBefore(WidenRecipe);
5411 E->insertBefore(WidenRecipe);
5412 PartialRed->replaceAllUsesWith(
E);
5418 const PartialReductionDescriptor &Link,
5421 const ExtendedReductionOperand &ExtendedOp = Link.ExtendedOp;
5422 std::optional<unsigned> BinOpc = std::nullopt;
5424 if (ExtendedOp.ExtendB.Kind != ExtendKind::PR_None)
5425 BinOpc = ExtendedOp.ExtendsUser->
getOpcode();
5427 std::optional<llvm::FastMathFlags>
Flags;
5431 auto GetLinkOpcode = [&Link]() ->
unsigned {
5434 return Instruction::Add;
5436 return Instruction::FAdd;
5438 return Link.ReductionBinOp->
getOpcode();
5443 GetLinkOpcode(), ExtendedOp.ExtendA.SrcType, ExtendedOp.ExtendB.SrcType,
5444 RdxType, VF, ExtendedOp.ExtendA.Kind, ExtendedOp.ExtendB.Kind, BinOpc,
5461static std::optional<ExtendedReductionOperand>
5464 "Op should be operand of UpdateR");
5472 if (
Op->hasOneUse() &&
5481 Type *RHSInputType =
Y->getScalarType();
5482 if (LHSInputType != RHSInputType ||
5483 LHSExt->getOpcode() != RHSExt->getOpcode())
5484 return std::nullopt;
5487 return ExtendedReductionOperand{
5493 std::optional<TTI::PartialReductionExtendKind> OuterExtKind;
5496 VPValue *CastSource = CastRecipe->getOperand(0);
5507 return ExtendedReductionOperand{
5514 if (!
Op->hasOneUse())
5515 return std::nullopt;
5520 return std::nullopt;
5530 return std::nullopt;
5537 const APInt *RHSConst =
nullptr;
5543 return std::nullopt;
5547 if (Cast && OuterExtKind &&
5549 return std::nullopt;
5551 Type *RHSInputType = LHSInputType;
5560 if (OuterExtKind && MulOp->
getOpcode() == Instruction::Mul &&
5562 return std::nullopt;
5564 return ExtendedReductionOperand{
5565 MulOp, {LHSInputType, LHSExtendKind}, {RHSInputType, RHSExtendKind}};
5572static std::optional<SmallVector<PartialReductionDescriptor>>
5579 return std::nullopt;
5580 VPValue *ExitValue = RdxResult->getOperand(0);
5589 VPValue *CurrentValue = ExitValue;
5590 while (CurrentValue != RedPhiR) {
5592 std::optional<unsigned> BlendReductionIdx;
5596 return std::nullopt;
5598 BlendReductionIdx = getBlendReductionUpdateValueIdx(Blend);
5599 if (!BlendReductionIdx)
5600 return std::nullopt;
5607 return std::nullopt;
5614 std::optional<ExtendedReductionOperand> ExtendedOp =
5615 matchExtendedReductionOperand(UpdateR,
Op);
5617 ExtendedOp = matchExtendedReductionOperand(UpdateR, PrevValue);
5619 return std::nullopt;
5627 return std::nullopt;
5629 Type *ExtSrcType = ExtendedOp->ExtendA.SrcType;
5632 return std::nullopt;
5634 PartialReductionDescriptor Link(
5635 {UpdateR, *ExtendedOp, RK,
5640 CurrentValue = PrevValue;
5645 std::reverse(Chain.
begin(), Chain.
end());
5655 assert(Phi->getVFScaleFactor() == 1 &&
"scale factor must not be set");
5656 Phi->setVFScaleFactor(Factor);
5661 StartInst->setOperand(2, NewScaleFactor);
5668 VPValue *OldStartValue = StartInst->getOperand(0);
5669 StartInst->setOperand(0, StartInst->getOperand(1));
5673 assert(RdxResult &&
"Could not find reduction result");
5676 unsigned SubOpc = RK ==
RecurKind::FSub ? Instruction::BinaryOps::FSub
5677 : Instruction::BinaryOps::Sub;
5680 Phi->getDebugLoc());
5696 if (
auto Chain = getScaledReductionChain(&RedPhiR))
5697 PhiToChain.
try_emplace(&RedPhiR, std::move(*Chain));
5698 else if (CostCtx.
Opts.use_partial_reductions_by_default &&
5702 UnorderedReductions.
push_back(&RedPhiR);
5708 for (
auto *Rdx : UnorderedReductions) {
5724 ? std::make_optional(Rdx->getFastMathFlagsOrNone())
5728 Backedge->getOpcode(), ScalarTy,
nullptr,
5730 std::nullopt, CostCtx.
CostKind, FMF);
5731 return PRCost <= CurrentCost;
5737 Rdx->getRecurrenceKind(), Rdx->getFastMathFlagsOrNone(),
5738 Backedge->getUnderlyingInstr(), Rdx, OtherOp,
nullptr,
5741 Partial->insertBefore(Backedge);
5742 Backedge->replaceAllUsesWith(Partial);
5743 Backedge->eraseFromParent();
5746 if (PhiToChain.
empty())
5754 for (
auto &[
_, Chain] : PhiToChain)
5755 for (
const PartialReductionDescriptor &Link : Chain) {
5756 PartialReductionOps.
insert(Link.ExtendedOp.ExtendsUser);
5758 PartialReductionBlends.
insert(Link.Blend);
5759 ScaledReductionMap[Link.ReductionBinOp] = Link.ScaleFactor;
5765 auto ExtendUsersValid = [&](
VPValue *Ext) {
5767 return PartialReductionOps.contains(cast<VPRecipeBase>(U));
5771 auto IsProfitablePartialReductionChainForVF =
5778 for (
const PartialReductionDescriptor &Link : Chain) {
5779 const ExtendedReductionOperand &ExtendedOp = Link.ExtendedOp;
5780 InstructionCost LinkCost = getPartialReductionLinkCost(CostCtx, Link, VF);
5784 PartialCost += LinkCost;
5785 RegularCost += Link.ReductionBinOp->
computeCost(VF, CostCtx);
5787 if (ExtendedOp.ExtendB.Kind != ExtendKind::PR_None)
5788 RegularCost += ExtendedOp.ExtendsUser->
computeCost(VF, CostCtx);
5791 RegularCost += Extend->computeCost(VF, CostCtx);
5793 return PartialCost.
isValid() && PartialCost < RegularCost;
5801 for (
auto &[RedPhiR, Chain] : PhiToChain) {
5802 for (
const PartialReductionDescriptor &Link : Chain) {
5803 if (!
all_of(Link.ExtendedOp.ExtendsUser->
operands(), ExtendUsersValid)) {
5807 auto UseIsValid = [&, RedPhiR = RedPhiR](
VPUser *U) {
5809 return PhiR == RedPhiR;
5813 return Blend == Link.Blend || PartialReductionBlends.
contains(Blend);
5815 return Link.ScaleFactor == ScaledReductionMap.
lookup_or(R, 0) ||
5821 if (!
all_of(Link.ReductionBinOp->
users(), UseIsValid)) {
5830 auto *RepR = dyn_cast<VPReplicateRecipe>(U);
5831 return RepR && RepR->getOpcode() == Instruction::Store;
5842 return IsProfitablePartialReductionChainForVF(Chain, VF);
5848 for (
auto &[Phi, Chain] : PhiToChain) {
5852 for (
const PartialReductionDescriptor &Link : Chain)
5853 transformToPartialReduction(Link, Plan, Phi);
5858 const PartialReductionDescriptor &Link = Chain[0];
5874 if (VPI.getUnderlyingValue() &&
5885 auto ProcessSubset = [&](
VPlan &,
auto ProcessVPInst) {
5888 if (!ProcessVPInst(VPI))
5897 assert(New->getParent() &&
"New recipe must have been inserted");
5898 if (VPI->
getOpcode() == Instruction::Load)
5907 return ReplaceWith(VPI,
VPBuilder(VPI).insert(
5914 "lowerMemoryIdioms", ProcessSubset, Plan, [&](
VPInstruction *VPI) {
5916 VPI, FinalRedStoresBuilder))
5925 return ReplaceWith(VPI,
VPBuilder(VPI).insert(Histogram));
5938 "scalarizeMemOpsWithIrregularTypes", ProcessSubset, Plan,
5942 return Scalarize(VPI);
5949 "makeVPlanMemOpDecision", ProcessSubset, Plan, [&](
VPInstruction *VPI) {
5951 bool IsLoad = VPI->
getOpcode() == Instruction::Load;
5961 const SCEV *PtrSCEV =
5963 bool IsSingleScalarLoad =
5969 I, Ptr, IsSingleScalarLoad,
5978 "widenConsecutiveMemOps", ProcessSubset, Plan, [&](
VPInstruction *VPI) {
5980 bool IsLoad = VPI->
getOpcode() == Instruction::Load;
5984 std::optional<int64_t> Stride =
5986 if (Stride != 1 && Stride != -1)
6017 return ReplaceWith(VPI,
Load);
6026 auto *StoreR = Builder.createWidenStore(
6029 return ReplaceWith(VPI, StoreR);
6036 return ReplaceWith(VPI, Recipe);
6038 return Scalarize(VPI);
6058 if (VPI.mayHaveSideEffects())
6063 if (VPI.getOpcode() == Instruction::ExtractValue)
6067 if (VPI.isMasked() && !VPI.isSafeToSpeculativelyExecute())
6072 if (VPI.getOpcode() == Instruction::Add &&
6081 VPI.getOpcode(), VPI.operandsWithoutMask(),
nullptr, VPI,
6082 VPI, VPI.getDebugLoc(), VPI.getScalarType(),
I);
6083 Recipe->insertBefore(&VPI);
6084 VPI.replaceAllUsesWith(Recipe);
6085 VPI.eraseFromParent();
6095 switch (Param.ParamKind) {
6096 case VFParamKind::Vector:
6097 case VFParamKind::GlobalPredicate:
6099 case VFParamKind::OMP_Uniform:
6100 return SE->isSCEVable(Args[Param.ParamPos]->getScalarType()) &&
6101 SE->isLoopInvariant(
6102 vputils::getSCEVExprForVPValue(Args[Param.ParamPos], PSE, L),
6104 case VFParamKind::OMP_Linear:
6105 return match(vputils::getSCEVExprForVPValue(Args[Param.ParamPos], PSE, L),
6106 m_scev_AffineAddRec(
6107 m_SCEV(), m_scev_SpecificSInt(Param.LinearStepOrPos),
6108 m_SpecificLoop(L)));
6125 const auto *It =
find_if(Mappings, [&](
const VFInfo &Info) {
6126 return Info.Shape.VF == VF && (!MaskRequired || Info.isMasked()) &&
6129 if (It == Mappings.end())
6136struct CallWideningDecision {
6137 enum class KindTy { Scalarize,
Intrinsic, VectorVariant };
6138 CallWideningDecision(KindTy Kind,
Function *Variant =
nullptr)
6161 return CallWideningDecision::KindTy::Scalarize;
6171 return CallWideningDecision::KindTy::Scalarize;
6175 false, VF, CostCtx);
6190 return CallWideningDecision::KindTy::Intrinsic;
6194 if (VecFunc && ScalarCost >= VecCallCost)
6195 return {CallWideningDecision::KindTy::VectorVariant, VecFunc};
6197 return CallWideningDecision::KindTy::Scalarize;
6203 bool Widened =
false;
6208 if (!VPI.getUnderlyingValue() || VPI.getOpcode() != Instruction::Call)
6213 VPI.op_begin() + CI->arg_size());
6215 CallWideningDecision Decision =
6223 assert((Decision.Kind == CallWideningDecision::KindTy::Scalarize ||
6224 !CI->hasOperandBundles()) &&
6225 "calls with operand bundles must not be widened");
6227 switch (Decision.Kind) {
6228 case CallWideningDecision::KindTy::Intrinsic: {
6232 VPI, VPI.getDebugLoc());
6236 case CallWideningDecision::KindTy::VectorVariant: {
6241 Ops.push_back(Mask);
6243 Ops.push_back(VPI.getOperand(VPI.getNumOperandsWithoutMask() - 1));
6247 Attrs, VPI.getDebugLoc());
6251 case CallWideningDecision::KindTy::Scalarize:
6257 VPI.replaceAllUsesWith(Replacement);
6258 VPI.eraseFromParent();
6275 if (VPI.getOpcode() != Instruction::Trunc)
6299 !
TTI.isTruncateFree(
6300 toVectorTy(VPI.getOperand(0)->getScalarType(), VF),
6304 IsNarrowingProfitable,
Range))
6310 WideIV->getPHINode(), WideIV->getStartValue(), WideIV->getStepValue(),
6311 WideIV->getVFValue(), WideIV->getInductionDescriptor(),
6314 NarrowIV->insertBefore(*HeaderVPBB, HeaderVPBB->
getFirstNonPhi());
6315 VPI.replaceAllUsesWith(NarrowIV);
6316 VPI.eraseFromParent();
6338 if (!MemR || MemR->isConsecutive())
6341 VPValue *Ptr = MemR->getAddr();
6353 VPValue *StoredValue =
nullptr;
6357 StoredValue = StoreR->getStoredValue();
6359 IntrinID = Intrinsic::experimental_vp_strided_store;
6363 IntrinID = Intrinsic::experimental_vp_strided_load;
6366 Align Alignment = MemR->getAlign();
6369 if (!Ctx.TTI.isLegalStridedLoadStore(VectorTy, Alignment))
6374 IntrinID, VectorTy, MemR->isMasked(), Alignment, Ctx);
6375 return StridedLoadStoreCost < CurrentCost;
6386 Ctx.invalidateWideningDecision(&MemR->getIngredient(), VF);
6391 I32VF = Builder.createScalarZExtOrTrunc(
6405 "Stride type from SCEV must match the index type");
6406 VPValue *CanIV = Builder.createScalarZExtOrTrunc(
6409 auto *
Offset = Builder.createOverflowingOp(
6410 Instruction::Mul, {CanIV, StrideInBytes},
6411 {AddRecPtr->hasNoUnsignedWrap(),
false});
6415 VPValue *BasePtr = Builder.createNoWrapPtrAdd(StartVPV,
Offset, NWFlags);
6418 VPValue *NewPtr = Builder.createVectorPointer(
6422 VPValue *Mask = MemR->getMask();
6427 Ops.push_back(StoredValue);
6428 Ops.append({NewPtr, StrideInBytes, Mask, I32VF});
6430 auto *StridedR = Builder.createWidenMemIntrinsic(
6433 *MemR, R.getDebugLoc());
6436 R.eraseFromParent();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements a class to represent arbitrary precision integral constant values and operations...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static bool isEqual(const Function &Caller, const Function &Callee)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static cl::opt< OutputCostKind > CostKind("cost-kind", cl::desc("Target cost kind"), cl::init(OutputCostKind::RecipThroughput), cl::values(clEnumValN(OutputCostKind::RecipThroughput, "throughput", "Reciprocal throughput"), clEnumValN(OutputCostKind::Latency, "latency", "Instruction latency"), clEnumValN(OutputCostKind::CodeSize, "code-size", "Code size"), clEnumValN(OutputCostKind::SizeAndLatency, "size-latency", "Code size and latency"), clEnumValN(OutputCostKind::All, "all", "Print all cost kinds")))
static cl::opt< IntrinsicCostStrategy > IntrinsicCost("intrinsic-cost-strategy", cl::desc("Costing strategy for intrinsic instructions"), cl::init(IntrinsicCostStrategy::InstructionCost), cl::values(clEnumValN(IntrinsicCostStrategy::InstructionCost, "instruction-cost", "Use TargetTransformInfo::getInstructionCost"), clEnumValN(IntrinsicCostStrategy::IntrinsicCost, "intrinsic-cost", "Use TargetTransformInfo::getIntrinsicInstrCost"), clEnumValN(IntrinsicCostStrategy::TypeBasedIntrinsicCost, "type-based-intrinsic-cost", "Calculate the intrinsic cost based only on argument types")))
iv Induction Variable Users
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
Legalize the Machine IR a function s Machine IR
This file provides utility analysis objects describing memory locations.
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
Function const char * Passes
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
This file contains the declarations for profiling metadata utility functions.
const SmallVectorImpl< MachineOperand > & Cond
This is the interface for a metadata-based scoped no-alias analysis.
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
This file implements the TypeSwitch template, which mimics a switch() statement whose cases are type ...
This file implements dominator tree analysis for a single level of a VPlan's H-CFG.
This file contains the declarations of different VPlan-related auxiliary helpers.
This file contains the declarations of the Vectorization Plan base classes:
static const X86InstrFMA3Group Groups[]
static const uint32_t IV[8]
Helper for extra no-alias checks via known-safe recipe and SCEV.
SinkStoreInfo(ArrayRef< VPReplicateRecipe * > ExcludeRecipes, VPReplicateRecipe &GroupLeader, PredicatedScalarEvolution &PSE, const Loop &L)
SinkStoreInfo(VPReplicateRecipe &GroupLeader)
bool shouldSkip(VPRecipeBase &R) const
Return true if R should be skipped during alias checking, either because it's in the exclude set or b...
Class for arbitrary precision integers.
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
LLVM_ABI APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
unsigned getActiveBits() const
Compute the number of active bits in the value.
APInt abs() const
Get the absolute value.
unsigned getBitWidth() const
Return the number of bits in the APInt.
int32_t exactLogBase2() const
bool isNonNegative() const
Determine if this APInt Value is non-negative (>= 0)
LLVM_ABI APInt sext(unsigned width) const
Sign extend to a new width.
bool isPowerOf2() const
Check if this APInt's value is a power of two greater than zero.
bool uge(const APInt &RHS) const
Unsigned greater or equal comparison.
An arbitrary precision integer that knows its signedness.
static APSInt getMinValue(uint32_t numBits, bool Unsigned)
Return the APSInt representing the minimum integer value with the given bit width and signedness.
static APSInt getMaxValue(uint32_t numBits, bool Unsigned)
Return the APSInt representing the maximum integer value with the given bit width and signedness.
@ NoAlias
The two locations do not alias at all.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
const T & back() const
Get the last element.
ArrayRef< T > drop_front(size_t N=1) const
Drop the first N elements of the array.
const T & front() const
Get the first element.
size_t size() const
Get the array size.
A cache of @llvm.assume calls within a function.
LLVM Basic Block Representation.
const Function * getParent() const
Return the enclosing method, or null if none.
bool isNoBuiltin() const
Return true if the call should not be treated as a call to a builtin.
This class represents a function call, abstracting a target machine's calling convention.
@ ICMP_ULT
unsigned less than
@ ICMP_ULE
unsigned less or equal
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
An abstraction over a floating-point predicate, and a pack of an integer predicate with samesign info...
This class represents a range of values.
LLVM_ABI bool contains(const APInt &Val) const
Return true if the specified value is in the set.
A parsed version of the target data layout string in and methods for querying it.
LLVM_ABI IntegerType * getIndexType(LLVMContext &C, unsigned AddressSpace) const
Returns the type of a GEP index in AddressSpace.
static DebugLoc getUnknown()
ValueT lookup_or(const_arg_type_t< KeyT > Val, U &&Default) const
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
bool dominates(const DomTreeNodeBase< NodeT > *A, const DomTreeNodeBase< NodeT > *B) const
dominates - Returns true iff A dominates B.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
static constexpr ElementCount getScalable(ScalarTy MinVal)
constexpr bool isScalar() const
Exactly one element.
Convenience struct for specifying and reasoning about fast-math flags.
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Represents flags for the getelementptr instruction/expression.
static GEPNoWrapFlags noUnsignedWrap()
bool hasNoUnsignedWrap() const
GEPNoWrapFlags withoutNoUnsignedWrap() const
static GEPNoWrapFlags none()
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
A struct for saving information about induction variables.
InductionKind
This enum represents the kinds of inductions that we support.
@ IK_PtrInduction
Pointer induction var. Step = C.
@ IK_IntInduction
Integer induction variable. Step = C.
static InstructionCost getInvalid(CostType Val=0)
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
The group of interleaved loads/stores sharing the same stride and close to each other.
This is an important class for using LLVM in a threaded context.
LLVM_ABI cl::LibraryOptionsContext & getLibraryOptions() const
The library options this context reads in place of their process-wide values.
An instruction for reading from memory.
static bool getDecisionAndClampRange(const std::function< bool(ElementCount)> &Predicate, VFRange &Range)
Test a Predicate on a Range of VF's.
Represents a single loop in the control flow graph.
LLVM_ABI MDNode * createBranchWeights(uint32_t TrueWeight, uint32_t FalseWeight, bool IsExpected=false)
Return metadata containing two branch weights.
This class implements a map that also provides access to all stored values in a deterministic order.
ValueT lookup(const KeyT &Key) const
std::pair< iterator, bool > try_emplace(const KeyT &Key, Ts &&...Args)
Representation for a specific memory location.
Function * getFunction(StringRef Name) const
Look up the specified function in the module symbol table.
Post-order traversal of a graph.
An interface layer with SCEV used to manage how we see SCEV expressions for values in the context of ...
ScalarEvolution * getSE() const
Returns the ScalarEvolution analysis used.
LLVM_ABI const SCEV * getSCEV(Value *V)
Returns the SCEV expression of V, in the context of the current SCEV predicate.
static LLVM_ABI unsigned getOpcode(RecurKind Kind)
Returns the opcode corresponding to the RecurrenceKind.
unsigned getOpcode() const
static bool isFindLastRecurrenceKind(RecurKind Kind)
Returns true if the recurrence kind is of the form select(cmp(),x,y) where one of (x,...
LLVM_ABI bool match(StringRef String, SmallVectorImpl< StringRef > *Matches=nullptr, std::string *Error=nullptr) const
matches - Match the regex against a given String.
RegionT * getParent() const
Get the parent of the Region.
This class represents a constant integer value.
ConstantInt * getValue() const
static const SCEV * rewrite(const SCEV *Scev, ScalarEvolution &SE, ValueToSCEVMapTy &Map)
This means that we are dealing with an entirely unknown SCEV value, and only represent it as its LLVM...
This class represents an analyzed expression in the program.
Type * getType() const
Return the LLVM type of this SCEV expression.
The main scalar evolution driver.
const DataLayout & getDataLayout() const
Return the DataLayout associated with the module this SCEV instance is operating on.
LLVM_ABI const SCEV * getElementCount(Type *Ty, ElementCount EC, SCEVFlags Flags=SCEV::FlagNone)
LLVM_ABI bool isKnownNegative(const SCEV *S)
Test if the given expression is known to be negative.
LLVM_ABI const SCEV * getMinusSCEV(SCEVUse LHS, SCEVUse RHS, SCEVFlags Flags=SCEV::FlagNone, unsigned Depth=0)
Return LHS-RHS.
LLVM_ABI const SCEV * getConstant(ConstantInt *V)
ConstantRange getSignedRange(const SCEV *S)
Determine the signed range for a particular SCEV.
LLVM_ABI bool isLoopInvariant(const SCEV *S, const Loop *L)
Return true if the value of the given SCEV is unchanging in the specified loop.
LLVM_ABI bool isKnownPositive(const SCEV *S)
Test if the given expression is known to be positive.
ConstantRange getUnsignedRange(const SCEV *S)
Determine the unsigned range for a particular SCEV.
LLVM_ABI bool isKnownPredicate(CmpPredicate Pred, SCEVUse LHS, SCEVUse RHS)
Test if the given expression is known to satisfy the condition described by Pred, LHS,...
LLVM_ABI const SCEV * getNegativeSCEV(const SCEV *V, SCEVFlags Flags=SCEV::FlagNone)
Return the SCEV object corresponding to -V.
static LLVM_ABI AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB)
A vector that has set insertion semantics.
size_type size() const
Determine the number of elements in the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
Represent a constant reference to a string, i.e.
Provides information about what library functions are available for the current target.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
This class implements a switch-like dispatch statement for a value of 'T' using dyn_cast functionalit...
TypeSwitch< T, ResultT > & Case(CallableT &&caseFn)
Add a case on the given type.
The instances of the Type class are immutable: once they are created, they are never changed.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
bool isPointerTy() const
True if this is an instance of PointerType.
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
bool isIntOrPtrTy() const
Return true if this is an integer type or a pointer type.
bool isIntegerTy() const
True if this is an instance of IntegerType.
static SmallVector< VFInfo, 8 > getMappings(const CallInst &CI)
Retrieve all the VFInfo instances associated to the CallInst CI.
bool isLegalMaskedLoadOrStore(bool IsLoad, Type *ScalarTy, Align Alignment, unsigned AddressSpace) const
Returns true if the target machine supports a masked load (if IsLoad) or masked store of scalar type ...
VPBasicBlock serves as the leaf of the Hierarchical Control-Flow Graph.
void appendRecipe(VPRecipeBase *Recipe)
Augment the existing recipes of a VPBasicBlock with an additional Recipe as the last recipe.
RecipeListTy::iterator iterator
Instruction iterators...
iterator begin()
Recipe iterator methods.
iterator_range< iterator > phis()
Returns an iterator range over the PHI-like recipes in the block.
iterator getFirstNonPhi()
Return the position of the first non-phi node recipe in the block.
VPBasicBlock * splitAt(iterator SplitAt)
Split current block at SplitAt by inserting a new block between the current block and its successors ...
const VPRecipeBase & front() const
VPRecipeBase * getTerminator()
If the block has multiple successors, return the branch recipe terminating the block.
const VPRecipeBase & back() const
void insert(VPRecipeBase *Recipe, iterator InsertPt)
A recipe for vectorizing a phi-node as a sequence of mask-based select instructions.
VPValue * getIncomingValue(unsigned Idx) const
Return incoming value number Idx.
VPValue * getMask(unsigned Idx) const
Return mask number Idx.
unsigned getNumIncomingValues() const
Return the number of incoming values, taking into account when normalized the first incoming value wi...
void setMask(unsigned Idx, VPValue *V)
Set mask number Idx to V.
bool isNormalized() const
A normalized blend is one that has an odd number of operands, whereby the first operand does not have...
VPBlockBase is the building block of the Hierarchical Control-Flow Graph.
void setSuccessors(ArrayRef< VPBlockBase * > NewSuccs)
Set each VPBasicBlock in NewSuccss as successor of this VPBlockBase.
VPRegionBlock * getParent()
const VPBasicBlock * getExitingBasicBlock() const
size_t getNumSuccessors() const
void setPredecessors(ArrayRef< VPBlockBase * > NewPreds)
Set each VPBasicBlock in NewPreds as predecessor of this VPBlockBase.
const VPBlocksTy & getPredecessors() const
VPBlockBase * getSinglePredecessor() const
void clearPredecessors()
Remove all the predecessor of this block.
const VPBasicBlock * getEntryBasicBlock() const
VPBlockBase * getSingleSuccessor() const
const VPBlocksTy & getSuccessors() const
static auto blocksAs(T &&Range)
Return an iterator range over Range with each block cast to BlockTy.
static void insertOnEdge(VPBlockBase *From, VPBlockBase *To, VPBlockBase *BlockPtr)
Inserts BlockPtr on the edge between From and To.
static bool isLatch(const VPBlockBase *VPB, const VPDominatorTree &VPDT)
Returns true if VPB is a loop latch, using isHeader().
static VPBasicBlock * getPlainCFGMiddleBlock(const VPlan &Plan)
Returns the middle block of Plan in plain CFG form (before regions are formed).
static void insertTwoBlocksAfter(VPBlockBase *IfTrue, VPBlockBase *IfFalse, VPBlockBase *BlockPtr)
Insert disconnected VPBlockBases IfTrue and IfFalse after BlockPtr.
static void connectBlocks(VPBlockBase *From, VPBlockBase *To, unsigned PredIdx=-1u, unsigned SuccIdx=-1u)
Connect VPBlockBases From and To bi-directionally.
static void disconnectBlocks(VPBlockBase *From, VPBlockBase *To)
Disconnect VPBlockBases From and To bi-directionally.
static auto blocksOnly(T &&Range)
Return an iterator range over Range which only includes BlockTy blocks.
static std::pair< VPBasicBlock *, VPBasicBlock * > getPlainCFGHeaderAndLatch(const VPlan &Plan)
Returns the header and latch of the outermost loop of Plan in plain CFG form (before regions are form...
static void transferSuccessors(VPBlockBase *Old, VPBlockBase *New)
Transfer successors from Old to New. New must have no successors.
static SmallVector< VPBasicBlock * > blocksInSingleSuccessorChainBetween(VPBasicBlock *FirstBB, VPBasicBlock *LastBB)
Returns the blocks between FirstBB and LastBB, where FirstBB to LastBB forms a single-sucessor chain.
A recipe for generating conditional branches on the bits of a mask.
VPlan-based builder utility similar to IRBuilder.
VPInstruction * createFreeze(VPValue *Op, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="")
static VPBuilderBase getToInsertAfter(VPRecipeBase *R)
VPInstruction * createLogicalAnd(VPValue *LHS, VPValue *RHS, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="")
VPInstruction * createAnyOfReduction(VPValue *ChainOp, VPValue *TrueVal, VPValue *FalseVal, DebugLoc DL=DebugLoc::getUnknown())
Create an AnyOf reduction pattern: or-reduce ChainOp, freeze the result, then select between TrueVal ...
VPDerivedIVRecipe * createDerivedIV(InductionDescriptor::InductionKind Kind, FPMathOperator *FPBinOp, VPValue *Start, VPValue *Current, VPValue *Step, const VPIRFlags::WrapFlagsTy &Flags={})
Convert Current to Start + Current * Step.
VPWidenCastRecipe * createWidenCast(Instruction::CastOps Opcode, VPValue *Op, Type *ResultTy)
VPInstruction * createAdd(VPValue *LHS, VPValue *RHS, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="", VPRecipeWithIRFlags::WrapFlagsTy WrapFlags={false, false})
VPInstruction * createSelect(VPValue *Cond, VPValue *TrueVal, VPValue *FalseVal, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="", std::optional< VPIRFlags > Flags=std::nullopt)
Create a select of TrueVal and FalseVal based on Cond, using the default flags for the result type,...
VPValue * createScalarZExtOrTrunc(VPValue *Op, Type *ResultTy, DebugLoc DL)
static VPSingleDefRecipe * createSingleScalarOp(unsigned Opcode, ArrayRef< VPValue * > Operands, VPValue *Mask, const VPIRFlags &Flags, const VPIRMetadata &Metadata, DebugLoc DL, Type *ResultTy, Instruction *UV)
VPInstruction * createLogicalOr(VPValue *LHS, VPValue *RHS, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="")
VPInstruction * createScalarCast(Instruction::CastOps Opcode, VPValue *Op, Type *ResultTy, DebugLoc DL, std::optional< VPIRFlags > Flags=std::nullopt, const VPIRMetadata &Metadata={})
VPInstruction * createNot(VPValue *Operand, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="")
VPWidenLoadRecipe * createWidenLoad(LoadInst &Load, VPValue *Addr, VPValue *Mask, bool Consecutive, const VPIRMetadata &Metadata, DebugLoc DL)
Create a recipe widening Load, loading from Addr with Mask (may be null).
void setInsertPoint(const VPInsertPoint &IP)
Set the current insert point.
VPWidenStoreRecipe * createWidenStore(StoreInst &Store, VPValue *Addr, VPValue *StoredVal, VPValue *Mask, bool Consecutive, const VPIRMetadata &Metadata, DebugLoc DL)
Create a recipe widening Store, storing StoredVal to Addr with Mask (may be null).
VPInstruction * createNaryOp(unsigned Opcode, ArrayRef< VPValue * > Operands, Instruction *Inst=nullptr, const VPIRFlags &Flags={}, const VPIRMetadata &MD={}, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="", Type *ResultTy=nullptr)
Create an N-ary operation with Opcode, Operands and set Inst as its underlying Instruction.
VPInstruction * createFirstActiveLane(ArrayRef< VPValue * > Masks, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="")
VPInstruction * createOr(VPValue *LHS, VPValue *RHS, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="")
VPInstruction * createICmp(CmpInst::Predicate Pred, VPValue *A, VPValue *B, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="")
Create a new ICmp VPInstruction with predicate Pred and operands A and B.
unsigned getNumDefinedValues() const
Returns the number of values defined by the VPDef.
VPValue * getVPSingleValue()
Returns the only VPValue defined by the VPDef.
VPValue * getVPValue(unsigned I)
Returns the VPValue with index I defined by the VPDef.
ArrayRef< VPRecipeValue * > definedValues()
Returns an ArrayRef of the values defined by the VPDef.
Template specialization of the standard LLVM dominator tree utility for VPBlockBases.
LLVM_ABI_FOR_TEST bool properlyDominates(const VPRecipeBase *A, const VPRecipeBase *B) const
Recipe to expand a SCEV expression.
A recipe to combine multiple recipes into a single 'expression' recipe, which should be considered a ...
A recipe representing a sequence of load -> update -> store as part of a histogram operation.
Manage IR per-argument and return attributes for call recipes.
A special type of VPBasicBlock that wraps an existing IR basic block.
Class to record and manage LLVM IR flags.
static LLVM_ABI_FOR_TEST VPIRFlags getDefaultFlags(unsigned Opcode, Type *ResultTy=nullptr)
Returns default flags for Opcode and scalar ResultTy for opcodes that support it, asserts otherwise.
LLVM_ABI_FOR_TEST FastMathFlags getFastMathFlagsOrNone() const
This is a concrete Recipe that models a single VPlan-level instruction.
unsigned getNumOperandsWithoutMask() const
Returns the number of operands, excluding the mask if the VPInstruction is masked.
@ ExtractLane
Extracts a single lane (first operand) from a set of vector operands.
@ ExtractPenultimateElement
@ ReductionStartVector
Start vector for reductions with 3 operands: the original start value, the identity value for the red...
@ BuildVector
Creates a fixed-width vector containing all operands.
@ ComputeReductionResult
Reduce the operands to the final reduction result using the operation specified via the operation's V...
unsigned getOpcode() const
VPValue * getMask() const
Returns the mask for the VPInstruction.
const InterleaveGroup< Instruction > * getInterleaveGroup() const
VPValue * getMask() const
Return the mask used by this recipe.
ArrayRef< VPValue * > getStoredValues() const
Return the VPValues stored by this interleave group.
VPInterleaveRecipe is a recipe for transforming an interleave group of load or stores into one wide l...
VPPredInstPHIRecipe is a recipe for generating the phi nodes needed when control converges back from ...
VPRecipeBase is a base class modeling a sequence of one or more output IR instructions.
VPRegionBlock * getRegion()
VPBasicBlock * getParent()
DebugLoc getDebugLoc() const
Returns the debug location of the recipe.
void moveBefore(VPBasicBlock &BB, iplist< VPRecipeBase >::iterator I)
Unlink this recipe and insert into BB before I.
void insertBefore(VPRecipeBase *InsertPos)
Insert an unlinked recipe into a basic block immediately before the specified recipe.
void insertAfter(VPRecipeBase *InsertPos)
Insert an unlinked Recipe into a basic block immediately after the specified Recipe.
iplist< VPRecipeBase >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Helper class to create VPRecipies from IR instructions.
VPHistogramRecipe * widenIfHistogram(VPInstruction *VPI)
If VPI represents a histogram operation (as determined by LoopVectorizationLegality) make that safe f...
bool prefersVectorizedAddressing() const
Returns true if the target prefers vectorized addressing.
VPRecipeBase * tryToWidenMemory(VPInstruction *VPI, VFRange &Range)
Check if the load or store instruction VPI should widened for Range.Start and potentially masked.
bool replaceWithFinalIfReductionStore(VPInstruction *VPI, VPBuilder &FinalRedStoresBuilder)
If VPI is a store of a reduction into an invariant address, delete it.
VPSingleDefRecipe * handleReplication(VPInstruction *VPI, VFRange &Range)
Build a replicating or single-scalar recipe for VPI.
bool isPredicatedInst(Instruction *I) const
Returns true if I needs to be predicated (i.e.
Type * getScalarType() const
Returns the scalar type of this VPRecipeValue.
A recipe for handling reduction phis.
bool isOrdered() const
Returns true, if the phi is part of an ordered reduction.
bool isInLoop() const
Returns true if the phi is part of an in-loop reduction.
RecurKind getRecurrenceKind() const
Returns the recurrence kind of the reduction.
A recipe to represent inloop, ordered or partial reduction operations.
VPRegionBlock represents a collection of VPBasicBlocks and VPRegionBlocks which form a Single-Entry-S...
const VPBlockBase * getEntry() const
bool isReplicator() const
An indicator whether this region is to generate multiple replicated instances of output IR correspond...
void setExiting(VPBlockBase *ExitingBlock)
Set ExitingBlock as the exiting VPBlockBase of this VPRegionBlock.
void print(raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const override
Print this VPRegionBlock to O (recursively), prefixing all lines with Indent.
Type * getCanonicalIVType() const
Return the type of the canonical IV for loop regions.
VPRegionValue * getCanonicalIV()
Return the canonical induction variable of the region, null for replicating regions.
const VPBlockBase * getExiting() const
VPRegionValue * getHeaderMask() const
Return the header mask of the region, or null if not set.
VPReplicateRecipe replicates a given instruction producing multiple scalar copies of the original sca...
bool isSingleScalar() const
Returns true if the recipe produces a single scalar value.
static InstructionCost computeCallCost(Function *CalledFn, Type *ResultTy, ArrayRef< const VPValue * > ArgOps, bool IsSingleScalar, ElementCount VF, VPCostContext &Ctx)
Return the cost of scalarizing a call to CalledFn with argument operands ArgOps for a given VF.
operand_range operandsWithoutMask()
Return the recipe's operands, excluding the mask of a predicated recipe.
bool isPredicated() const
VPValue * getMask()
Return the mask of a predicated VPReplicateRecipe.
Lightweight SCEV-to-VPlan expander.
VPValue * expand(const SCEV *S)
Expand S into recipes and live-ins using the builder.
A recipe for handling phi nodes of integer and floating-point inductions, producing their scalar valu...
VPSingleDefRecipe is a base class for recipes that model a sequence of one or more output IR that def...
Instruction * getUnderlyingInstr()
Returns the underlying instruction.
VPSingleDefRecipe * clone() override=0
Clone the current recipe.
A symbolic live-in VPValue, used for values like vector trip count, VF, and VFxUF.
This class augments VPValue with operands which provide the inverse def-use edges from VPValue's user...
void setOperand(unsigned I, VPValue *New)
unsigned getNumOperands() const
VPValue * getOperand(unsigned N) const
This is the base class of the VPlan Def/Use graph, used for modeling the data flow into,...
Type * getScalarType() const
Returns the scalar type of this VPValue, dispatching based on the concrete subclass.
Value * getLiveInIRValue() const
Return the underlying IR value for a VPIRValue.
bool isDefinedOutsideLoopRegions() const
Returns true if the VPValue is defined outside any loop.
VPRecipeBase * getDefiningRecipe()
Returns the recipe defining this VPValue or nullptr if it is not defined by a recipe,...
bool hasMoreThanOneUniqueUser() const
Returns true if the value has more than one unique user.
Value * getUnderlyingValue() const
Return the underlying Value attached to this VPValue.
void replaceUsesWithIf(VPValue *New, llvm::function_ref< bool(VPUser *U)> ShouldReplace)
Go through the uses list for this VPValue and make each use point to New if the callback ShouldReplac...
VPUser * getSingleUser()
Return the single user of this value, or nullptr if there is not exactly one user.
void replaceAllUsesWith(VPValue *New)
A recipe to compute a pointer to the last element of each part of a widened memory access for widened...
A recipe for widening Call instructions using library calls.
static InstructionCost computeCallCost(Function *Variant, VPCostContext &Ctx)
Return the cost of widening a call using the vector function Variant.
VPWidenCastRecipe is a recipe to create vector cast instructions.
Instruction::CastOps getOpcode() const
A recipe for handling GEP instructions.
Base class for widened induction (VPWidenIntOrFpInductionRecipe and VPWidenPointerInductionRecipe),...
PHINode * getPHINode() const
Returns the underlying PHINode if one exists, or null otherwise.
VPValue * getStepValue()
Returns the step value of the induction.
const InductionDescriptor & getInductionDescriptor() const
Returns the induction descriptor for the recipe.
A recipe for handling phi nodes of integer and floating-point inductions, producing their vector valu...
bool isTruncated() const
Returns true if this induction is evaluated in a narrower type than the start value.
A recipe for widening vector intrinsics.
static InstructionCost computeCallCost(Intrinsic::ID ID, ArrayRef< const VPValue * > Operands, const VPRecipeWithIRFlags &R, ElementCount VF, VPCostContext &Ctx)
Compute the cost of a vector intrinsic with ID and Operands.
static InstructionCost computeMemIntrinsicCost(Intrinsic::ID IID, Type *Ty, bool IsMasked, Align Alignment, VPCostContext &Ctx)
Helper function for computing the cost of vector memory intrinsic.
A common mixin class for widening memory operations.
virtual VPRecipeBase * getAsRecipe()=0
Return a VPRecipeBase* to the current object.
A recipe for widened phis.
VPWidenRecipe is a recipe for producing a widened instruction using the opcode and operands of the re...
InstructionCost computeCost(ElementCount VF, VPCostContext &Ctx) const override
Return the cost of this VPWidenRecipe.
VPWidenRecipe * clone() override
Clone the current recipe.
unsigned getOpcode() const
VPlan models a candidate for vectorization, encoding various decisions take to produce efficient outp...
VPIRValue * getLiveIn(Value *V) const
Return the live-in VPIRValue for V, if there is one or nullptr otherwise.
bool hasVF(ElementCount VF) const
const DataLayout & getDataLayout() const
LLVMContext & getContext() const
VPBasicBlock * getEntry()
bool hasScalableVF() const
VPValue * getTripCount() const
The trip count of the original loop.
VPValue * getOrCreateBackedgeTakenCount()
The backedge taken count of the original loop.
iterator_range< SmallSetVector< ElementCount, 2 >::iterator > vectorFactors() const
Returns an iterator range over all VFs of the plan.
VPIRValue * getFalse()
Return a VPIRValue wrapping i1 false.
VPSymbolicValue & getVFxUF()
Returns VF * UF of the vector loop region.
VPIRValue * getAllOnesValue(Type *Ty)
Return a VPIRValue wrapping the AllOnes value of type Ty.
VPRegionBlock * createReplicateRegion(VPBlockBase *Entry, VPBlockBase *Exiting, const std::string &Name="")
Create a new replicate region with Entry, Exiting and Name.
auto getLiveIns() const
Return the list of live-in VPValues available in the VPlan.
bool hasUF(unsigned UF) const
ArrayRef< VPIRBasicBlock * > getExitBlocks() const
Return an ArrayRef containing VPIRBasicBlocks wrapping the exit blocks of the original scalar loop.
VPSymbolicValue & getVectorTripCount()
The vector trip count.
VPValue * getBackedgeTakenCount() const
VPIRValue * getOrAddLiveIn(Value *V)
Gets the live-in VPIRValue for V or adds a new live-in (if none exists yet) for V.
VPIRValue * getZero(Type *Ty)
Return a VPIRValue wrapping the null value of type Ty.
void setVF(ElementCount VF)
bool isUnrolled() const
Returns true if the VPlan already has been unrolled, i.e.
LLVM_ABI_FOR_TEST VPRegionBlock * getVectorLoopRegion()
Returns the VPRegionBlock of the vector loop.
unsigned getConcreteUF() const
Returns the concrete UF of the plan, after unrolling.
void resetTripCount(VPValue *NewTripCount)
Resets the trip count for the VPlan.
VPBasicBlock * getMiddleBlock()
Returns the 'middle' block of the plan, that is the block that selects whether to execute the scalar ...
VPBasicBlock * createVPBasicBlock(const Twine &Name, VPRecipeBase *Recipe=nullptr)
Create a new VPBasicBlock with Name and containing Recipe if present.
VPIRValue * getTrue()
Return a VPIRValue wrapping i1 true.
VPBasicBlock * getVectorPreheader() const
Returns the preheader of the vector loop region, if one exists, or null otherwise.
VPSymbolicValue & getUF()
Returns the UF of the vector loop region.
bool hasScalarVFOnly() const
VPBasicBlock * getScalarPreheader() const
Return the VPBasicBlock for the preheader of the scalar loop.
bool hasTailFolded() const
Returns true if the vector loop region is tail-folded.
VPSymbolicValue & getVF()
Returns the VF of the vector loop region.
LLVM_ABI_FOR_TEST VPlan * duplicate()
Clone the current VPlan, update all VPValues of the new VPlan and cloned recipes to refer to the clon...
VPIRValue * getConstantInt(Type *Ty, uint64_t Val, bool IsSigned=false)
Return a VPIRValue wrapping a ConstantInt with the given type and value.
LLVM Value Representation.
iterator_range< user_iterator > users()
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Base class of all SIMD vector types.
static LLVM_ABI VectorType * get(Type *ElementType, ElementCount EC)
This static method is the primary way to construct an VectorType.
constexpr bool hasKnownScalarFactor(const FixedOrScalableQuantity &RHS) const
Returns true if there exists a value X where RHS*X will result in a value whose quantity matches our ...
constexpr ScalarTy getFixedValue() const
constexpr ScalarTy getKnownScalarFactor(const FixedOrScalableQuantity &RHS) const
Returns a value X where RHS*X will result in a value whose quantity matches our own.
static constexpr bool isKnownLT(const FixedOrScalableQuantity &LHS, const FixedOrScalableQuantity &RHS)
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
constexpr bool isFixed() const
Returns true if the quantity is not scaled by vscale.
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
An efficient, type-erasing, non-owning reference to a callable.
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
LLVM_ABI APInt RoundingUDiv(const APInt &A, const APInt &B, APInt::Rounding RM)
Return A unsign-divided by B, rounded by the given rounding mode.
std::variant< std::monostate, Loc::Single, Loc::Multi, Loc::MMI, Loc::EntryValue > Variant
Alias for the std::variant specialization base class of DbgVariable.
void reportVectorizationFailure(const StringRef DebugMsg, const StringRef OREMsg, const StringRef ORETag, OptimizationRemarkEmitter *ORE, const Loop *TheLoop, Instruction *I=nullptr)
Reports a vectorization failure: print DebugMsg for debugging purposes along with the corresponding o...
SpecificConstantMatch m_ZeroInt()
Convenience matchers for specific integer values.
AllOnesConstantMatch m_AllOnes()
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
OneUse_match< SubPat > m_OneUse(const SubPat &SP)
match_unless< Pattern > m_Unless(const Pattern &P)
Match if the inner matcher does NOT match.
match_isa< To... > m_Isa()
match_combine_or< Ty... > m_CombineOr(const Ty &...Ps)
Combine pattern matchers matching any of Ps patterns.
auto m_Cmp()
Matches any compare instruction and ignore it.
BinaryOp_match< LHS, RHS, Instruction::Add > m_Add(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, Instruction::AShr > m_AShr(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, Instruction::URem > m_URem(const LHS &L, const RHS &R)
OneOps_match< OpTy, Instruction::Freeze > m_Freeze(const OpTy &Op)
Matches FreezeInst.
ap_match< APInt > m_APInt(const APInt *&Res)
Match a ConstantInt or splatted ConstantVector, binding the specified pointer to the contained APInt.
CastInst_match< OpTy, TruncInst > m_Trunc(const OpTy &Op)
Matches Trunc.
LogicalOp_match< LHS, RHS, Instruction::And > m_LogicalAnd(const LHS &L, const RHS &R)
Matches L && R either in the form of L & R or L ?
specific_intval< false > m_SpecificInt(const APInt &V)
Match a specific integer value or vector with all elements equal to the value.
BinaryOp_match< LHS, RHS, Instruction::FMul > m_FMul(const LHS &L, const RHS &R)
bool match(Val *V, const Pattern &P)
match_deferred< Value > m_Deferred(Value *const &V)
Like m_Specific(), but works if the specific value to match is determined as part of the same match()...
specificval_ty m_Specific(const Value *V)
Match if we have a specific specified value.
CmpClass_match< LHS, RHS, CmpInst, true > m_c_Cmp(const LHS &L, const RHS &R)
CmpClass_match< LHS, RHS, ICmpInst, true > m_c_ICmp(CmpPredicate &Pred, const LHS &L, const RHS &R)
Matches an ICmp with a predicate over LHS and RHS in either order.
auto match_fn(const Pattern &P)
A match functor that can be used as a UnaryPredicate in functional algorithms like all_of.
cst_pred_ty< is_one > m_One()
Match an integer 1 or a vector with all elements equal to 1.
ThreeOps_match< Cond, LHS, RHS, Instruction::Select > m_Select(const Cond &C, const LHS &L, const RHS &R)
Matches SelectInst.
SpecificCmpClass_match< LHS, RHS, CmpInst > m_SpecificCmp(CmpPredicate MatchPred, const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, Instruction::Mul > m_Mul(const LHS &L, const RHS &R)
auto m_LogicalOr()
Matches L || R where L and R are arbitrary values.
CastInst_match< OpTy, FPExtInst > m_FPExt(const OpTy &Op)
SpecificCmpClass_match< LHS, RHS, ICmpInst > m_SpecificICmp(CmpPredicate MatchPred, const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, Instruction::UDiv > m_UDiv(const LHS &L, const RHS &R)
SelectLike_match< CondTy, LTy, RTy > m_SelectLike(const CondTy &C, const LTy &TrueC, const RTy &FalseC)
Matches a value that behaves like a boolean-controlled select, i.e.
BinaryOp_match< LHS, RHS, Instruction::Add, true > m_c_Add(const LHS &L, const RHS &R)
Matches a Add with LHS and RHS in either order.
CastOperator_match< OpTy, Instruction::BitCast > m_BitCast(const OpTy &Op)
Matches BitCast.
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
BinaryOp_match< LHS, RHS, Instruction::LShr > m_LShr(const LHS &L, const RHS &R)
CmpClass_match< LHS, RHS, ICmpInst > m_ICmp(CmpPredicate &Pred, const LHS &L, const RHS &R)
match_combine_or< CastInst_match< OpTy, ZExtInst >, CastInst_match< OpTy, SExtInst > > m_ZExtOrSExt(const OpTy &Op)
FNeg_match< OpTy > m_FNeg(const OpTy &X)
Match 'fneg X' as 'fsub -0.0, X'.
BinaryOp_match< LHS, RHS, Instruction::FAdd, true > m_c_FAdd(const LHS &L, const RHS &R)
Matches FAdd with LHS and RHS in either order.
LogicalOp_match< LHS, RHS, Instruction::And, true > m_c_LogicalAnd(const LHS &L, const RHS &R)
Matches L && R with LHS and RHS in either order.
BinaryOp_match< LHS, RHS, Instruction::Shl > m_Shl(const LHS &L, const RHS &R)
auto m_LogicalAnd()
Matches L && R where L and R are arbitrary values.
CastInst_match< OpTy, SExtInst > m_SExt(const OpTy &Op)
Matches SExt.
LogicalOp_match< LHS, RHS, Instruction::Or, true > m_c_LogicalOr(const LHS &L, const RHS &R)
Matches L || R with LHS and RHS in either order.
BinaryOp_match< LHS, RHS, Instruction::Mul, true > m_c_Mul(const LHS &L, const RHS &R)
Matches a Mul with LHS and RHS in either order.
BinaryOp_match< LHS, RHS, Instruction::Sub > m_Sub(const LHS &L, const RHS &R)
auto m_ConstantInt()
Match an arbitrary ConstantInt and ignore it.
bind_cst_ty m_scev_APInt(const APInt *&C)
Match an SCEV constant and bind it to an APInt.
cst_pred_ty< is_one > m_scev_One()
Match an integer 1.
specificloop_ty m_SpecificLoop(const Loop *L)
bool match(const SCEV *S, const Pattern &P)
SCEVAffineAddRec_match< Op0_t, Op1_t, match_isa< const Loop > > m_scev_AffineAddRec(const Op0_t &Op0, const Op1_t &Op1)
VPInstruction_match< VPInstruction::ExtractLastLane, VPInstruction_match< VPInstruction::ExtractLastPart, Op0_t > > m_ExtractLastLaneOfLastPart(const Op0_t &Op0)
AllRecipe_commutative_match< Instruction::And, Op0_t, Op1_t > m_c_BinaryAnd(const Op0_t &Op0, const Op1_t &Op1)
Match a binary AND operation.
AllRecipe_match< Instruction::Or, Op0_t, Op1_t > m_BinaryOr(const Op0_t &Op0, const Op1_t &Op1)
Match a binary OR operation.
VPInstruction_match< VPInstruction::AnyOf > m_AnyOf()
AllRecipe_commutative_match< Instruction::Or, Op0_t, Op1_t > m_c_BinaryOr(const Op0_t &Op0, const Op1_t &Op1)
VPInstruction_match< VPInstruction::ComputeReductionResult, Op0_t > m_ComputeReductionResult(const Op0_t &Op0)
auto m_WidenAnyExtend(const Op0_t &Op0)
match_bind< VPIRValue > m_VPIRValue(VPIRValue *&V)
Match a VPIRValue.
VPInstruction_match< VPInstruction::WideActiveLaneMask, Op0_t, Op1_t, Op2_t > m_WideActiveLaneMask(const Op0_t &Op0, const Op1_t &Op1, const Op2_t &Op2)
auto m_VPPhi(const Op0_t &Op0, const Op1_t &Op1)
VPInstruction_match< VPInstruction::BranchOnTwoConds > m_BranchOnTwoConds()
VPWidenStoreRecipe_match< Op0_t, Op1_t > m_WidenStore(const Op0_t &Op0, const Op1_t &Op1)
AllRecipe_match< Opcode, Op0_t, Op1_t > m_Binary(const Op0_t &Op0, const Op1_t &Op1)
VPWidenLoadRecipe_match< Op0_t > m_WidenLoad(const Op0_t &Op0)
VPInstruction_match< VPInstruction::LastActiveLane, Op0_t > m_LastActiveLane(const Op0_t &Op0)
auto m_WidenIntrinsic(const T &...Ops)
canonical_widen_iv_match m_CanonicalWidenIV()
VPInstruction_match< VPInstruction::ExitingIVValue, Op0_t > m_ExitingIVValue(const Op0_t &Op0)
VPInstruction_match< Instruction::ExtractElement, Op0_t, Op1_t > m_ExtractElement(const Op0_t &Op0, const Op1_t &Op1)
VectorPointerRecipe_match< Op0_t, Op1_t > m_VecPtr(const Op0_t &Op0, const Op1_t &Op1)
VPInstruction_match< VPInstruction::ExtractLastLane, Op0_t > m_ExtractLastLane(const Op0_t &Op0)
int_pred_ty< is_zero_int, 1 > m_False()
match_bind< VPSingleDefRecipe > m_VPSingleDefRecipe(VPSingleDefRecipe *&V)
Match a VPSingleDefRecipe, capturing if we match.
VPInstruction_match< VPInstruction::BranchOnCount > m_BranchOnCount()
auto m_GetElementPtr(const Op0_t &Op0, const Op1_t &Op1)
auto m_VPValue()
Match an arbitrary VPValue and ignore it.
VPInstruction_match< VPInstruction::ExtractVectorForPart, Op0_t, Op1_t > m_ExtractVectorForPart(const Op0_t &Op0, const Op1_t &Op1)
VPInstruction_match< VPInstruction::ExtractLastPart, Op0_t > m_ExtractLastPart(const Op0_t &Op0)
VPRecipeBase * findUserOf(VPValue *V, const MatchT &P)
If V is used by a recipe matching pattern P, return it.
VPInstruction_match< VPInstruction::Broadcast, Op0_t > m_Broadcast(const Op0_t &Op0)
bool match(Val *V, const Pattern &P)
header_mask_match m_HeaderMask()
VPInstruction_match< VPInstruction::BuildVector > m_BuildVector()
BuildVector is matches only its opcode, w/o matching its operands as the number of operands is not fi...
VPInstruction_match< VPInstruction::ExtractPenultimateElement, Op0_t > m_ExtractPenultimateElement(const Op0_t &Op0)
match_bind< VPInstruction > m_VPInstruction(VPInstruction *&V)
Match a VPInstruction, capturing if we match.
VPInstruction_match< VPInstruction::FirstActiveLane, Op0_t > m_FirstActiveLane(const Op0_t &Op0)
int_pred_ty< is_one, 1 > m_True()
auto m_DerivedIV(const Op0_t &Op0, const Op1_t &Op1, const Op2_t &Op2)
VPInstruction_match< VPInstruction::BranchOnCond > m_BranchOnCond()
VPInstruction_match< VPInstruction::ExtractLane, Op0_t, Op1_t > m_ExtractLane(const Op0_t &Op0, const Op1_t &Op1)
auto m_AnyNeg(const Op0_t &Op0)
VPInstruction_match< VPInstruction::Reverse, Op0_t > m_Reverse(const Op0_t &Op0)
NodeAddr< DefNode * > Def
bool isSingleScalar(const VPValue *VPV)
Returns true if VPV is a single scalar, either because it produces the same value for all lanes or on...
VPValue * getOrCreateVPValueForSCEVExpr(VPlan &Plan, const SCEV *Expr)
Get or create a VPValue that corresponds to the expansion of Expr.
bool cannotHoistOrSinkRecipe(const VPRecipeBase &R, bool Sinking=false)
Return true if we do not know how to (mechanically) hoist or sink R.
unsigned getOpcode(const VPValue *V)
Return the instruction opcode for the recipe defining V or 0 for unsupported recipes and VPValues not...
std::optional< int64_t > getConstantStride(VPValue *Addr, Type *AccessTy, PredicatedScalarEvolution &PSE, const Loop *L)
If the pointer operand Addr of a memory access is an affine AddRec w.r.t.
VPInstruction * findComputeReductionResult(VPReductionPHIRecipe *PhiR)
Find the ComputeReductionResult recipe for PhiR, looking through selects inserted for predicated redu...
VPInstruction * findCanonicalIVIncrement(VPlan &Plan)
Find the canonical IV increment of Plan's vector loop region.
std::optional< MemoryLocation > getMemoryLocation(const VPRecipeBase &R)
Return a MemoryLocation for R with noalias metadata populated from R, if the recipe is supported and ...
bool onlyFirstLaneUsed(const VPValue *Def)
Returns true if only the first lane of Def is used.
VPIRValue * tryToFoldLiveIns(VPSingleDefRecipe &R, ArrayRef< VPValue * > Operands, const DataLayout &DL)
Try to fold R using InstSimplifyFolder.
SmallVector< std::pair< VPBasicBlock *, VPIRBasicBlock * > > getEarlyExits(const VPlan &Plan, const VPBlockBase *MiddleVPBB)
Returns the (early exiting block, exit block) pairs of Plan, i.e.
VPScalarIVStepsRecipe * createScalarIVSteps(VPlan &Plan, InductionDescriptor::InductionKind Kind, Instruction::BinaryOps InductionOpcode, FPMathOperator *FPBinOp, Type *ResultTy, VPValue *StartV, VPValue *Step, DebugLoc DL, VPBuilder &Builder, const VPIRFlags::WrapFlagsTy &Flags={})
Create a scalar-iv-steps recipe over Plan's canonical IV for an induction of Kind with InductionOpcod...
void recursivelyDeleteDeadRecipes(VPValue *V)
Recursively delete V and any of its operands that become dead.
bool doesGeneratePerAllLanes(const VPRecipeBase *R)
Returns true if R produces scalar values for all VF lanes.
bool isDeadRecipe(VPRecipeBase &R)
Returns true if R is dead, i.e.
VPRecipeBase * findRecipe(VPValue *Start, PredT Pred)
Search Start's users for a recipe satisfying Pred, looking through recipes with definitions.
LLVM_ABI_FOR_TEST bool isUniformAcrossVFsAndUFs(const VPValue *V)
Checks if V is uniform across all VF lanes and UF parts.
bool isUsedByLoadStoreAddress(const VPValue *V)
Returns true if V is used as part of the address of another load or store.
std::optional< std::pair< bool, unsigned > > getOpcodeOrIntrinsicID(const VPValue *V)
Get the instruction opcode or intrinsic ID for the recipe defining V.
VPValue * scalarizeVPWidenPointerInduction(VPWidenPointerInductionRecipe *PtrIV, VPlan &Plan, VPBuilder &Builder)
Scalarize a VPWidenPointerInductionRecipe by replacing it with a PtrAdd (IndStart,...
LLVM_ABI_FOR_TEST const SCEV * getSCEVExprForVPValue(const VPValue *V, PredicatedScalarEvolution &PSE, const Loop *L=nullptr)
Return the SCEV expression for V.
void pullOutPermutations(VPlan &Plan, Match_t Perm, Builder Build)
Removes the permutation pattern Perm from any elementwise operations in the plan, by constructing a n...
SmallVector< VPUser * > collectUsersRecursively(VPValue *V)
Collect all users of V, looking through recipes that define other values.
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
SmallVector< VPBasicBlock * > vp_rpo_plain_cfg_loop_body(VPBasicBlock *Header)
Returns the VPBasicBlocks forming the loop body of a plain (pre-region) VPlan in reverse post-order s...
constexpr auto not_equal_to(T &&Arg)
Functor variant of std::not_equal_to that can be used as a UnaryPredicate in functional algorithms li...
void stable_sort(R &&Range)
auto min_element(R &&Range)
Provide wrappers to std::min_element which take ranges instead of having to pass begin/end explicitly...
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
unsigned getLoadStoreAddressSpace(const Value *I)
A helper function that returns the address space of the pointer operand of load or store instruction.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
LLVM_ABI Intrinsic::ID getVectorIntrinsicIDForCall(const CallInst *CI, const TargetLibraryInfo *TLI)
Returns intrinsic ID for call.
detail::zippy< detail::zip_first, T, U, Args... > zip_equal(T &&t, U &&u, Args &&...args)
zip iterator that assumes that all iteratees have the same length.
ReductionStyle getReductionStyle(bool InLoop, bool Ordered, unsigned ScaleFactor)
DenseMap< const Value *, const SCEV * > ValueToSCEVMapTy
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
const Value * getLoadStorePointerOperand(const Value *V)
A helper function that returns the pointer operand of a load or store instruction.
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
VPBuilderBase<> VPBuilder
constexpr from_range_t from_range
auto dyn_cast_if_present(const Y &Val)
dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a null (or none in the case ...
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
auto cast_or_null(const Y &Val)
Align getLoadStoreAlignment(const Value *I)
A helper function that returns the alignment of load or store instruction.
iterator_range< df_iterator< VPBlockShallowTraversalWrapper< VPBlockBase * > > > vp_depth_first_shallow(VPBlockBase *G)
Returns an iterator range to traverse the graph starting at G in depth-first order.
bool isa_and_nonnull(const Y &Val)
iterator_range< df_iterator< VPBlockDeepTraversalWrapper< VPBlockBase * > > > vp_depth_first_deep(VPBlockBase *G)
Returns an iterator range to traverse the graph starting at G in depth-first order while traversing t...
constexpr auto equal_to(T &&Arg)
Functor variant of std::equal_to that can be used as a UnaryPredicate in functional algorithms like a...
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
auto map_range(ContainerTy &&C, FuncTy F)
Return a range that applies F to the elements of C.
uint64_t PowerOf2Ceil(uint64_t A)
Returns the power of two which is greater than or equal to the given value.
auto make_isa_range(RangeT &&Range)
Return a range over Range containing only elements for which isa<T> holds, casting each of them to T.
auto dyn_cast_or_null(const Y &Val)
void erase(Container &C, ValueType V)
Wrapper function to remove a value from a container:
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
auto reverse(ContainerTy &&C)
constexpr size_t range_size(R &&Range)
Returns the size of the Range, i.e., the number of elements.
void sort(IteratorTy Start, IteratorTy End)
DenseMap< Value *, const SCEVUnknown * > SymbolicStrideMap
Maps a pointer to its symbolic (non-constant) stride.
bool hasIrregularType(Type *Ty, const DataLayout &DL)
A helper function that returns true if the given type is irregular.
UncountableExitStyle
Different methods of handling early exits.
@ ReadOnly
No side effects to worry about, so we can process any uncountable exits in the loop and branch either...
@ MaskedHandleExitInScalarLoop
All memory operations other than the load(s) required to determine whether an uncountable exit occurr...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
SmallVector< ValueTypeFromRangeType< R >, Size > to_vector(R &&Range)
Given a range of type R, iterate the entire range and return a SmallVector with elements of the vecto...
iterator_range< filter_iterator< detail::IterOfRange< RangeT >, PredicateT > > make_filter_range(RangeT &&Range, PredicateT Pred)
Convenience function that takes a range of elements and a predicate, and return a new filter_iterator...
bool canConstantBeExtended(const APInt *C, Type *NarrowType, TTI::PartialReductionExtendKind ExtKind)
Check if a constant CI can be safely treated as having been extended from a narrower type with the gi...
T * find_singleton(R &&Range, Predicate P, bool AllowRepeats=false)
Return the single value in Range that satisfies P(<member of Range> *, AllowRepeats)->T * returning n...
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
auto drop_end(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the last N elements excluded.
RecurKind
These are the kinds of recurrences that we support.
@ UMin
Unsigned integer min implemented in terms of select(cmp()).
@ FindIV
FindIV reduction with select(icmp(),x,y) where one of (x,y) is a loop induction variable (increasing ...
@ Or
Bitwise or logical OR of integers.
@ Mul
Product of integers.
@ FSub
Subtraction of floats.
@ SMax
Signed integer max implemented in terms of select(cmp()).
@ SMin
Signed integer min implemented in terms of select(cmp()).
@ Sub
Subtraction of integers.
@ AddChainWithSubs
A chain of adds and subs.
@ UMax
Unsigned integer max implemented in terms of select(cmp()).
LLVM_ABI Value * getRecurrenceIdentity(RecurKind K, Type *Tp, FastMathFlags FMF)
Given information about an recurrence kind, return the identity for the @llvm.vector....
LLVM_ABI BasicBlock * SplitBlock(BasicBlock *Old, BasicBlock::iterator SplitPt, DominatorTree *DT, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr, const Twine &BBName="")
Split the specified block at the specified instruction.
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
DWARFExpression::Operation Op
auto max_element(R &&Range)
Provide wrappers to std::max_element which take ranges instead of having to pass begin/end explicitly...
ArrayRef(const T &OneElt) -> ArrayRef< T >
LLVM_ABI bool extractBranchWeights(const MDNode *ProfileData, SmallVectorImpl< uint32_t > &Weights)
Extract branch weights from MD_prof metadata.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Type * getLoadStoreType(const Value *I)
A helper function that returns the type of a load or store instruction.
bool all_equal(std::initializer_list< T > Values)
Returns true if all Values in the initializer lists are equal or the list.
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
bool equal(L &&LRange, R &&RRange)
Wrapper function around std::equal to detect if pair-wise elements between two ranges are the same.
Type * toVectorTy(Type *Scalar, ElementCount EC)
A helper function for converting Scalar types to vector types.
LLVM_ABI bool isDereferenceableAndAlignedInLoop(LoadInst *LI, Loop *L, ScalarEvolution &SE, DominatorTree &DT, AssumptionCache *AC=nullptr, SmallVectorImpl< const SCEVPredicate * > *Predicates=nullptr)
Return true if we can prove that the given load (which is assumed to be within the specified loop) wo...
constexpr detail::IsaCheckPredicate< Types... > IsaPred
Function object wrapper for the llvm::isa type check.
LLVM_ABI_FOR_TEST bool verifyVPlanIsValid(const VPlan &Plan)
Verify invariants for general VPlans.
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last)
Compute a hash_code for a sequence of values.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
VPBasicBlock * EarlyExitingVPBB
VPIRBasicBlock * EarlyExitVPBB
This struct is a compact representation of a valid (non-zero power of two) alignment.
An information struct used to provide DenseMap with the various necessary components for a given valu...
This reduction is unordered with the partial result scaled down by some factor.
Holds the VFShape for a specific scalar to vector function mapping.
Encapsulates information needed to describe a parameter.
A range of powers-of-2 vectorization factors with fixed start and adjustable end.
Struct to hold various analysis needed for cost computations.
const VFSelectionContext & Config
static bool isFreeScalarIntrinsic(Intrinsic::ID ID)
Returns true if ID is a pseudo intrinsic that is dropped via scalarization rather than widened.
bool isMaskRequired(Instruction *I) const
Forwards to LoopVectorizationCostModel::isMaskRequired.
PredicatedScalarEvolution & PSE
bool willBeScalarized(Instruction *I, ElementCount VF) const
Returns true if I is known to be scalarized at VF.
TargetTransformInfo::TargetCostKind CostKind
const TargetLibraryInfo & TLI
const TargetTransformInfo & TTI
const VectorizeOptions & Opts
A recipe for handling first-order recurrence phis.
WrapFlagsTy withoutNoSignedWrap()
A VPValue representing a live-in from the input IR or a constant.
Type * getType() const
Returns the type of the underlying IR value.
A recipe for widening load operations, using the address to load from and an optional mask.
A recipe for widening store operations, using the stored value, the address to store to and an option...